xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/fractions.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1# Originally contributed by Sjoerd Mullender.
2# Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.
3
4"""Fraction, infinite-precision, rational numbers."""
5
6from decimal import Decimal
7import math
8import numbers
9import operator
10import re
11import sys
12
13__all__ = ['Fraction']
14
15
16# Constants related to the hash implementation;  hash(x) is based
17# on the reduction of x modulo the prime _PyHASH_MODULUS.
18_PyHASH_MODULUS = sys.hash_info.modulus
19# Value to be used for rationals that reduce to infinity modulo
20# _PyHASH_MODULUS.
21_PyHASH_INF = sys.hash_info.inf
22
23_RATIONAL_FORMAT = re.compile(r"""
24    \A\s*                                 # optional whitespace at the start,
25    (?P<sign>[-+]?)                       # an optional sign, then
26    (?=\d|\.\d)                           # lookahead for digit or .digit
27    (?P<num>\d*|\d+(_\d+)*)               # numerator (possibly empty)
28    (?:                                   # followed by
29       (?:/(?P<denom>\d+(_\d+)*))?        # an optional denominator
30    |                                     # or
31       (?:\.(?P<decimal>d*|\d+(_\d+)*))?  # an optional fractional part
32       (?:E(?P<exp>[-+]?\d+(_\d+)*))?     # and optional exponent
33    )
34    \s*\Z                                 # and optional whitespace to finish
35""", re.VERBOSE | re.IGNORECASE)
36
37
38class Fraction(numbers.Rational):
39    """This class implements rational numbers.
40
41    In the two-argument form of the constructor, Fraction(8, 6) will
42    produce a rational number equivalent to 4/3. Both arguments must
43    be Rational. The numerator defaults to 0 and the denominator
44    defaults to 1 so that Fraction(3) == 3 and Fraction() == 0.
45
46    Fractions can also be constructed from:
47
48      - numeric strings similar to those accepted by the
49        float constructor (for example, '-2.3' or '1e10')
50
51      - strings of the form '123/456'
52
53      - float and Decimal instances
54
55      - other Rational instances (including integers)
56
57    """
58
59    __slots__ = ('_numerator', '_denominator')
60
61    # We're immutable, so use __new__ not __init__
62    def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
63        """Constructs a Rational.
64
65        Takes a string like '3/2' or '1.5', another Rational instance, a
66        numerator/denominator pair, or a float.
67
68        Examples
69        --------
70
71        >>> Fraction(10, -8)
72        Fraction(-5, 4)
73        >>> Fraction(Fraction(1, 7), 5)
74        Fraction(1, 35)
75        >>> Fraction(Fraction(1, 7), Fraction(2, 3))
76        Fraction(3, 14)
77        >>> Fraction('314')
78        Fraction(314, 1)
79        >>> Fraction('-35/4')
80        Fraction(-35, 4)
81        >>> Fraction('3.1415') # conversion from numeric string
82        Fraction(6283, 2000)
83        >>> Fraction('-47e-2') # string may include a decimal exponent
84        Fraction(-47, 100)
85        >>> Fraction(1.47)  # direct construction from float (exact conversion)
86        Fraction(6620291452234629, 4503599627370496)
87        >>> Fraction(2.25)
88        Fraction(9, 4)
89        >>> Fraction(Decimal('1.47'))
90        Fraction(147, 100)
91
92        """
93        self = super(Fraction, cls).__new__(cls)
94
95        if denominator is None:
96            if type(numerator) is int:
97                self._numerator = numerator
98                self._denominator = 1
99                return self
100
101            elif isinstance(numerator, numbers.Rational):
102                self._numerator = numerator.numerator
103                self._denominator = numerator.denominator
104                return self
105
106            elif isinstance(numerator, (float, Decimal)):
107                # Exact conversion
108                self._numerator, self._denominator = numerator.as_integer_ratio()
109                return self
110
111            elif isinstance(numerator, str):
112                # Handle construction from strings.
113                m = _RATIONAL_FORMAT.match(numerator)
114                if m is None:
115                    raise ValueError('Invalid literal for Fraction: %r' %
116                                     numerator)
117                numerator = int(m.group('num') or '0')
118                denom = m.group('denom')
119                if denom:
120                    denominator = int(denom)
121                else:
122                    denominator = 1
123                    decimal = m.group('decimal')
124                    if decimal:
125                        decimal = decimal.replace('_', '')
126                        scale = 10**len(decimal)
127                        numerator = numerator * scale + int(decimal)
128                        denominator *= scale
129                    exp = m.group('exp')
130                    if exp:
131                        exp = int(exp)
132                        if exp >= 0:
133                            numerator *= 10**exp
134                        else:
135                            denominator *= 10**-exp
136                if m.group('sign') == '-':
137                    numerator = -numerator
138
139            else:
140                raise TypeError("argument should be a string "
141                                "or a Rational instance")
142
143        elif type(numerator) is int is type(denominator):
144            pass # *very* normal case
145
146        elif (isinstance(numerator, numbers.Rational) and
147            isinstance(denominator, numbers.Rational)):
148            numerator, denominator = (
149                numerator.numerator * denominator.denominator,
150                denominator.numerator * numerator.denominator
151                )
152        else:
153            raise TypeError("both arguments should be "
154                            "Rational instances")
155
156        if denominator == 0:
157            raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
158        if _normalize:
159            g = math.gcd(numerator, denominator)
160            if denominator < 0:
161                g = -g
162            numerator //= g
163            denominator //= g
164        self._numerator = numerator
165        self._denominator = denominator
166        return self
167
168    @classmethod
169    def from_float(cls, f):
170        """Converts a finite float to a rational number, exactly.
171
172        Beware that Fraction.from_float(0.3) != Fraction(3, 10).
173
174        """
175        if isinstance(f, numbers.Integral):
176            return cls(f)
177        elif not isinstance(f, float):
178            raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
179                            (cls.__name__, f, type(f).__name__))
180        return cls(*f.as_integer_ratio())
181
182    @classmethod
183    def from_decimal(cls, dec):
184        """Converts a finite Decimal instance to a rational number, exactly."""
185        from decimal import Decimal
186        if isinstance(dec, numbers.Integral):
187            dec = Decimal(int(dec))
188        elif not isinstance(dec, Decimal):
189            raise TypeError(
190                "%s.from_decimal() only takes Decimals, not %r (%s)" %
191                (cls.__name__, dec, type(dec).__name__))
192        return cls(*dec.as_integer_ratio())
193
194    def as_integer_ratio(self):
195        """Return the integer ratio as a tuple.
196
197        Return a tuple of two integers, whose ratio is equal to the
198        Fraction and with a positive denominator.
199        """
200        return (self._numerator, self._denominator)
201
202    def limit_denominator(self, max_denominator=1000000):
203        """Closest Fraction to self with denominator at most max_denominator.
204
205        >>> Fraction('3.141592653589793').limit_denominator(10)
206        Fraction(22, 7)
207        >>> Fraction('3.141592653589793').limit_denominator(100)
208        Fraction(311, 99)
209        >>> Fraction(4321, 8765).limit_denominator(10000)
210        Fraction(4321, 8765)
211
212        """
213        # Algorithm notes: For any real number x, define a *best upper
214        # approximation* to x to be a rational number p/q such that:
215        #
216        #   (1) p/q >= x, and
217        #   (2) if p/q > r/s >= x then s > q, for any rational r/s.
218        #
219        # Define *best lower approximation* similarly.  Then it can be
220        # proved that a rational number is a best upper or lower
221        # approximation to x if, and only if, it is a convergent or
222        # semiconvergent of the (unique shortest) continued fraction
223        # associated to x.
224        #
225        # To find a best rational approximation with denominator <= M,
226        # we find the best upper and lower approximations with
227        # denominator <= M and take whichever of these is closer to x.
228        # In the event of a tie, the bound with smaller denominator is
229        # chosen.  If both denominators are equal (which can happen
230        # only when max_denominator == 1 and self is midway between
231        # two integers) the lower bound---i.e., the floor of self, is
232        # taken.
233
234        if max_denominator < 1:
235            raise ValueError("max_denominator should be at least 1")
236        if self._denominator <= max_denominator:
237            return Fraction(self)
238
239        p0, q0, p1, q1 = 0, 1, 1, 0
240        n, d = self._numerator, self._denominator
241        while True:
242            a = n//d
243            q2 = q0+a*q1
244            if q2 > max_denominator:
245                break
246            p0, q0, p1, q1 = p1, q1, p0+a*p1, q2
247            n, d = d, n-a*d
248
249        k = (max_denominator-q0)//q1
250        bound1 = Fraction(p0+k*p1, q0+k*q1)
251        bound2 = Fraction(p1, q1)
252        if abs(bound2 - self) <= abs(bound1-self):
253            return bound2
254        else:
255            return bound1
256
257    @property
258    def numerator(a):
259        return a._numerator
260
261    @property
262    def denominator(a):
263        return a._denominator
264
265    def __repr__(self):
266        """repr(self)"""
267        return '%s(%s, %s)' % (self.__class__.__name__,
268                               self._numerator, self._denominator)
269
270    def __str__(self):
271        """str(self)"""
272        if self._denominator == 1:
273            return str(self._numerator)
274        else:
275            return '%s/%s' % (self._numerator, self._denominator)
276
277    def _operator_fallbacks(monomorphic_operator, fallback_operator):
278        """Generates forward and reverse operators given a purely-rational
279        operator and a function from the operator module.
280
281        Use this like:
282        __op__, __rop__ = _operator_fallbacks(just_rational_op, operator.op)
283
284        In general, we want to implement the arithmetic operations so
285        that mixed-mode operations either call an implementation whose
286        author knew about the types of both arguments, or convert both
287        to the nearest built in type and do the operation there. In
288        Fraction, that means that we define __add__ and __radd__ as:
289
290            def __add__(self, other):
291                # Both types have numerators/denominator attributes,
292                # so do the operation directly
293                if isinstance(other, (int, Fraction)):
294                    return Fraction(self.numerator * other.denominator +
295                                    other.numerator * self.denominator,
296                                    self.denominator * other.denominator)
297                # float and complex don't have those operations, but we
298                # know about those types, so special case them.
299                elif isinstance(other, float):
300                    return float(self) + other
301                elif isinstance(other, complex):
302                    return complex(self) + other
303                # Let the other type take over.
304                return NotImplemented
305
306            def __radd__(self, other):
307                # radd handles more types than add because there's
308                # nothing left to fall back to.
309                if isinstance(other, numbers.Rational):
310                    return Fraction(self.numerator * other.denominator +
311                                    other.numerator * self.denominator,
312                                    self.denominator * other.denominator)
313                elif isinstance(other, Real):
314                    return float(other) + float(self)
315                elif isinstance(other, Complex):
316                    return complex(other) + complex(self)
317                return NotImplemented
318
319
320        There are 5 different cases for a mixed-type addition on
321        Fraction. I'll refer to all of the above code that doesn't
322        refer to Fraction, float, or complex as "boilerplate". 'r'
323        will be an instance of Fraction, which is a subtype of
324        Rational (r : Fraction <: Rational), and b : B <:
325        Complex. The first three involve 'r + b':
326
327            1. If B <: Fraction, int, float, or complex, we handle
328               that specially, and all is well.
329            2. If Fraction falls back to the boilerplate code, and it
330               were to return a value from __add__, we'd miss the
331               possibility that B defines a more intelligent __radd__,
332               so the boilerplate should return NotImplemented from
333               __add__. In particular, we don't handle Rational
334               here, even though we could get an exact answer, in case
335               the other type wants to do something special.
336            3. If B <: Fraction, Python tries B.__radd__ before
337               Fraction.__add__. This is ok, because it was
338               implemented with knowledge of Fraction, so it can
339               handle those instances before delegating to Real or
340               Complex.
341
342        The next two situations describe 'b + r'. We assume that b
343        didn't know about Fraction in its implementation, and that it
344        uses similar boilerplate code:
345
346            4. If B <: Rational, then __radd_ converts both to the
347               builtin rational type (hey look, that's us) and
348               proceeds.
349            5. Otherwise, __radd__ tries to find the nearest common
350               base ABC, and fall back to its builtin type. Since this
351               class doesn't subclass a concrete type, there's no
352               implementation to fall back to, so we need to try as
353               hard as possible to return an actual value, or the user
354               will get a TypeError.
355
356        """
357        def forward(a, b):
358            if isinstance(b, (int, Fraction)):
359                return monomorphic_operator(a, b)
360            elif isinstance(b, float):
361                return fallback_operator(float(a), b)
362            elif isinstance(b, complex):
363                return fallback_operator(complex(a), b)
364            else:
365                return NotImplemented
366        forward.__name__ = '__' + fallback_operator.__name__ + '__'
367        forward.__doc__ = monomorphic_operator.__doc__
368
369        def reverse(b, a):
370            if isinstance(a, numbers.Rational):
371                # Includes ints.
372                return monomorphic_operator(a, b)
373            elif isinstance(a, numbers.Real):
374                return fallback_operator(float(a), float(b))
375            elif isinstance(a, numbers.Complex):
376                return fallback_operator(complex(a), complex(b))
377            else:
378                return NotImplemented
379        reverse.__name__ = '__r' + fallback_operator.__name__ + '__'
380        reverse.__doc__ = monomorphic_operator.__doc__
381
382        return forward, reverse
383
384    # Rational arithmetic algorithms: Knuth, TAOCP, Volume 2, 4.5.1.
385    #
386    # Assume input fractions a and b are normalized.
387    #
388    # 1) Consider addition/subtraction.
389    #
390    # Let g = gcd(da, db). Then
391    #
392    #              na   nb    na*db ± nb*da
393    #     a ± b == -- ± -- == ------------- ==
394    #              da   db        da*db
395    #
396    #              na*(db//g) ± nb*(da//g)    t
397    #           == ----------------------- == -
398    #                      (da*db)//g         d
399    #
400    # Now, if g > 1, we're working with smaller integers.
401    #
402    # Note, that t, (da//g) and (db//g) are pairwise coprime.
403    #
404    # Indeed, (da//g) and (db//g) share no common factors (they were
405    # removed) and da is coprime with na (since input fractions are
406    # normalized), hence (da//g) and na are coprime.  By symmetry,
407    # (db//g) and nb are coprime too.  Then,
408    #
409    #     gcd(t, da//g) == gcd(na*(db//g), da//g) == 1
410    #     gcd(t, db//g) == gcd(nb*(da//g), db//g) == 1
411    #
412    # Above allows us optimize reduction of the result to lowest
413    # terms.  Indeed,
414    #
415    #     g2 = gcd(t, d) == gcd(t, (da//g)*(db//g)*g) == gcd(t, g)
416    #
417    #                       t//g2                   t//g2
418    #     a ± b == ----------------------- == ----------------
419    #              (da//g)*(db//g)*(g//g2)    (da//g)*(db//g2)
420    #
421    # is a normalized fraction.  This is useful because the unnormalized
422    # denominator d could be much larger than g.
423    #
424    # We should special-case g == 1 (and g2 == 1), since 60.8% of
425    # randomly-chosen integers are coprime:
426    # https://en.wikipedia.org/wiki/Coprime_integers#Probability_of_coprimality
427    # Note, that g2 == 1 always for fractions, obtained from floats: here
428    # g is a power of 2 and the unnormalized numerator t is an odd integer.
429    #
430    # 2) Consider multiplication
431    #
432    # Let g1 = gcd(na, db) and g2 = gcd(nb, da), then
433    #
434    #            na*nb    na*nb    (na//g1)*(nb//g2)
435    #     a*b == ----- == ----- == -----------------
436    #            da*db    db*da    (db//g1)*(da//g2)
437    #
438    # Note, that after divisions we're multiplying smaller integers.
439    #
440    # Also, the resulting fraction is normalized, because each of
441    # two factors in the numerator is coprime to each of the two factors
442    # in the denominator.
443    #
444    # Indeed, pick (na//g1).  It's coprime with (da//g2), because input
445    # fractions are normalized.  It's also coprime with (db//g1), because
446    # common factors are removed by g1 == gcd(na, db).
447    #
448    # As for addition/subtraction, we should special-case g1 == 1
449    # and g2 == 1 for same reason.  That happens also for multiplying
450    # rationals, obtained from floats.
451
452    def _add(a, b):
453        """a + b"""
454        na, da = a.numerator, a.denominator
455        nb, db = b.numerator, b.denominator
456        g = math.gcd(da, db)
457        if g == 1:
458            return Fraction(na * db + da * nb, da * db, _normalize=False)
459        s = da // g
460        t = na * (db // g) + nb * s
461        g2 = math.gcd(t, g)
462        if g2 == 1:
463            return Fraction(t, s * db, _normalize=False)
464        return Fraction(t // g2, s * (db // g2), _normalize=False)
465
466    __add__, __radd__ = _operator_fallbacks(_add, operator.add)
467
468    def _sub(a, b):
469        """a - b"""
470        na, da = a.numerator, a.denominator
471        nb, db = b.numerator, b.denominator
472        g = math.gcd(da, db)
473        if g == 1:
474            return Fraction(na * db - da * nb, da * db, _normalize=False)
475        s = da // g
476        t = na * (db // g) - nb * s
477        g2 = math.gcd(t, g)
478        if g2 == 1:
479            return Fraction(t, s * db, _normalize=False)
480        return Fraction(t // g2, s * (db // g2), _normalize=False)
481
482    __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
483
484    def _mul(a, b):
485        """a * b"""
486        na, da = a.numerator, a.denominator
487        nb, db = b.numerator, b.denominator
488        g1 = math.gcd(na, db)
489        if g1 > 1:
490            na //= g1
491            db //= g1
492        g2 = math.gcd(nb, da)
493        if g2 > 1:
494            nb //= g2
495            da //= g2
496        return Fraction(na * nb, db * da, _normalize=False)
497
498    __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
499
500    def _div(a, b):
501        """a / b"""
502        # Same as _mul(), with inversed b.
503        na, da = a.numerator, a.denominator
504        nb, db = b.numerator, b.denominator
505        g1 = math.gcd(na, nb)
506        if g1 > 1:
507            na //= g1
508            nb //= g1
509        g2 = math.gcd(db, da)
510        if g2 > 1:
511            da //= g2
512            db //= g2
513        n, d = na * db, nb * da
514        if d < 0:
515            n, d = -n, -d
516        return Fraction(n, d, _normalize=False)
517
518    __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
519
520    def _floordiv(a, b):
521        """a // b"""
522        return (a.numerator * b.denominator) // (a.denominator * b.numerator)
523
524    __floordiv__, __rfloordiv__ = _operator_fallbacks(_floordiv, operator.floordiv)
525
526    def _divmod(a, b):
527        """(a // b, a % b)"""
528        da, db = a.denominator, b.denominator
529        div, n_mod = divmod(a.numerator * db, da * b.numerator)
530        return div, Fraction(n_mod, da * db)
531
532    __divmod__, __rdivmod__ = _operator_fallbacks(_divmod, divmod)
533
534    def _mod(a, b):
535        """a % b"""
536        da, db = a.denominator, b.denominator
537        return Fraction((a.numerator * db) % (b.numerator * da), da * db)
538
539    __mod__, __rmod__ = _operator_fallbacks(_mod, operator.mod)
540
541    def __pow__(a, b):
542        """a ** b
543
544        If b is not an integer, the result will be a float or complex
545        since roots are generally irrational. If b is an integer, the
546        result will be rational.
547
548        """
549        if isinstance(b, numbers.Rational):
550            if b.denominator == 1:
551                power = b.numerator
552                if power >= 0:
553                    return Fraction(a._numerator ** power,
554                                    a._denominator ** power,
555                                    _normalize=False)
556                elif a._numerator >= 0:
557                    return Fraction(a._denominator ** -power,
558                                    a._numerator ** -power,
559                                    _normalize=False)
560                else:
561                    return Fraction((-a._denominator) ** -power,
562                                    (-a._numerator) ** -power,
563                                    _normalize=False)
564            else:
565                # A fractional power will generally produce an
566                # irrational number.
567                return float(a) ** float(b)
568        else:
569            return float(a) ** b
570
571    def __rpow__(b, a):
572        """a ** b"""
573        if b._denominator == 1 and b._numerator >= 0:
574            # If a is an int, keep it that way if possible.
575            return a ** b._numerator
576
577        if isinstance(a, numbers.Rational):
578            return Fraction(a.numerator, a.denominator) ** b
579
580        if b._denominator == 1:
581            return a ** b._numerator
582
583        return a ** float(b)
584
585    def __pos__(a):
586        """+a: Coerces a subclass instance to Fraction"""
587        return Fraction(a._numerator, a._denominator, _normalize=False)
588
589    def __neg__(a):
590        """-a"""
591        return Fraction(-a._numerator, a._denominator, _normalize=False)
592
593    def __abs__(a):
594        """abs(a)"""
595        return Fraction(abs(a._numerator), a._denominator, _normalize=False)
596
597    def __int__(a, _index=operator.index):
598        """int(a)"""
599        if a._numerator < 0:
600            return _index(-(-a._numerator // a._denominator))
601        else:
602            return _index(a._numerator // a._denominator)
603
604    def __trunc__(a):
605        """math.trunc(a)"""
606        if a._numerator < 0:
607            return -(-a._numerator // a._denominator)
608        else:
609            return a._numerator // a._denominator
610
611    def __floor__(a):
612        """math.floor(a)"""
613        return a.numerator // a.denominator
614
615    def __ceil__(a):
616        """math.ceil(a)"""
617        # The negations cleverly convince floordiv to return the ceiling.
618        return -(-a.numerator // a.denominator)
619
620    def __round__(self, ndigits=None):
621        """round(self, ndigits)
622
623        Rounds half toward even.
624        """
625        if ndigits is None:
626            floor, remainder = divmod(self.numerator, self.denominator)
627            if remainder * 2 < self.denominator:
628                return floor
629            elif remainder * 2 > self.denominator:
630                return floor + 1
631            # Deal with the half case:
632            elif floor % 2 == 0:
633                return floor
634            else:
635                return floor + 1
636        shift = 10**abs(ndigits)
637        # See _operator_fallbacks.forward to check that the results of
638        # these operations will always be Fraction and therefore have
639        # round().
640        if ndigits > 0:
641            return Fraction(round(self * shift), shift)
642        else:
643            return Fraction(round(self / shift) * shift)
644
645    def __hash__(self):
646        """hash(self)"""
647
648        # To make sure that the hash of a Fraction agrees with the hash
649        # of a numerically equal integer, float or Decimal instance, we
650        # follow the rules for numeric hashes outlined in the
651        # documentation.  (See library docs, 'Built-in Types').
652
653        try:
654            dinv = pow(self._denominator, -1, _PyHASH_MODULUS)
655        except ValueError:
656            # ValueError means there is no modular inverse.
657            hash_ = _PyHASH_INF
658        else:
659            # The general algorithm now specifies that the absolute value of
660            # the hash is
661            #    (|N| * dinv) % P
662            # where N is self._numerator and P is _PyHASH_MODULUS.  That's
663            # optimized here in two ways:  first, for a non-negative int i,
664            # hash(i) == i % P, but the int hash implementation doesn't need
665            # to divide, and is faster than doing % P explicitly.  So we do
666            #    hash(|N| * dinv)
667            # instead.  Second, N is unbounded, so its product with dinv may
668            # be arbitrarily expensive to compute.  The final answer is the
669            # same if we use the bounded |N| % P instead, which can again
670            # be done with an int hash() call.  If 0 <= i < P, hash(i) == i,
671            # so this nested hash() call wastes a bit of time making a
672            # redundant copy when |N| < P, but can save an arbitrarily large
673            # amount of computation for large |N|.
674            hash_ = hash(hash(abs(self._numerator)) * dinv)
675        result = hash_ if self._numerator >= 0 else -hash_
676        return -2 if result == -1 else result
677
678    def __eq__(a, b):
679        """a == b"""
680        if type(b) is int:
681            return a._numerator == b and a._denominator == 1
682        if isinstance(b, numbers.Rational):
683            return (a._numerator == b.numerator and
684                    a._denominator == b.denominator)
685        if isinstance(b, numbers.Complex) and b.imag == 0:
686            b = b.real
687        if isinstance(b, float):
688            if math.isnan(b) or math.isinf(b):
689                # comparisons with an infinity or nan should behave in
690                # the same way for any finite a, so treat a as zero.
691                return 0.0 == b
692            else:
693                return a == a.from_float(b)
694        else:
695            # Since a doesn't know how to compare with b, let's give b
696            # a chance to compare itself with a.
697            return NotImplemented
698
699    def _richcmp(self, other, op):
700        """Helper for comparison operators, for internal use only.
701
702        Implement comparison between a Rational instance `self`, and
703        either another Rational instance or a float `other`.  If
704        `other` is not a Rational instance or a float, return
705        NotImplemented. `op` should be one of the six standard
706        comparison operators.
707
708        """
709        # convert other to a Rational instance where reasonable.
710        if isinstance(other, numbers.Rational):
711            return op(self._numerator * other.denominator,
712                      self._denominator * other.numerator)
713        if isinstance(other, float):
714            if math.isnan(other) or math.isinf(other):
715                return op(0.0, other)
716            else:
717                return op(self, self.from_float(other))
718        else:
719            return NotImplemented
720
721    def __lt__(a, b):
722        """a < b"""
723        return a._richcmp(b, operator.lt)
724
725    def __gt__(a, b):
726        """a > b"""
727        return a._richcmp(b, operator.gt)
728
729    def __le__(a, b):
730        """a <= b"""
731        return a._richcmp(b, operator.le)
732
733    def __ge__(a, b):
734        """a >= b"""
735        return a._richcmp(b, operator.ge)
736
737    def __bool__(a):
738        """a != 0"""
739        # bpo-39274: Use bool() because (a._numerator != 0) can return an
740        # object which is not a bool.
741        return bool(a._numerator)
742
743    # support for pickling, copy, and deepcopy
744
745    def __reduce__(self):
746        return (self.__class__, (self._numerator, self._denominator))
747
748    def __copy__(self):
749        if type(self) == Fraction:
750            return self     # I'm immutable; therefore I am my own clone
751        return self.__class__(self._numerator, self._denominator)
752
753    def __deepcopy__(self, memo):
754        if type(self) == Fraction:
755            return self     # My components are also immutable
756        return self.__class__(self._numerator, self._denominator)
757