理解数值稳定性大计算损失

时间:2016-03-10 14:31:55

标签: python

我参加了一些关于机器学习的课程,并试图理解这个计算问题:

variable = 1000000000 #1 billion
for i in xrange(1000000):
       variable = variable+ 1e-6 #0.000001

variable = variable -1000000000 #1 subtracts with 1 billion again
variable
#>> 0.95367431640625

应为 1 ,但结果为 0.95367431640625

有人可以告诉我为什么会这样吗?

2 个答案:

答案 0 :(得分:4)

你正在失去精确度。这是因为Python中的float实现了double floating point精度,它只能保证精度达到15/16位。

当你这样做时:

1,000,000,000 + 0.000001
1,000,000,000.000001 + 0.000001
# and so on, note that you are adding the 16-th digit
# but 1,000,000,000.000001 is not actually exactly 1,000,000,000.000001
# behind is something like 1,000,000,000.000001014819 or 1,000,000,000.000000999819

接下来,您违反了精度限制,1中的最后一个0.000001后面还有一些其他值,仅代表0.000001。因此你得到累积错误。

如果您将variable初始化为0,那么事情会有所不同。这是因为在计算中:

0.000000 + 0.000001
0.000001 + 0.000001
0.000002 + 0.000001
#and so on

虽然0.000001的实际值并非0.000001,但第16位不精确度与重要数字相差甚远:

0.000000 + 0.00000100000000000000011111
0.000001 + 0.00000100000000000000011111 #insignificant error

您还可以使用decimal值代替double来避免错误:

from decimal import *
variable = Decimal(1000000000)
addition = Decimal(1e-6)
for i in xrange(1000000):
   variable = variable+ addition #0.000001

variable = variable-Decimal(1000000000) #1 subtracts with 1 billion again
variable

答案 1 :(得分:1)

Python数学本身不能处理任意精度。如果您想要更精确的结果,看起来您需要使用decimal模块,即使这样,也要小心:

from decimal import *
x = Decimal(1000000000)
y = Decimal(1e-6)
z = x+y
z
##>> Decimal(1000000000.00000100000000000)
w = z-x
w
##>> Decimal(0.000001000000000000)

## however, when I tried:
bad_x = Decimal(1000000000 + 1e-6)
bad_x
##>> Decimal(1000000000.0000009992934598234592348593458)

bad_x成为“错误”值的原因是因为它首先在10000000001e-6上进行了常规ython添加,遇到浮点问题,然后接受了(错误的)并将其传递给Decimal - 损坏已经完成。

对于您的用例,看起来您可以在添加/减去之前将值设置为Decimal s ,这样您就可以毫无问题地获得所需的结果。