From 046c84e8f970306b668d62cfacbd58f65b8c6e66 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sun, 14 Mar 2021 07:43:36 +0300 Subject: [PATCH] Use Fraction's private attributes in arithmetic methods 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 | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 9937b960ba84..0e0673c5e3f2 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -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) -- 2.47.3