众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
当前回答
使用Python的decimal模块,该模块提供decimal类。
评论如下:
值得注意的是,如果你 做繁重的数学工作,而你没有 绝对需要精准的 小数,这很麻烦 下来。浮点数要快得多 处理,但不精确。小数是 非常精确但很慢。
其他回答
我喜欢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))
浮点数不能相等比较的常识是不准确的。浮点数与整数没有什么不同:如果你计算“a == b”,如果它们是相同的数字,你就会得到真值,否则就会得到假值(要理解两个nan当然不是相同的数字)。
实际的问题是:如果我做了一些计算,但不确定我要比较的两个数字是否完全正确,那么该怎么办?这个问题对于浮点数和整数是一样的。如果计算整数表达式“7/3*3”,它将不等于“7*3/3”。
假设我们问"如何比较整数是否相等"在这种情况下。没有唯一的答案;你应该做什么取决于具体的情况,尤其是你有什么样的错误和你想要达到什么。
这里有一些可能的选择。
If you want to get a "true" result if the mathematically exact numbers would be equal, then you might try to use the properties of the calculations you perform to prove that you get the same errors in the two numbers. If that is feasible, and you compare two numbers that result from expressions that would give equal numbers if computed exactly, then you will get "true" from the comparison. Another approach is that you might analyze the properties of the calculations and prove that the error never exceeds a certain amount, perhaps an absolute amount or an amount relative to one of the inputs or one of the outputs. In that case, you can ask whether the two calculated numbers differ by at most that amount, and return "true" if they are within the interval. If you cannot prove an error bound, you might guess and hope for the best. One way of guessing is to evaluate many random samples and see what sort of distribution you get in the results.
当然,因为我们只设置了在数学上精确的结果相等的情况下获得“真”的要求,所以即使它们不相等,我们也保留了获得“真”的可能性。(事实上,我们可以通过总是返回“true”来满足这个要求。这使得计算简单,但通常是不可取的,所以我将在下面讨论如何改善这种情况。)
如果您希望在数学上精确的数字不相等时得到“错误”结果,则需要证明在数学上精确的数字不相等时,对数字的计算会产生不同的数字。在许多常见情况下,从实际的角度来看,这可能是不可能的。所以让我们考虑另一种选择。
A useful requirement might be that we get a "false" result if the mathematically exact numbers differ by more than a certain amount. For example, perhaps we are going to calculate where a ball thrown in a computer game traveled, and we want to know whether it struck a bat. In this case, we certainly want to get "true" if the ball strikes the bat, and we want to get "false" if the ball is far from the bat, and we can accept an incorrect "true" answer if the ball in a mathematically exact simulation missed the bat but is within a millimeter of hitting the bat. In that case, we need to prove (or guess/estimate) that our calculation of the ball's position and the bat's position have a combined error of at most one millimeter (for all positions of interest). This would allow us to always return "false" if the ball and bat are more than a millimeter apart, to return "true" if they touch, and to return "true" if they are close enough to be acceptable.
所以,在比较浮点数时,如何决定返回什么很大程度上取决于你的具体情况。
As to how you go about proving error bounds for calculations, that can be a complicated subject. Any floating-point implementation using the IEEE 754 standard in round-to-nearest mode returns the floating-point number nearest to the exact result for any basic operation (notably multiplication, division, addition, subtraction, square root). (In case of tie, round so the low bit is even.) (Be particularly careful about square root and division; your language implementation might use methods that do not conform to IEEE 754 for those.) Because of this requirement, we know the error in a single result is at most 1/2 of the value of the least significant bit. (If it were more, the rounding would have gone to a different number that is within 1/2 the value.)
Going on from there gets substantially more complicated; the next step is performing an operation where one of the inputs already has some error. For simple expressions, these errors can be followed through the calculations to reach a bound on the final error. In practice, this is only done in a few situations, such as working on a high-quality mathematics library. And, of course, you need precise control over exactly which operations are performed. High-level languages often give the compiler a lot of slack, so you might not know in which order operations are performed.
关于这个主题还有很多可以(也已经)写的东西,但我必须在这里停下来。总之,答案是:没有用于这种比较的库例程,因为没有适合大多数需求的单一解决方案值得放入库例程中。(如果比较相对或绝对误差间隔对您来说足够了,您可以不使用库例程简单地进行比较。)
我发现下面的比较很有帮助:
str(f1) == str(f2)
不带atol/rtol与给定小数进行比较:
def almost_equal(a, b, decimal=6):
return '{0:.{1}f}'.format(a, decimal) == '{0:.{1}f}'.format(b, decimal)
print(almost_equal(0.0, 0.0001, decimal=5)) # False
print(almost_equal(0.0, 0.0001, decimal=4)) # True
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是在所有情况下按原样应用的绝对容差。如果差值小于这些公差中的任何一个,则认为值相等。