在 Python 中舍入以避免机器精度错误

Rounding in Python to avoid machine precision errors

我想检查一个浮点数是否是另一个浮点数的倍数,但 运行 遇到机器精度问题。例如:

t1 = 0.02
factor = 0.01
print(t1%factor==0)

以上输出True,但是

t2 = 0.030000000000000002
print(round(t2,5)%factor==0)

这输出 False。在我的代码中的某些点,我正在检查的数字会产生这些机器精度错误,我认为我可以简单地通过四舍五入来解决这个问题(我的代码后面需要 5 位小数,但如果我只需四舍五入到小数点后两位)。

为什么上面的检查 round(t2,5)%factor==0 没有按预期工作?我该如何解决?

一般来说,Python 中的浮点数是...乱七八糟的,找不到更好的词了。他们可以以非常出乎意料的方式行事。 (您可以阅读有关该行为的更多信息 here。)

然而,为了您的目标,更好的方法是:

t2 = 0.03000003
factor = 0.01
precision = 10000  # 4 digits
print(int(t2*precision)%int(factor*precision)==0)

将数学转移到基于整数的计算可以解决大部分问题。

它没有按预期工作,因为检查浮点数是否相等几乎从不按预期工作。快速修复是使用 math.isclose。这也允许您调整您的容忍度。记住在做算术mod r的时候,r等于0,所以你应该检查你是否接近于0或r。

import math

t1 = 0.02
factor = 0.01
res = t1 % factor
print(math.isclose(res, 0) or math.isclose(res, factor))

这是非常快速和肮脏的,您需要确保您的公差对这两项检查都正确且等效。

您应该使用十进制模块。 decimal 模块提供对快速正确舍入的十进制浮点运算的支持。

import decimal
print( decimal.Decimal('0.03') % decimal.Decimal('0.01') == decimal.Decimal('0') )

给出:

True