机器算术和涂抹:大数和小数相加

Machine Arithmetic and Smearing: addition of a large an small number

所以到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上,避免smaering。

主要问题是 1/100000.0001 不能准确编码为机器浮点值(参见 IEEE 754 标准),因为 10000 不是2的幂。另外1/10 = 0.1不能编码为机器浮点数,所以你会遇到像0.1 + 0.1 + 0.1 > 0.3.

这样的现象

使用双精度(64 位)计算时,以下成立:

1.0001 - 1 < 0.0001
10000.0001 + 9999*0.0001 == 10001

所以我假设您正在使用单精度(32 位)进行计算?

单次加法的小"smearing"误差可以精确计算为

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