Thursday, May 8, 2008

More on Python Rationals

Coercing to floats internal to some other operation is inherently bad. And so Jared replaces ...

def __gt__(self, arg):
if not isinstance(arg, type(self)):
arg = self.__class__(arg)
return float(self) > float(arg)

... and friends with ...

def __gt__(self, arg):
if not isinstance(arg, type(self)):
return self.numerator > self.denominator * arg
return self.numerator * arg.denominator > arg.numerator * self.denominator

... or even ...

def __eq__(self, arg):
return self.numerator == self.denominator * arg

... which is especially nice.

Will sign trickiness ever give a wrong result? A couple dozen random cases work here and so I've put revised and reposted the implementation.

Of course what Jared's really interested in is whether the class can — or, in fact, already does — work as rational field. I'm just happy he caught that the fact that we can ditch the __cmp__ override because the presence of __gt__, __eq__, __lt__ and friends.

One question that remains is what to do with int. The current implementation goes towards zero and not towards negative infinity. So int(Rational(-6, 5)) gives -1 and not -2.

def __int__(self):
result = abs(self.numerator) // abs(self.denominator)
if self >= 0:
return result
else:
return -result

But is this right? Perhaps Google will break a tie ...

No comments: