Python中的近似比较
我想在我的程序中让'=='运算符进行近似比较:如果浮点值x和y相等(==),那么它们的比较方式是
abs(x-y)/(0.5(x+y)) < 0.001
有没有什么好的方法来实现这个?因为浮点数是内置类型,我觉得我不能重新定义==运算符,对吧?
需要注意的是,我希望能继续使用浮点数的其他特性,我唯一想改变的就是相等运算符。
编辑:
谢谢大家的回答,我理解你们关于可读性和其他问题的看法。
不过,我真的希望,如果可能的话,能继续使用普通的浮点类型,而不是创建一个新类或新的比较函数。对于普通浮点数,重新定义==运算符真的有可能吗?
我的理由是:
(a) 使用我写的程序的每个人都希望浮点数以这种方式进行比较
(b) 世界上没有人会想用浮点数的默认==运算符……这到底为什么会出现在语言里??
(c) 我不喜欢代码中出现多余的字;显然,使用现有的浮点数在代码中根本不会有任何变化
编辑2。
现在我知道我不能为浮点数重载==运算符了,我得改变我的问题。这个问题会变得非常不同,所以我会在内置容器的自定义比较上另开一个新问题。
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)
这样可以避免出现除以零的情况。
你可以创建一个新的类,这个类是从内置的浮点数类型(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
你可能还想重写一些其他的操作符,比如<=等。
你的定义有两个问题:
缺少一个
*
如果
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:你写道:
世界上没有人会想用浮点数的默认
==
... 它为什么会出现在语言里???
真的没有人吗?假设你有一个函数返回一个浮点数,然后你突然想到一个算法,能更快或更优雅地得到相同的结果;那你怎么测试它呢?