开发者

approximate comparison in python

I want to make '==' operator use approximate comparison in my program: float values x and y are equal (==) if

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

What's a good way to do that? Given that float is a built-in type, I don't think I can redefine the == operator, can I?

Note that I would like to use other features of float, the only thing that I'd like to change is the equality operator.

EDIT:

Thank you for the answers, and I understand your arguments about readability and other issues.

That said, I really would prefer, if possible, to actually开发者_如何学C keep using the regular float type, instead of having a new class or a new comparison function. Is it even possible to redefine == operator for regular floats?

My reasons are::

(a) everyone using the program I'm writing wants the floats to be compared this way

(b) there's no way in the world anyone would ever want to use the default == for floats.. Why is it even in the language???

(c) I dislike extra words in the code; obviously using the existing float results in no changes in the code whatsoever

EDIT 2.

Now that I know I can't overload the == operator for float, I have to change my question. It will become so different that I'll make a new one at custom comparison for built-in containers


You can create a new class deriving from the builtin float type, and then overwrite the necessary operators:

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

You may also want to overwrite operators like <= etc.


Your definition has two problems:

  1. Missing an *

  2. Will attempt to divide by zero if x + y == 0.0 (which covers a possibly frequent case x == y == 0.0)

Try this instead:

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

Edit: Note the use of <= instead of < ... needed to make the x == y == 0.0 case work properly.

I wouldn't try to override ==

Edit 2: You wrote:

there's no way in the world anyone would ever want to use the default == for floats.. Why is it even in the language???

No way? Suppose you have a function that returns a float, and you have a brainwave about an algorithm that would produce the same answers faster and/or more elegantly; how do you test it?


If you wrap the numbers in a class you can overload "==" with:

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

however you should rewrite the expression to

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

to avoid zero division.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜