Python中的近似比较

4 投票
3 回答
11790 浏览
提问于 2025-04-16 04:57

我想在我的程序中让'=='运算符进行近似比较:如果浮点值x和y相等(==),那么它们的比较方式是

abs(x-y)/(0.5(x+y)) < 0.001

有没有什么好的方法来实现这个?因为浮点数是内置类型,我觉得我不能重新定义==运算符,对吧?

需要注意的是,我希望能继续使用浮点数的其他特性,我唯一想改变的就是相等运算符。

编辑:

谢谢大家的回答,我理解你们关于可读性和其他问题的看法。

不过,我真的希望,如果可能的话,能继续使用普通的浮点类型,而不是创建一个新类或新的比较函数。对于普通浮点数,重新定义==运算符真的有可能吗?

我的理由是:

(a) 使用我写的程序的每个人都希望浮点数以这种方式进行比较

(b) 世界上没有人会想用浮点数的默认==运算符……这到底为什么会出现在语言里??

(c) 我不喜欢代码中出现多余的字;显然,使用现有的浮点数在代码中根本不会有任何变化

编辑2。

现在我知道我不能为浮点数重载==运算符了,我得改变我的问题。这个问题会变得非常不同,所以我会在内置容器的自定义比较上另开一个新问题。

3 个回答

3

如果你把数字放在一个类里面,你可以重写“==”这个比较符号,方法是:

def __eq__(self, x):
   return abs(x - self.x) / (0.5 * (x + self.x)) < 0.001

不过你应该把表达式改成

abs(x - self.x) < 0.0005 * (x + self.x)

这样可以避免出现除以零的情况。

18

你可以创建一个新的类,这个类是从内置的浮点数类型(float)派生出来的,然后重写一些必要的操作符。

class InexactFloat(float):
    def __eq__(self, other):
        try:
            return abs(self.real - other) / (0.5 * (abs(self.real) + abs(other))) < 0.001
        except ZeroDivisionError:
            # Could do another inexact comparison here, this is just an example:
            return self.real == other

    def __ne__(self, other):
        return not self.__eq__(other)

print 5.2 == 5.20000000000001 # False
print 5.2 != 5.20000000000001 # True
print InexactFloat(5.2) == InexactFloat(5.20000000000001) # True
print InexactFloat(5.2) != InexactFloat(5.20000000000001) # False
print InexactFloat(-5) == -5 # True

# Works for InexactFloat <-> float comparison
print 5.0 == InexactFloat(5.0) # True
print InexactFloat(5.0) == 5.0 # True

# Zero division case (note how I implemented it above!)
print InexactFloat(-0.00001) == InexactFloat(0.00001) # False
print InexactFloat(-0.000000001) == InexactFloat(0.000000001) # False
print InexactFloat(-5) == InexactFloat(5) # False

# Unit test for fixed negative numbers problem
print InexactFloat(-5) == InexactFloat(-10) # False

你可能还想重写一些其他的操作符,比如<=等。

8

你的定义有两个问题:

  1. 缺少一个 *

  2. 如果 x + y == 0.0,会尝试进行除以零的操作(这可能是一个常见的情况 x == y == 0.0

试试这个:

define approx_Equal(x, y, tolerance=0.001):
    return abs(x-y) <= 0.5 * tolerance * (x + y)

补充说明:注意使用 <= 而不是 < ... 这样做是为了让 x == y == 0.0 的情况能正常工作。

我不建议你去重写 == 的功能。

补充说明 2:你写道:

世界上没有人会想用浮点数的默认 ==... 它为什么会出现在语言里???

真的没有人吗?假设你有一个函数返回一个浮点数,然后你突然想到一个算法,能更快或更优雅地得到相同的结果;那你怎么测试它呢?

撰写回答