Python 测试浮点相等性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4028889/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 13:55:23  来源:igfitidea点击:

Testing floating point equality

pythoncomparisonfloating-point

提问by Neil G

Is there a function to test floating point approximate equality in python? Something like,

python中是否有测试浮点近似相等的函数?就像是,

 def approx_equal(a, b, tol):
     return abs(a - b) < tol

My use case is similar to how Google's C++ testing library, gtest.h, defines EXPECT_NEAR.

我的用例类似于 Google 的 C++ 测试库 gtest.h 如何定义EXPECT_NEAR.

Here is an example:

下面是一个例子:

def bernoulli_fraction_to_angle(fraction):
    return math.asin(sqrt(fraction))
def bernoulli_angle_to_fraction(angle):
    return math.sin(angle) ** 2
def test_bernoulli_conversions():
    assert(approx_equal(bernoulli_angle_to_fraction(pi / 4), 0.5, 1e-4))
    assert(approx_equal(
              bernoulli_fraction_to_angle(bernoulli_angle_to_fraction(0.1)),
                0.1, 1e-4))

采纳答案by Neil G

  • For comparing numbers, there is math.iscloseas per PEP 485since Python 3.5.
  • For comparing numbers or arrays, there is numpy.allclose.
  • For testing numbers or arrays, there is numpy.testing.assert_allclose
  • 为了比较数字,从 Python 3.5 开始math.isclose,按照PEP 485 进行
  • 为了比较数字或数组,有numpy.allclose.
  • 对于测试数字或数组,有 numpy.testing.assert_allclose

回答by Rafe Kettler

If I were you, I'd just use what you wrote, and either put it in a separate module (perhaps with other utilities you need that Python doesn't have an implementation for) or at the top of whatever code requires it.

如果我是你,我只会使用你写的东西,或者把它放在一个单独的模块中(也许还有你需要的其他实用程序,而 Python 没有实现),或者放在任何需要它的代码的顶部。

You can also use a lambda expression (one of my favorite language features, but probably less clear):

您还可以使用 lambda 表达式(我最喜欢的语言功能之一,但可能不太清楚):

approx_equal = lambda a, b, t: abs(a - b) < t

回答by S.Lott

Is there a function to test floating point approximate equality in python?

python中是否有测试浮点近似相等的函数?

There can't be afunction, since the definition depends on context.

不能函数,因为定义取决于上下文。

def eq( a, b, eps=0.0001 ):
    return abs(a - b) <= eps

Doesn't always work. There are circumstances where

并不总是有效。有这样的情况

def eq( a, b, eps=0.0001 ):
     return abs( a - b ) / abs(a) <= eps

could be more appropriate.

可能更合适。

Plus, there's the always popular.

另外,总是很受欢迎。

def eq( a, b, eps=0.0001 ):
    return abs(math.log( a ) - math.log(b)) <=  eps

Which might be more appropriate.

哪个可能更合适。

I can't see how you can ask for a(single) function do combine all the mathematical alternatives. Since it depends on the application.

我看不出你怎么能要求一个(单个)函数结合所有的数学替代方案。因为这取决于应用程序。

回答by martineau

Another approach is to compute the relative change(or relative difference) of the two numbers, which is "used to compare two quantities while taking into account the 'sizes' of the things being compared". The two formulasmentioned in the Wikipedia article could be used in comparisons like the following in Python, which also handle cases where one or both of the values being compared are zero:

另一种方法是计算两个数字的相对变化(或相对差异),它“用于比较两个数量,同时考虑被比较事物的‘大小’”。维基百科文章中提到的两个公式可用于 Python 中的如下比较,它还可以处理被比较的一个或两个值为零的情况:

def approx_equal(a, b, tol):
    return abs(a-b) <= max(abs(a), abs(b)) * tol

def approx_equal(a, b, tol):
    return abs(a-b) <= (abs(a)+abs(b))/2 * tol

The calculated value in either case is a unitless fraction. In the first case the baseline value is the maximum absolute value of the two numbers and in the second it's their mean absolute value. The article discusses each in more detail as well as their pros and cons. The latter can turned into a percentage differenceif multiplied by 100 before the comparison (with tolbecoming a percentage value). Note that the article suggests that if the changing value "is a percentage itself, it is better to talk about its change by using percentage points" — i.e. absolute change.

两种情况下的计算值都是无单位分数。在第一种情况下,基线值是两个数字的最大绝对值,在第二种情况下是它们的平均绝对值。文章更详细地讨论了每种方法及其优缺点。如果在比较之前乘以 100 ,后者可以变成百分比差异tol成为百分比值)。请注意,文章建议,如果变化值“本身就是一个百分比,最好用百分比来谈论它的变化”——即绝对变化。

Both of these methods (obviously) require a little more computation than simply taking the absolute value of the difference of the two numbers, which might be a consideration.

这两种方法(显然)都需要比简单地取两个数字差的绝对值多一点的计算,这可能是一个考虑因素。

回答by SingleNegationElimination

Comparing floats for equality is just usually a bad idea. Even with the tolerance feature you're using, this isn't really what you want to do.

比较浮动的平等性通常是一个坏主意。即使使用您正在使用的容差功能,这也不是您真正想要做的。

If you want to use floats, a reasonable option is to refactor your algorithm to use inequalities, a < bbecause this is more likely to do what you expect, with far fewer false negatives or positives, and most importantly, it means you don't have to guess how equal they must be for them to be equal.

如果你想使用浮点数,一个合理的选择是重构你的算法以使用不等式,a < b因为这更有可能达到你的预期,假阴性或阳性少得多,最重要的是,这意味着你不必猜猜他们必须有多平等才能平等。

If you can't do that, another option is to use an exact representation. If your algorithm is composed only of arithmetic operations (+, -, *and /) then you can use a rational represntation, as provided by fractions.Fraction, or maybe decimal.Decimalis what you want (for instance, with financial calculations).

如果您不能这样做,另一种选择是使用精确表示。如果您的算法仅由算术运算 ( +, -,*/) 组成,那么您可以使用由 提供的有理表示fractions.Fraction,或者可能decimal.Decimal是您想要的(例如,财务计算)。

If your algorithm cannot be expressed easily with an arbitrary precision representation, another choice is to manage the roundoff error explicitly with interval arithmetic, for instance with this module.

如果您的算法无法用任意精度表示轻松表达,另一种选择是使用区间算法明确管理舍入误差,例如使用此模块

回答by Saeid BK

According to the tutorial:

根据教程

... Though the numbers cannot be made closer to their intended exact values, the round() function can be useful for post-rounding so that results with inexact values become comparable to one another...

...虽然数字不能更接近其预期的精确值,但 round() 函数可用于后四舍五入,以便具有不精确值的结果彼此之间具有可比性...

Therefore, this is the way that I define "isclose" functions in Python:

因此,这是我在 Python 中定义“isclose”函数的方式:

def isclose(a, b, ndigits):
   return round(a-b, ndigits) == 0

I usually use 5 as ndigits; However, it depends on the precision that you expect.

我通常使用 5 作为ndigits; 但是,这取决于您期望的精度。