Math 机器运算和涂抹:大数和小数的相加

Math 机器运算和涂抹:大数和小数的相加,math,binary,precision,Math,Binary,Precision,因此,在10000的基础上加上1/10000的值。从逻辑上讲,这是10001。 但是,由于涂抹,由于存储限制,不会发生这种情况。结果是10000.9999999228。 我已经找到了涂抹发生的位置,这是第二次添加: 1: 10000.0001 2: 10000.000199999999 3: 10000.000299999998 4: 10000.000399999997 etc... 然而,要弄清楚为什么会发生这种污点才是斗争的关键所在。 我编写了生成浮点二进制数的代码,以查看这里是

因此,在10000的基础上加上1/10000的值。从逻辑上讲,这是10001。 但是,由于涂抹,由于存储限制,不会发生这种情况。结果是10000.9999999228。 我已经找到了涂抹发生的位置,这是第二次添加:

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上,以避免弄虚作假。

主要的问题是
1/10000
0.0001
不能完全编码为机器浮点值(参见标准),因为
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
1.0001-1<0.0001
10000.0001 + 9999*0.0001 == 10001
因此,我假设您是以单精度(32位)计算的?

单次加法的小“涂抹”误差可以精确地计算为

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

您最好能找到一本好的浮点表示的通用指南。我会推荐,或者,对于一个更温和的骑行,推荐。