众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
当前回答
我同意Gareth的答案可能是最合适的轻量级函数/解决方案。
但我认为,如果您正在使用NumPy或正在考虑使用NumPy,那么有一个打包的函数用于此,这将是有帮助的。
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
不过有一点免责声明:根据您的平台,安装NumPy可能是一种非常重要的体验。
其他回答
这对于你想要确保两个数字是相同的“达到精度”的情况很有用,并且不需要指定公差:
求这两个数的最小精度 将两者舍入到最小精度并进行比较
def isclose(a, b):
astr = str(a)
aprec = len(astr.split('.')[1]) if '.' in astr else 0
bstr = str(b)
bprec = len(bstr.split('.')[1]) if '.' in bstr else 0
prec = min(aprec, bprec)
return round(a, prec) == round(b, prec)
如上所述,它只适用于字符串表示中没有'e'的数字(意思是0.999999999999995e -4 < number <= 0.99999999999999995e11)
例子:
>>> isclose(10.0, 10.049)
True
>>> isclose(10.0, 10.05)
False
做一些像下面这样简单的事情就足够了:
return abs(f1 - f2) <= allowed_error
至于绝对误差,你可以检查一下
if abs(a - b) <= error:
print("Almost equal")
一些关于Python中浮动行为怪异的信息: Python 3教程03 - if-else,逻辑运算符和初学者常犯的错误
你也可以用数学。相对误差接近。
I'm not aware of anything in the Python standard library (or elsewhere) that implements Dawson's AlmostEqual2sComplement function. If that's the sort of behaviour you want, you'll have to implement it yourself. (In which case, rather than using Dawson's clever bitwise hacks you'd probably do better to use more conventional tests of the form if abs(a-b) <= eps1*(abs(a)+abs(b)) + eps2 or similar. To get Dawson-like behaviour you might say something like if abs(a-b) <= eps*max(EPS,abs(a),abs(b)) for some small fixed EPS; this isn't exactly the same as Dawson, but it's similar in spirit.
这可能是一个有点丑陋的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}'