]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Use Fraction's private attributes in arithmetic methods
authorSergey B Kirpichev <skirpichev@gmail.com>
Sun, 14 Mar 2021 04:43:36 +0000 (07:43 +0300)
committerSergey B Kirpichev <skirpichev@gmail.com>
Sun, 14 Mar 2021 05:27:13 +0000 (08:27 +0300)
That's slightly faster for small components.

Before:
$ ./python -m timeit -r11 -s 'from fractions import Fraction as F' \
-s 'a = F(10, 3)' -s 'b = F(6, 5)' 'a + b'
20000 loops, best of 11: 12.1 usec per loop
$ ./python -m timeit -r11 -s 'from fractions import Fraction as F' \
-s 'a = F(10, 3)' -s 'b = 7' 'a + b'
20000 loops, best of 11: 11.4 usec per loop

After:
$ ./python -m timeit -r11 -s 'from fractions import Fraction as F' \
-s 'a = F(10, 3)' -s 'b = F(6, 5)' 'a + b'
50000 loops, best of 11: 9.74 usec per loop
$ ./python -m timeit -r11 -s 'from fractions import Fraction as F' \
-s 'a = F(10, 3)' -s 'b = 7' 'a + b'
20000 loops, best of 11: 16.5 usec per loop

On the master:
$ ./python -m timeit -r11 -s 'from fractions import Fraction as F' \
-s 'a = F(10, 3)' -s 'b = F(6, 5)' 'a + b'
50000 loops, best of 11: 9.61 usec per loop
$ ./python -m timeit -r11 -s 'from fractions import Fraction as F' \
-s 'a = F(10, 3)' -s 'b = 7' 'a + b'
50000 loops, best of 11: 9.11 usec per loop

Lib/fractions.py

index 9937b960ba84617deca400a3f32da06971ea36e6..0e0673c5e3f2f196465831747cbb4767546c3612 100644 (file)
@@ -355,8 +355,10 @@ class Fraction(numbers.Rational):
 
         """
         def forward(a, b):
-            if isinstance(b, (int, Fraction)):
+            if isinstance(b, Fraction):
                 return monomorphic_operator(a, b)
+            elif isinstance(b, int):
+                return monomorphic_operator(a, Fraction(b))
             elif isinstance(b, float):
                 return fallback_operator(float(a), b)
             elif isinstance(b, complex):
@@ -367,9 +369,10 @@ class Fraction(numbers.Rational):
         forward.__doc__ = monomorphic_operator.__doc__
 
         def reverse(b, a):
-            if isinstance(a, numbers.Rational):
-                # Includes ints.
+            if isinstance(a, Fraction):
                 return monomorphic_operator(a, b)
+            elif isinstance(a, numbers.Integral):
+                return monomorphic_operator(Fraction(a), b)
             elif isinstance(a, numbers.Real):
                 return fallback_operator(float(a), float(b))
             elif isinstance(a, numbers.Complex):
@@ -444,8 +447,8 @@ class Fraction(numbers.Rational):
     # common factors are removed by g1 == gcd(na, db).
 
     def _add_sub_(a, b, pm=int.__add__):
-        na, da = a.numerator, a.denominator
-        nb, db = b.numerator, b.denominator
+        na, da = a._numerator, a._denominator
+        nb, db = b._numerator, b._denominator
         g = math.gcd(da, db)
         if g == 1:
             return Fraction(pm(na * db, da * nb), da * db, _normalize=False)
@@ -465,8 +468,8 @@ class Fraction(numbers.Rational):
 
     def _mul(a, b):
         """a * b"""
-        na, da = a.numerator, a.denominator
-        nb, db = b.numerator, b.denominator
+        na, da = a._numerator, a._denominator
+        nb, db = b._numerator, b._denominator
         g1 = math.gcd(na, db)
         g2 = math.gcd(nb, da)
         return Fraction((na // g1) * (nb // g2),
@@ -477,8 +480,8 @@ class Fraction(numbers.Rational):
     def _div(a, b):
         """a / b"""
         # Same as _mul(), with inversed b.
-        na, da = a.numerator, a.denominator
-        nb, db = b.numerator, b.denominator
+        na, da = a._numerator, a._denominator
+        nb, db = b._numerator, b._denominator
         g1 = math.gcd(na, nb)
         g2 = math.gcd(db, da)
         n, d = (na // g1) * (db // g2), (nb // g1) * (da // g2)