我问这个的原因是因为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
返回一个奇数值。
有人可以向我解释为什么会这样吗?
答案 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 "")