众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
众所周知,由于舍入和精度问题,比较浮点数是否相等有点棘手。
例如:比较浮点数,2012版
在Python中处理这个问题的推荐方法是什么?
有标准的库函数吗?
当前回答
如果你想在测试/TDD环境中使用它,我认为这是一种标准方法:
from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) # The default is 7
其他回答
我同意Gareth的答案可能是最合适的轻量级函数/解决方案。
但我认为,如果您正在使用NumPy或正在考虑使用NumPy,那么有一个打包的函数用于此,这将是有帮助的。
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
不过有一点免责声明:根据您的平台,安装NumPy可能是一种非常重要的体验。
浮点数不能相等比较的常识是不准确的。浮点数与整数没有什么不同:如果你计算“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.
关于这个主题还有很多可以(也已经)写的东西,但我必须在这里停下来。总之,答案是:没有用于这种比较的库例程,因为没有适合大多数需求的单一解决方案值得放入库例程中。(如果比较相对或绝对误差间隔对您来说足够了,您可以不使用库例程简单地进行比较。)
我喜欢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))
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.
如果你想在测试或TDD上下文中使用pytest包,下面是如何做到的:
import pytest
PRECISION = 1e-3
def assert_almost_equal():
obtained_value = 99.99
expected_value = 100.00
assert obtained_value == pytest.approx(expected_value, PRECISION)