1
1
# Originally contributed by Sjoerd Mullender.
2
2
# Significantly modified by Jeffrey Yasskin <jyasskin at gmail.com>.
3
3
4
- """Fraction, infinite-precision, real numbers."""
4
+ """Fraction, infinite-precision, rational numbers."""
5
5
6
6
from decimal import Decimal
7
7
import math
10
10
import re
11
11
import sys
12
12
13
- __all__ = ['Fraction' , 'gcd' ]
13
+ __all__ = ['Fraction' ]
14
14
15
15
16
-
17
- def gcd (a , b ):
18
- """Calculate the Greatest Common Divisor of a and b.
19
-
20
- Unless b==0, the result will have the same sign as b (so that when
21
- b is divided by it, the result comes out positive).
22
- """
23
- import warnings
24
- warnings .warn ('fractions.gcd() is deprecated. Use math.gcd() instead.' ,
25
- DeprecationWarning , 2 )
26
- if type (a ) is int is type (b ):
27
- if (b or a ) < 0 :
28
- return - math .gcd (a , b )
29
- return math .gcd (a , b )
30
- return _gcd (a , b )
31
-
32
- def _gcd (a , b ):
33
- # Supports non-integers for backward compatibility.
34
- while b :
35
- a , b = b , a % b
36
- return a
37
-
38
16
# Constants related to the hash implementation; hash(x) is based
39
17
# on the reduction of x modulo the prime _PyHASH_MODULUS.
40
18
_PyHASH_MODULUS = sys .hash_info .modulus
@@ -43,17 +21,17 @@ def _gcd(a, b):
43
21
_PyHASH_INF = sys .hash_info .inf
44
22
45
23
_RATIONAL_FORMAT = re .compile (r"""
46
- \A\s* # optional whitespace at the start, then
47
- (?P<sign>[-+]?) # an optional sign, then
48
- (?=\d|\.\d) # lookahead for digit or .digit
49
- (?P<num>\d*) # numerator (possibly empty)
50
- (?: # followed by
51
- (?:/(?P<denom>\d+))? # an optional denominator
52
- | # or
53
- (?:\.(?P<decimal>\d *))? # an optional fractional part
54
- (?:E(?P<exp>[-+]?\d+))? # and optional exponent
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
55
33
)
56
- \s*\Z # and optional whitespace to finish
34
+ \s*\Z # and optional whitespace to finish
57
35
""" , re .VERBOSE | re .IGNORECASE )
58
36
59
37
@@ -144,6 +122,7 @@ def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
144
122
denominator = 1
145
123
decimal = m .group ('decimal' )
146
124
if decimal :
125
+ decimal = decimal .replace ('_' , '' )
147
126
scale = 10 ** len (decimal )
148
127
numerator = numerator * scale + int (decimal )
149
128
denominator *= scale
@@ -177,13 +156,9 @@ def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
177
156
if denominator == 0 :
178
157
raise ZeroDivisionError ('Fraction(%s, 0)' % numerator )
179
158
if _normalize :
180
- if type (numerator ) is int is type (denominator ):
181
- # *very* normal case
182
- g = math .gcd (numerator , denominator )
183
- if denominator < 0 :
184
- g = - g
185
- else :
186
- g = _gcd (numerator , denominator )
159
+ g = math .gcd (numerator , denominator )
160
+ if denominator < 0 :
161
+ g = - g
187
162
numerator //= g
188
163
denominator //= g
189
164
self ._numerator = numerator
@@ -406,32 +381,139 @@ def reverse(b, a):
406
381
407
382
return forward , reverse
408
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
+
409
452
def _add (a , b ):
410
453
"""a + b"""
411
- da , db = a .denominator , b .denominator
412
- return Fraction (a .numerator * db + b .numerator * da ,
413
- da * db )
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 )
414
465
415
466
__add__ , __radd__ = _operator_fallbacks (_add , operator .add )
416
467
417
468
def _sub (a , b ):
418
469
"""a - b"""
419
- da , db = a .denominator , b .denominator
420
- return Fraction (a .numerator * db - b .numerator * da ,
421
- da * db )
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 )
422
481
423
482
__sub__ , __rsub__ = _operator_fallbacks (_sub , operator .sub )
424
483
425
484
def _mul (a , b ):
426
485
"""a * b"""
427
- return Fraction (a .numerator * b .numerator , a .denominator * b .denominator )
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 )
428
497
429
498
__mul__ , __rmul__ = _operator_fallbacks (_mul , operator .mul )
430
499
431
500
def _div (a , b ):
432
501
"""a / b"""
433
- return Fraction (a .numerator * b .denominator ,
434
- a .denominator * b .numerator )
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 )
435
517
436
518
__truediv__ , __rtruediv__ = _operator_fallbacks (_div , operator .truediv )
437
519
@@ -512,8 +594,15 @@ def __abs__(a):
512
594
"""abs(a)"""
513
595
return Fraction (abs (a ._numerator ), a ._denominator , _normalize = False )
514
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
+
515
604
def __trunc__ (a ):
516
- """trunc(a)"""
605
+ """math. trunc(a)"""
517
606
if a ._numerator < 0 :
518
607
return - (- a ._numerator // a ._denominator )
519
608
else :
@@ -556,23 +645,34 @@ def __round__(self, ndigits=None):
556
645
def __hash__ (self ):
557
646
"""hash(self)"""
558
647
559
- # XXX since this method is expensive, consider caching the result
560
-
561
- # In order to make sure that the hash of a Fraction agrees
562
- # with the hash of a numerically equal integer, float or
563
- # Decimal instance, we follow the rules for numeric hashes
564
- # outlined in the documentation. (See library docs, 'Built-in
565
- # Types').
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').
566
652
567
- # dinv is the inverse of self._denominator modulo the prime
568
- # _PyHASH_MODULUS, or 0 if self._denominator is divisible by
569
- # _PyHASH_MODULUS.
570
- dinv = pow (self ._denominator , _PyHASH_MODULUS - 2 , _PyHASH_MODULUS )
571
- if not dinv :
653
+ try :
654
+ dinv = pow (self ._denominator , - 1 , _PyHASH_MODULUS )
655
+ except ValueError :
656
+ # ValueError means there is no modular inverse.
572
657
hash_ = _PyHASH_INF
573
658
else :
574
- hash_ = abs (self ._numerator ) * dinv % _PyHASH_MODULUS
575
- result = hash_ if self >= 0 else - hash_
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_
576
676
return - 2 if result == - 1 else result
577
677
578
678
def __eq__ (a , b ):
@@ -643,7 +743,7 @@ def __bool__(a):
643
743
# support for pickling, copy, and deepcopy
644
744
645
745
def __reduce__ (self ):
646
- return (self .__class__ , (str ( self ), ))
746
+ return (self .__class__ , (self . _numerator , self . _denominator ))
647
747
648
748
def __copy__ (self ):
649
749
if type (self ) == Fraction :
0 commit comments