我编写了一个程序来演示Go中的浮点错误:
func main() {
a := float64(0.2)
a += 0.1
a -= 0.3
var i int
for i = 0; a < 1.0; i++ {
a += a
}
fmt.Printf("After %d iterations, a = %e\n", i, a)
}
它打印:
After 54 iterations, a = 1.000000e+00
这与用C编写的相同程序的行为相匹配(使用双代码类型)
但是,如果改用float32
,程序就会陷入无限循环!如果将C程序修改为使用float
而不是double
,它将打印
After 27 iterations, a = 1.600000e+00
为什么在使用float32
时,Go程序的输出与C程序的输出不一样?
同意阿尼萨斯,围棋是在做正确的事。关于C,我不相信他的猜测。
C标准没有规定,但大多数libc实现都会将十进制表示转换为最接近的浮点(至少符合IEEE-754 2008或ISO 10967),因此我认为这不是最可能的解释。
C程序行为可能不同的原因有很多。。。特别是,某些中间计算可能会执行过高精度(双精度或长双精度)。
我能想到的最可能的事情是,如果你在C中写了0.1而不是0.1f。
在这种情况下,你可能会在初始化
中导致过高的精度(你和浮点数相加为双0.1=
如果我模仿这些操作
float32(float32(float32(0.2) + float64(0.1)) - float64(0.3))
然后我发现1.1920929e-8f附近有东西
经过27次迭代后,其总和为1.6f
使用数学。Float32bit
和数学。Float64bit
,您可以看到Go如何将不同的十进制值表示为IEEE 754二进制值:
游乐场:https://play.html" target="_blank">golang.org/p/ZqzdCZLfvC
结果:
float32(0.1): 00111101110011001100110011001101
float32(0.2): 00111110010011001100110011001101
float32(0.3): 00111110100110011001100110011010
float64(0.1): 0011111110111001100110011001100110011001100110011001100110011010
float64(0.2): 0011111111001001100110011001100110011001100110011001100110011010
float64(0.3): 0011111111010011001100110011001100110011001100110011001100110011
如果将这些二进制表示形式转换为十进制值并进行循环,您可以看到对于float32,a
的初始值将为:
0.20000000298023224
+ 0.10000000149011612
- 0.30000001192092896
= -7.4505806e-9
一个负值,永远不会和1相加。
那么,为什么C表现不同呢?
如果您查看二进制模式(并且稍微了解如何表示二进制值),您可以看到Go循环最后一位,而我假设C只是对其进行裁剪。
因此,在某种意义上,虽然Go和C都不能在浮点中精确表示0.1,但Go使用最接近0.1的值:
Go: 00111101110011001100110011001101 => 0.10000000149011612
C(?): 00111101110011001100110011001100 => 0.09999999403953552
编辑:
我发布了一个关于C如何处理浮点常量的问题,从答案来看,似乎任何C标准的实现都可以这样做。您尝试过的实现只是做得与Go不同。
谢谢
问题内容: 我编写了一个程序来演示Go中的浮点错误: 它打印: 这与用C编写的同一程序的行为匹配(使用类型) 但是,如果使用,则该程序将陷入无限循环!如果您将C程序修改为使用a 而不是a ,则会输出 使用时,为什么Go程序没有与C程序相同的输出? 问题答案: 同意ANisus,go在做正确的事。关于C,我不相信他的猜测。 C标准没有规定,但是libc的大多数实现会将十进制表示形式转换为最接近的浮点
问题内容: $a = ‘35’; $b = ‘-34.99’; echo ($a + $b); 结果为0.009999999999998 这是怎么回事?我想知道为什么我的程序不断报告奇怪的结果。 为什么PHP不返回预期的0.01? 问题答案: 因为浮点运算!=实数运算。对于一些浮子和,由不精确性引起的差异的说明是。这适用于使用浮点数的任何语言。 由于浮点数是具有有限精度的二进制数,因此存在有限数量
本文向大家介绍Fortran 浮点数精度,包括了Fortran 浮点数精度的使用技巧和注意事项,需要的朋友参考一下 示例 类型的浮点数real不能有任何实数值。它们可以表示实数,最多可以包含一定数量的十进制数字。 FORTRAN 77保证了两种浮点类型,而最新的标准则至少保证了两种实数类型。实变量可以声明为 x这是默认类型的实数,并且y是比更大的十进制精度的实数x。在Fortran 2008中,十
问题内容: 我正在读取一个带有浮点数的文本文件,这些数字都带有1或2个小数点。我正在使用将线转换为浮点数,并在失败的情况下引发。我将所有花车存储在列表中。打印时,我想将其打印为2个小数位的浮点数。 假设我有一个文本文件,其编号为-3,65、9,17、1。我阅读了每个文件,然后将它们转换为float并将它们附加到列表中。现在在Python 2中,调用return 。但是在Python 3中,-3.6
运行以下代码时,我希望收到这样的输出: 但结果如下: 欢迎任何能指导我正确使用浮点比较和正确使用setprecision的建议。