测试浮点相等性[重复]
- 2025-03-21 09:06:00
- admin 原创
- 65
问题描述:
python 中是否有测试浮点近似相等性的函数?例如,
def approx_equal(a, b, tol):
return abs(a - b) < tol
我的用例与 Google 的 C++ 测试库 gtest.h 的定义类似EXPECT_NEAR
。
以下是一个例子:
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))
解决方案 1:
对于比较数字,有
math.isclose
。为了比较数字或数组,有
numpy.allclose
。对于测试数字或数组,有
numpy.testing.assert_allclose
解决方案 2:
另一种方法是计算两个数字的相对变化(或相对差异),这“用于比较两个数量,同时考虑到被比较事物的‘大小’”。维基百科文章中提到的两个公式可用于 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
在任何一种情况下,计算出的值都是无单位分数。在第一种情况下,基线值是两个数字的最大绝对值,在第二种情况下,基线值是它们的平均绝对值。本文更详细地讨论了每种方法以及它们的优缺点。如果在比较之前将后者乘以 100(变为百分比值),则可以将其转换为百分比差异tol
。请注意,本文建议,如果变化值“本身就是百分比,则最好使用百分点来谈论其变化”——即绝对变化。
这两种方法(显然)都需要比简单地取两个数字差的绝对值更多的计算,这可能需要考虑。
解决方案 3:
在 Python 中是否有一个函数可以测试浮点近似相等性?
不可能存在函数,因为定义取决于上下文。
def eq( a, b, eps=0.0001 ):
return abs(a - b) <= eps
并不总是有效。有些情况下
def eq( a, b, eps=0.0001 ):
return abs( a - b ) / abs(a) <= eps
可能更合适。
此外,还有一直很受欢迎的产品。
def eq( a, b, eps=0.0001 ):
return abs(math.log( a ) - math.log(b)) <= eps
哪一个可能更合适。
我不明白你如何要求一个(单一)函数将所有数学替代方案结合起来。因为这取决于应用程序。
解决方案 4:
如果我是你,我只会使用你写的内容,然后将它放在单独的模块中(也许与你需要但 Python 没有实现的其他实用程序一起)或放在需要它的任何代码的顶部。
您还可以使用 lambda 表达式(我最喜欢的语言特性之一,但可能不太清楚):
approx_equal = lambda a, b, t: abs(a - b) < t
解决方案 5:
比较浮点数是否相等通常不是一个好主意。即使你使用了容差功能,这也不是你真正想要做的。
如果您想使用浮点数,一个合理的选择是重构您的算法以使用不等式,a < b
因为这更有可能实现您所期望的结果,并且假阴性或阳性结果会少得多,最重要的是,这意味着您不必猜测它们必须有多相等才能相等。
如果您不能这样做,另一个选择是使用精确表示。如果您的算法仅由算术运算(、 和+
)-
组成,那么您可以使用有理表示,如 提供,或者 可能是您想要的(例如,用于财务计算)。*
`/fractions.Fraction
decimal.Decimal`
如果您的算法不能很容易地用任意精度表示来表达,另一种选择是使用区间算术明确地管理舍入误差,例如使用此模块。
解决方案 6:
根据教程:
... 虽然数字无法更接近其预期的精确值,但 round() 函数可以用于后期舍入,以便使不精确值的结果可以相互比较......
因此,这是我在 Python 中定义“isclose”函数的方式:
def isclose(a, b, ndigits):
return round(a-b, ndigits) == 0
我通常使用 5 作为ndigits
;但是,这取决于您期望的精度。
扫码咨询,免费领取项目管理大礼包!