diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2009-07-18 15:18:18 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2009-07-18 15:18:18 (GMT) |
commit | 88a0a2e47fa60c26b3662ef5ee152fd78181c7b1 (patch) | |
tree | b2b75d78afefe544fe4a52c95e01dec512ae5d64 /Lib/fractions.py | |
parent | 3bb474714ba859a008cd51545372eb2dfc63a349 (diff) | |
download | cpython-88a0a2e47fa60c26b3662ef5ee152fd78181c7b1.zip cpython-88a0a2e47fa60c26b3662ef5ee152fd78181c7b1.tar.gz cpython-88a0a2e47fa60c26b3662ef5ee152fd78181c7b1.tar.bz2 |
Issue #6431: Fix Fraction comparisons with unknown types, and with
float infinities and nans. Backport of r74078 from py3k.
Diffstat (limited to 'Lib/fractions.py')
-rwxr-xr-x | Lib/fractions.py | 62 |
1 files changed, 32 insertions, 30 deletions
diff --git a/Lib/fractions.py b/Lib/fractions.py index 15711ed..cc3ec11 100755 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -486,54 +486,56 @@ class Fraction(Rational): if isinstance(b, numbers.Complex) and b.imag == 0: b = b.real if isinstance(b, float): - return a == a.from_float(b) + if math.isnan(b) or math.isinf(b): + # comparisons with an infinity or nan should behave in + # the same way for any finite a, so treat a as zero. + return 0.0 == b + else: + return a == a.from_float(b) else: - # XXX: If b.__eq__ is implemented like this method, it may - # give the wrong answer after float(a) changes a's - # value. Better ways of doing this are welcome. - return float(a) == b + # Since a doesn't know how to compare with b, let's give b + # a chance to compare itself with a. + return NotImplemented - def _subtractAndCompareToZero(a, b, op): - """Helper function for comparison operators. + def _richcmp(self, other, op): + """Helper for comparison operators, for internal use only. - Subtracts b from a, exactly if possible, and compares the - result with 0 using op, in such a way that the comparison - won't recurse. If the difference raises a TypeError, returns - NotImplemented instead. + Implement comparison between a Rational instance `self`, and + either another Rational instance or a float `other`. If + `other` is not a Rational instance or a float, return + NotImplemented. `op` should be one of the six standard + comparison operators. """ - if isinstance(b, numbers.Complex) and b.imag == 0: - b = b.real - if isinstance(b, float): - b = a.from_float(b) - try: - # XXX: If b <: Real but not <: Rational, this is likely - # to fall back to a float. If the actual values differ by - # less than MIN_FLOAT, this could falsely call them equal, - # which would make <= inconsistent with ==. Better ways of - # doing this are welcome. - diff = a - b - except TypeError: + # convert other to a Rational instance where reasonable. + if isinstance(other, Rational): + return op(self._numerator * other.denominator, + self._denominator * other.numerator) + if isinstance(other, numbers.Complex) and other.imag == 0: + other = other.real + if isinstance(other, float): + if math.isnan(other) or math.isinf(other): + return op(0.0, other) + else: + return op(self, self.from_float(other)) + else: return NotImplemented - if isinstance(diff, Rational): - return op(diff.numerator, 0) - return op(diff, 0) def __lt__(a, b): """a < b""" - return a._subtractAndCompareToZero(b, operator.lt) + return a._richcmp(b, operator.lt) def __gt__(a, b): """a > b""" - return a._subtractAndCompareToZero(b, operator.gt) + return a._richcmp(b, operator.gt) def __le__(a, b): """a <= b""" - return a._subtractAndCompareToZero(b, operator.le) + return a._richcmp(b, operator.le) def __ge__(a, b): """a >= b""" - return a._subtractAndCompareToZero(b, operator.ge) + return a._richcmp(b, operator.ge) def __nonzero__(a): """a != 0""" |