views:

164

answers:

3

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 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 http://stackoverflow.com/questions/3860009/custom-comparison-for-built-in-containers

+2  A: 

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.

MdaG
Arguments don't seem right. http://docs.python.org/reference/datamodel.html#object.__eq__
livibetter
Make sure to also define __ne__ as well so you don't have both a==b and a!=b true. And be aware that with __eq__ redefined as above you can have both a==b and a<b true, but if that doesn't make sense you can define __gt__ and __ge__ as well.
Bill Gribble
livibetter. Sorry I fetched the info from http://docs.python.org/library/operator.html
MdaG
Which class is "in your class" referring to? The OP has float objects.
Roger Pate
I'm making assumptions here since he wants to overload an operator and as far as I know you can only overload operators for user defined classes. If I'm wrong I can delete my answer.
MdaG
+1 for preventing the ZeroDivisionError.
poke
@poke: Whose answer did he get that idea from?
John Machin
It's not rocket science John. I've handled zero divisions before.
MdaG
+10  A: 

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 * (self.real + 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

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

AndiDog
+1: I think this is the best idea - creating a new class instead of overriding builtin operators for builtin classes. But you should still handle the `ZeroDivisionError` if both numbers are or add up to zero.
Tim Pietzcker
@Tim Pietzcker: Right, I forgot about that case. Changed to code accordingly.
AndiDog
@AndiDog: At what stage does he switch from using float to using this class? Does he need to wrap `InexactFloat()` around every float? Suppose he doesn't do that but does all his calculations in floats and gets two values a and b ... does he need to do `InexactFloat(a) == InexactFloat(b)` or can he get away with `InexactFloat(a) == b`? If the latter, why does he need a class at all?
John Machin
@John Machin: If you put `print other` into the `__eq__` method, you'll see that if at least one side of the comparison is a `InexactFloat` instance, then the custom comparison method is used. So `InexactFloat(a) == b` is enough. He needs the class because overwriting the builtin `float.__eq__` is 1) not possible and 2) could lead to unexpected behavior in other libraries or parts of the program. That's why a custom class is better. If only few inexact comparisons are necessary, one could as well use a function `compareInexact(a, b)` as suggested in another answer.
AndiDog
@Andidog: If the number of inexact comparisons is of any relevance, the function (as suggested in other answers, including mine) should be preferred for a **large** number of inexact comparisons, as it is more efficient.
John Machin
@John Machin: With "few inexact comparisons" I actually meant "few occurrences in the code". The function solution is explicit and needs more typing whereas the `__eq__` overloading is implicit and only has to be written once. Concerning performance, your solution is surely better.
AndiDog
@Andidog: If the OP is going to use your class in a just-in-time manner, he needs to type `Classname(a) == b` for each comparison occurrence in the code, which is two keystrokes more than `func_name(a, b)` if one adheres to PEP8, else one more. Otherwise for every code occurrence of saving a float value that may be compared later, the OP needs to locate that occurrence, and insert `classname(whatever)` -- do you recommend that? Would you be happy maintaining such code??
John Machin
+1 for helping me see how subclass solution would work.
max
Do I really need to define `__ne__` here? Wouldn't `__ne__` be defined as `not __eq__` anyway in any builtin class?
max
@John Machin: No, I wouldn't like to maintain something like that. The class-based solution does only make sense if such numbers must be created in very few places in the code, and if you like implicit inexact comparisons. Nobody would do this in a project like 3D game programming. I didn't say my approach was any better, in most cases it's not. It's just that I wondered whether it could be done with a subclass, so I tried it out and posted it here. Everyone's free to decide which solution to take, depending on the problem.
AndiDog
@max: If you don't override `__ne__`, it will be called in the superclass. That will be `float_richcompare` in "floatobject.c" of the Python source code, thus comparing the floating-point numbers for exact inequality. Comment out my `__ne__` implementation and then check the results of `InexactFloat(5.2) == InexactFloat(5.20000000000001)` and `InexactFloat(5.2) != InexactFloat(5.20000000000001)`. Both are `True`.
AndiDog
@Andidog: Yes, you didn't say it was any better. The point is that nor did you say that it was any worse, until pummelled, probed and prodded.
John Machin
Ahh so the float in Python optimizes both `__ne__` and '__eq__` so that neither of them calls the other. I guess it makes sense that I cannot simply rely on my simplistic view that one should be implemented through the other. Thanks!
max
+3  A: 

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 ==

John Machin
One of the reasons for my question is that I often compare dictionaries, which have values of different types including float. The standard Python == operator is perfectly fine, except for the float (which need to be compared approximately). Obviously, there's easy ways to do that with some extra code, but I was hoping overriding == in float would be the cleanest, most elegant solution.
max
I accept this answer because dealing with custom float subclass is terribly inconvenient in Python for reasons shown in comments to that solution. Other than the subclass, this is the first correct solution.
max
If you could override float ==, to avoid utter disaster you would need to override the other 5 relational operators in a consistent fashion. The override would be effective for all the library code, which would not be expecting it. E.g. sorting a list of floats might not give the same answer. All hell may break loose. The effort of working through a proof that it won't cause a catastrophe would be a large undertaking.
John Machin
+1 - best way to deal with division by zero.
max