“round”ed编号乘以0.01会产生x.y00000000000001而不是x.y?

时间:2012-03-28 22:32:06

标签: python openerp

我问这个的原因是因为OpenERP中的验证让我发疯了:

>>> round(1.2 / 0.01) * 0.01
1.2
>>> round(12.2 / 0.01) * 0.01
12.200000000000001
>>> round(122.2 / 0.01) * 0.01
122.2
>>> round(1222.2 / 0.01) * 0.01
1222.2

如您所见,第二个round返回一个奇数值。

有人可以向我解释为什么会这样吗?

4 个答案:

答案 0 :(得分:8)

这实际上与round无关,如果你只是1220 * 0.01,你可以看到完全相同的问题:

>>> 1220*0.01
12.200000000000001

您在此处看到的是标准浮点问题。

您可能想要了解维基百科对floating point accuracy problems所说的内容:

  

浮点数不能精确地表示所有实数,并且浮点运算不能精确地表示真正的算术运算,这会导致许多令人惊讶的情况。这与计算机通常代表数字的有限精度有关。

另见:

浮点数值不稳定的一个简单示例: 数字是有限的。假设我们在给定计算机或语言中的点之后保存4位数。 0.0001乘以0.0001会导致低于0.0001,因此无法保存此结果! 在这种情况下,如果你计算(0.0001 x 0.0001)/ 0.0001 = 0.0001,这个简单的计算机将无法准确,因为它试图先加倍而后才加倍除。在javascript中,除以分数会导致类似的不准确性。

答案 1 :(得分:5)

您正在使用的float类型存储二进制浮点数。并非每个十进制数都可以表示为float。特别是没有1.2或0.01的精确表示,因此存储在计算机中的实际数字与源代码中写入的值略有不同。这种表示错误可能导致计算结果与精确的数学结果略有不同。

重要的是要注意每当使用浮点运算时出现小错误的可能性,并且即使计算出的值不完全正确,也要编写代码以使其正常工作。例如,在将值显示给用户时,应考虑将值四舍五入到一定数量的小数位。

您还可以考虑使用存储十进制浮点数的decimal类型。如果您使用decimal,则可以准确存储1.2。但是,使用decimal会降低代码的性能。如果十进制数的精确表示很重要,则应该只使用它。您还应该意识到decimal并不意味着您永远不会有任何问题。例如,0.33333 ...没有精确表示为decimal

答案 2 :(得分:4)

由于存储浮点数的方式,分区的准确性会有所下降,因此您会看到此标识不存在

>>> 12.2 / 0.01 * 0.01 == 12.2
False

bArmageddon,提供了一堆你应该阅读的链接,但我相信外卖信息是不要指望浮点数给出确切的结果,除非你完全理解表示的限制。

特别是不要用花车来代表金额!这是一个很常见的错误

Python也有十进制模块,可能对你有用

答案 3 :(得分:2)

其他人回答了你的问题,并提到很多数字都没有精确的二进制小数表示。如果你习惯于只使用十进制数字,那么一个漂亮的“圆形”数字(如0.01)在某些其他基数中可能是一个非终止数字似乎是非常奇怪的。本着“眼见为实”的精神,这里有一个Python程序,可以将任意数字的二进制表示打印成任意数字的数字。

from decimal import Decimal

n = Decimal("0.01")     # the number to print the binary equivalent of
m = 1000                # maximum number of digits to print

p = -1
r = []
w = int(n)
n = abs(n) - abs(w)

while n and -p < m:
    s = Decimal(2) ** p
    if n >= s:
        r.append("1")
        n -= s
    else:
        r.append("0")
    p -= 1

print "%s.%s%s" % ("-" if w < 0 else "", bin(abs(w))[2:], 
                   "".join(r), "..." if n else "")