使用缩放容差比较浮点数

Using a Scaled Tolerance to Compare Floats

提问人:mcu 提问时间:10/25/2015 最后编辑:mcu 更新时间:11/1/2023 访问量:394

问:

我突然想到,比较浮子的一个好方法是用浮子缩放公差。这是个好主意吗?

此例程需要针对特殊数量(例如 NaN、+/-Inf)进行扩展,但它给出了一个基本概念。

def FloatEq(a, b, ToleranceFactor=1e-6):
    if a == b: return True
    c = min(abs(a), abs(b))
    return(abs(a-b) < (c*ToleranceFactor))

a = 0.000000000001
b = 0.000000000001000000001

print('Straight compare ==', a==b)
print('FloatEq(,,1e-6) ==', FloatEq(a,b))
print('FloatEq(,,1e-10) ==', FloatEq(a,b,1e-10))

输出:

Straight compare == False
FloatEq(,,1e-6) == True
FloatEq(,,1e-10) == False

更新:

一种可能的解决方案,可以处理其中一个操作数为零。它使用固定的、用户可配置的公差,而不是一个因子。

def FloatEq(a, b, ToleranceFactor=1e-6, ToleranceAtZero=None):
    if a == b:
        return True
    elif a==0 or b==0:
        c = a if b==0 else b
        if ToleranceAtZero is None:
            import sys
            # Ignoring denormalized numbers for now
            ToleranceAtZero = sys.float_info.min
        return abs(c) < ToleranceAtZero
    else:
        c = min(abs(a), abs(b))
        return(abs(a-b) < (c*ToleranceFactor))
python 比较 浮点精度

评论

1赞 5gon12eder 10/25/2015
这取决于您的用例,但我见过更糟糕的尝试来比较浮点值。请注意,您的逻辑有些复杂。如果你应用差异并使用,你可以摆脱所有的/东西。另请注意,你的决赛是假的。还要考虑一个值正好为零的情况。在这种情况下,您希望使用什么容差?ifelseabsmin(abs(a), abs(b))return
0赞 mcu 10/25/2015
我清理了它。我想将公差因子应用于绝对值较小的浮点数。如果一个值为零,则结果为 ,这在这里似乎很合适。False
0赞 labheshr 10/25/2015
为什么不直接拥有: isEqual = lambda(t,a,b) : abs(a) - abs(b) < t ..然后将其用作 isEqual(1e-6,a,b)
1赞 mcu 10/25/2015
@JTurk 使用公差的固定值。它不与浮点数一起缩放。
1赞 mcu 10/25/2015
@JTurk 这样说也许可以,但不能。1000.0+0.0001 == 1000.00.00000001+0.0001 == 0.00000001

答:

0赞 Peter Cordes 10/25/2015 #1

这是一个明智的想法,除非您正在比较可能是灾难性取消结果的值(例如,减去两个附近的数字以产生一个非常小、非常不准确的数字)。在这种情况下,我认为您应该根据预取消值的大小来缩放容差。

我不是数值计算/浮点专家。把这些东西做好是很困难的,而且有一个完整的堆栈交换:计算 Science.SE

一些搜索出现了:https://scicomp.stackexchange.com/questions/3362/relative-comparison-of-floating-point-numbers 有几个关于FP比较的答案。