众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
当前回答
这可能是一个有点丑陋的hack,但当你不需要超过默认的浮点精度(大约11个小数)时,它工作得很好。
round_to函数使用内置str类中的format方法将浮点数四舍五入为表示浮点数的字符串,其中包含所需的小数数,然后将eval内置函数应用于四舍五入的浮点数字符串,以返回浮点数字类型。
is_close函数只是对四舍五入的浮点数应用一个简单的条件。
def round_to(float_num, prec):
return eval("'{:." + str(int(prec)) + "f}'.format(" + str(float_num) + ")")
def is_close(float_a, float_b, prec):
if round_to(float_a, prec) == round_to(float_b, prec):
return True
return False
>>>a = 10.0
10.0
>>>b = 10.0001
10.0001
>>>print is_close(a, b, prec=3)
True
>>>print is_close(a, b, prec=4)
False
更新:
正如@stepehjfox所建议的,构建一个避免“eval”的rount_to函数的更干净的方法是使用嵌套格式:
def round_to(float_num, prec):
return '{:.{precision}f}'.format(float_num, precision=prec)
遵循同样的思想,使用新的f-string (Python 3.6+)代码可以更简单:
def round_to(float_num, prec):
return f'{float_num:.{prec}f}'
所以,我们甚至可以用一个简单干净的'is_close'函数来概括它:
def is_close(a, b, prec):
return f'{a:.{prec}f}' == f'{b:.{prec}f}'
其他回答
如果你想比较浮点数,上面的选项很好,但在我的情况下,我最终使用Enum的,因为我只有几个有效的浮点数,我的用例可以接受。
from enum import Enum
class HolidayMultipliers(Enum):
EMPLOYED_LESS_THAN_YEAR = 2.0
EMPLOYED_MORE_THAN_YEAR = 2.5
然后运行:
testable_value = 2.0
HolidayMultipliers(testable_value)
如果float是有效的,就没问题,否则它会抛出一个ValueError。
对于一些可以影响源数表示的情况,可以使用整数分子和整数分母将它们表示为分数而不是浮点数。这样你就可以进行准确的比较。
详见分数模块中的分数。
如果你想在测试/TDD环境中使用它,我认为这是一种标准方法:
from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) # The default is 7
至于绝对误差,你可以检查一下
if abs(a - b) <= error:
print("Almost equal")
一些关于Python中浮动行为怪异的信息: Python 3教程03 - if-else,逻辑运算符和初学者常犯的错误
你也可以用数学。相对误差接近。
我喜欢Sesquipedal的建议,但有修改(一个特殊的用例时,两个值都是0返回False)。在我的例子中,我使用的是Python 2.7,只使用了一个简单的函数:
if f1 ==0 and f2 == 0:
return True
else:
return abs(f1-f2) < tol*max(abs(f1),abs(f2))