因此,对于10000,将添加值1/10000 10000次。从逻辑上讲,这给出了10001。 但是,由于涂抹不会发生这种情况,这源于存储限制。结果是10000.999999992928。 我找到了涂抹的位置,这是第二次添加:
1: 10000.0001
2: 10000.000199999999
3: 10000.000299999998
4: 10000.000399999997
etc...
然而,掌握涂抹的原因是斗争的所在。 我编写代码来生成浮点二进制数,以查看是否发生了拖尾
So 10000 = 10011100010000 or 1.001110001*10**13 while
0.0001= 0.00000000000001101001 or
1.1010001101101110001011101011000111000100001100101101*2**(-14)
then 10000.0001 = 10011100010000.00000000000001101001
现在在下一次添加时会出现拖尾现象。是否与尾数大小有关?为什么它只在这一步中出现?只是有兴趣知道。我将首先添加所有1/10000,然后将其添加到10000以避免晃动。
答案 0 :(得分:0)
主要问题是1/10000
即0.0001
无法完全编码为机器浮点值(请参阅IEEE 754标准),因为10000
不是2. 1/10 = 0.1
也不能编码为机器浮动,因此您将体验到像0.1 + 0.1 + 0.1 > 0.3
这样的phanomena。
当使用双精度(64位)进行计算时,以下内容成立:
1.0001 - 1 < 0.0001
10000.0001 + 9999*0.0001 == 10001
所以我假设您使用单精度(32位)进行计算?
答案 1 :(得分:0)
单次添加的小“拖尾”错误可以完全按照
计算a=10000; b=0.0001
err = ((a+b)-a)-b
print "err=",err
>>> err= -7.07223084891e-13
添加的舍入误差大小为(abs(a)+abs(b))*mu/2
或大约1e4 * 1e-16 = 1e-12
,这非常适合计算结果。
一般来说,你还必须测试表达式((a+b)-b)-a
,但其中一个总是为零,这里是后一个。
事实上,在所有步骤中积累的这一步误差已经给出了观察结果,与总和缓慢增加相关的二次误差,因为每次添加的第一项影响要小得多。
print err*10000
>>> -7.072230848908026e-09
print 10001+err*10000
>>> 10000.999999992928