带浮点数的python舍入错误

Python rounding error with float numbers

本问题已经有最佳答案,请猛点这里访问。

我不知道这是否是一个明显的错误,但是当运行一个用于改变模拟参数的python脚本时,我发现delta=0.29和delta=0.58的结果丢失了。在调查中,我注意到以下python代码:

1
2
3
4
5
6
for i_delta in range(0, 101, 1):
  delta = float(i_delta) / 100

  (...)

filename = 'foo' + str(int(delta * 100)) + '.dat'

为delta=0.28和0.29生成了相同的文件,与.57和.58相同,原因是python将float(29)/100返回为0.28999999999998。但这不是一个系统性的错误,不是说它发生在每个整数上。所以我创建了下面的python脚本:

1
2
3
4
5
6
7
import sys

n = int(sys.argv[1])

for i in range(0, n + 1):
  a = int(100 * (float(i) / 100))
  if i != a: print i, a

我看不到数字中出现这种舍入误差的模式。为什么这些特定的数字会发生这种情况?


任何不能用2的精确幂建立的数都不能精确地表示为浮点数;它需要近似。有时最接近的近似值会小于实际值。

阅读每个计算机科学家应该知道的关于浮点运算的知识。


由于浮点数的性质,它非常有名。

如果你想做十进制算术而不是浮点算术,有一些库可以做到这一点。

例如。,

1
2
3
4
5
6
7
>>> from decimal import Decimal
>>> Decimal(29)/Decimal(100)
Decimal('0.29')
>>> Decimal('0.29')*100
Decimal('29')
>>> int(Decimal('29'))
29

一般来说,当数字没有有限的十进制表示时(例如分母不是1或分母不是2或5的任何分数-十进制基数(10)的因子),小数可能会出现舍入错误,并且在极少数情况下仍然会出现舍入错误。例如:

1
2
3
4
5
>>> s = Decimal(7)
>>> Decimal(1)/s/s/s/s/s/s/s*s*s*s*s*s*s*s
Decimal('0.9999999999999999999999999996')
>>> int(Decimal('0.9999999999999999999999999996'))
0

所以最好总是在将浮点值强制转换为整数之前进行取整,除非您希望使用floor函数。

1
2
3
4
>>> int(1.9999)
1
>>> int(round(1.999))
2

另一种选择是使用分数库中不近似的分数类。(它会根据需要不断地加减整数分子和分母)。