1 # Originally contributed by Sjoerd Mullender.
2 # Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.
3
4 """Fraction, infinite-precision, rational numbers."""
5
6 from decimal import Decimal
7 import math
8 import numbers
9 import operator
10 import re
11 import 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
38 class ESC[4;38;5;81mFraction(ESC[4;38;5;149mnumbersESC[4;38;5;149m.ESC[4;38;5;149mRational):
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)