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