众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
当前回答
我发现下面的比较很有帮助:
str(f1) == str(f2)
其他回答
至于绝对误差,你可以检查一下
if abs(a - b) <= error:
print("Almost equal")
一些关于Python中浮动行为怪异的信息: Python 3教程03 - if-else,逻辑运算符和初学者常犯的错误
你也可以用数学。相对误差接近。
我同意Gareth的答案可能是最合适的轻量级函数/解决方案。
但我认为,如果您正在使用NumPy或正在考虑使用NumPy,那么有一个打包的函数用于此,这将是有帮助的。
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
不过有一点免责声明:根据您的平台,安装NumPy可能是一种非常重要的体验。
Python 3.5增加了数学运算。Isclose和cmath。isclose函数如PEP 485所述。
如果您使用的是较早版本的Python,相应的函数在文档中给出。
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
Rel_tol是一个相对容差,它乘以两个参数的大小中较大的一个;当值变大时,它们之间允许的差异也会变大,但仍然认为它们相等。
Abs_tol是在所有情况下按原样应用的绝对容差。如果差值小于这些公差中的任何一个,则认为值相等。
math.isclose()已为此添加到Python 3.5(源代码)。这里是它到Python 2的一个端口。它与Mark Ransom的单行程序的不同之处在于它可以正确地处理“inf”和“-inf”。
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
'''
Python 2 implementation of Python 3.5 math.isclose()
https://github.com/python/cpython/blob/v3.5.10/Modules/mathmodule.c#L1993
'''
# sanity check on the inputs
if rel_tol < 0 or abs_tol < 0:
raise ValueError("tolerances must be non-negative")
# short circuit exact equality -- needed to catch two infinities of
# the same sign. And perhaps speeds things up a bit sometimes.
if a == b:
return True
# This catches the case of two infinities of opposite sign, or
# one infinity and one finite number. Two infinities of opposite
# sign would otherwise have an infinite relative tolerance.
# Two infinities of the same sign are caught by the equality check
# above.
if math.isinf(a) or math.isinf(b):
return False
# now do the regular computation
# this is essentially the "weak" test from the Boost library
diff = math.fabs(b - a)
result = (((diff <= math.fabs(rel_tol * b)) or
(diff <= math.fabs(rel_tol * a))) or
(diff <= abs_tol))
return result
这可能是一个有点丑陋的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}'