【问题标题】:compare two floats for equality in Python [duplicate]在Python中比较两个浮点数的相等性[重复]
【发布时间】:2016-01-06 13:48:44
【问题描述】:

在 Python 中比较两个浮点数时,我总是看到这样的代码来比较一个小值 epsilon,想知道选择正确 epsilon 值的最佳实践是什么?而它背后的场景又是怎样的呢?谢谢。

epsilon = 0.000001
abs(a - b)<epsilon

【问题讨论】:

  • 在 python 3.5 中添加了这个:docs.python.org/3.5/library/math.html#math.isclose。根据文档,它或多或少地返回:abs(a-b) &lt;= max( rel_tol * max(abs(a), abs(b)), abs_tol )
  • 您是否希望获得最小的 epsilon,或者您认为您希望根据您的 a 和 b 动态更改您的 epsilon?
  • 请参阅stackoverflow.com/questions/6837007/… 了解一种方法。问题是针对 Java 的,但答案是通用的。
  • Python 只有一个浮点类型float,而且在我熟悉的每个实现中,它都是 64 位 IEEE。
  • 为 Python 3.5 选择的精度边界在我在另一个问题上留下的答案中。如果您有不同的感觉,我已为您提供了足够的信息以做出明智的决定。

标签: python floating-point


【解决方案1】:

答案相当复杂,因为您需要知道如何保存单精度或双精度浮点数 (Wikipedia),根据经验,您可以使用 this Table on Wikipedia 作为选择 epsilon 的参考。但是可能会有一些例外,特别是如果您不完全知道它是 float32 还是 float64(或者对于 Linux/Mac,也有 float96 和 float128)。

但我想最好的做法是使用一些预定义的函数,例如 numpy_assert_array_almost_equal(需要 numpy)。

我想每个人处理它的方式都不同,只要你可以相信你的结果,每种方法都有其优点和缺点。并且始终记住,浮点数可能会因错误的算术运算而完全失控。即正在计算大值的小差异。最后,epsilon 的值取决于需要的精度以及应该在那里测试的精度。

【讨论】:

  • 感谢 MSeifert,我通读了这份文档 (en.wikipedia.org/wiki/…),内容非常丰富。我对一件事感到困惑,在表格中有两列名为“Machine epsilon”,想知道它们有什么区别?
  • @LinMa 不同之处在于您要如何定义它:第一个只是第二个除以二。因此,第一个可能是您想要的,因为您比较了两个浮点数差异的 absolute。我猜第一个类似于+/- 错误,第二个更像是任何浮点数上的绝对错误。但我不太确定。
  • @LinMa 不幸的是,没有简单的方法来确定这样的 epsilon。因为比较结果的质量有另一个 epsilon 作为初始值。假设你有一个变量A,浮点错误epsilon1。如果您查看B 的错误A+A,它的浮点错误现在是2*epsilon。添加可能是可重构的,但假设您使用 A+B*C/D**E % math.exp(F) 这个结果会有什么错误?
  • 也许我错了,但尝试a=0 然后尝试for i in range(1000): a+=0.1print(a-100) 然后再尝试for loopprint(a-200) 你可以一次又一次地尝试这个,至少在我的电脑上差异越来越大。
  • 这证明了你不能定义一个通用的epsilon 来进行任意浮点比较,因为你可能知道也可能不知道浮点是如何处理的。
【解决方案2】:

选择正确的 epsilon 值的最佳做法是什么?

这取决于应用程序的要求。

如果它正在为我所在的航天器再入计划一个地球轨道,我会选择一个非常小的值,比如epsilon = (a+b) * 1e-15

如果它预测美国联邦赤字(其本身具有很大的不确定性),则可能适合更大的 epsilon:epsilon = (a+b) * 0.002

【讨论】:

  • 感谢 wallyk 提供的样本,我同意你的不同精度适用于不同的情况。我的问题更多来自 Python 内部表示,它可能是什么精度边界。正如您的示例所示,在某些情况下,您可以使用 1e-15,但我如何知道 Python 内部是否可以对浮点数或双精度数具有如此精度?感谢您的见解。谢谢。
【解决方案3】:

如果您正在寻找有史以来最好的 epsilon,为了获得最佳比较,您可以使用 python 的 sys epsilon using

>>> import sys
>>> sys.float_info.epsilon
2.220446049250313e-16

但如果您更希望根据您的 a 和 b 动态地拥有此 epsilon,我建议您选择:

abs(f1-f2) < tol*max(abs(f1),abs(f2))

abs(a-b) <= max( rel_tol * max(abs(a), abs(b)), abs_tol )

【讨论】:

  • 感谢用户12321,有点迷茫,动态使用epsilon有什么好处?一个例子表示赞赏。
【解决方案4】:

numpy 中有一个 assert 函数用于此目的,默认使用七位小数精度。

from numpy.testing import assert_almost_equal

a = 0.000000001
b = 0.0000000001

>>> assert_almost_equal(a, b)
# Nothing returned.

b = 1
>>> assert_almost_equal(a, b)
AssertionError: 
Arrays are not almost equal to 7 decimals
 ACTUAL: 1e-09
 DESIRED: 1

【讨论】:

  • 嗨,Alexander,非常整洁,但是如何在您的实践中选择小数的值?
  • 这是非常主观的,完全取决于你在做什么。这样的问题本身就是一个编程问题,在我看来并不适合 SO。
  • ** 不是编程问题
  • 谢谢 Alexander,我认为 Python 应该有自己的浮点精度边界,为什么不把它用作 epsilon?谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-08-24
  • 1970-01-01
  • 2015-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-17
相关资源
最近更新 更多