Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3c286e2

Browse files
committed
Issue #21136: Avoid unnecessary normalization in Fractions resulting from power and other operations.
1 parent 2a32200 commit 3c286e2

3 files changed

Lines changed: 19 additions & 10 deletions

File tree

Lib/fractions.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class Fraction(numbers.Rational):
7070
__slots__ = ('_numerator', '_denominator')
7171

7272
# We're immutable, so use __new__ not __init__
73-
def __new__(cls, numerator=0, denominator=None):
73+
def __new__(cls, numerator=0, denominator=None, _normalize=True):
7474
"""Constructs a Rational.
7575
7676
Takes a string like '3/2' or '1.5', another Rational instance, a
@@ -165,9 +165,12 @@ def __new__(cls, numerator=0, denominator=None):
165165

166166
if denominator == 0:
167167
raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
168-
g = gcd(numerator, denominator)
169-
self._numerator = numerator // g
170-
self._denominator = denominator // g
168+
if _normalize:
169+
g = gcd(numerator, denominator)
170+
numerator //= g
171+
denominator //= g
172+
self._numerator = numerator
173+
self._denominator = denominator
171174
return self
172175

173176
@classmethod
@@ -453,10 +456,12 @@ def __pow__(a, b):
453456
power = b.numerator
454457
if power >= 0:
455458
return Fraction(a._numerator ** power,
456-
a._denominator ** power)
459+
a._denominator ** power,
460+
_normalize=False)
457461
else:
458462
return Fraction(a._denominator ** -power,
459-
a._numerator ** -power)
463+
a._numerator ** -power,
464+
_normalize=False)
460465
else:
461466
# A fractional power will generally produce an
462467
# irrational number.
@@ -480,15 +485,15 @@ def __rpow__(b, a):
480485

481486
def __pos__(a):
482487
"""+a: Coerces a subclass instance to Fraction"""
483-
return Fraction(a._numerator, a._denominator)
488+
return Fraction(a._numerator, a._denominator, _normalize=False)
484489

485490
def __neg__(a):
486491
"""-a"""
487-
return Fraction(-a._numerator, a._denominator)
492+
return Fraction(-a._numerator, a._denominator, _normalize=False)
488493

489494
def __abs__(a):
490495
"""abs(a)"""
491-
return Fraction(abs(a._numerator), a._denominator)
496+
return Fraction(abs(a._numerator), a._denominator, _normalize=False)
492497

493498
def __trunc__(a):
494499
"""trunc(a)"""

Lib/test/test_fractions.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,6 @@ def testRound(self):
330330
self.assertTypedEquals(F(-2, 10), round(F(-15, 100), 1))
331331
self.assertTypedEquals(F(-2, 10), round(F(-25, 100), 1))
332332

333-
334333
def testArithmetic(self):
335334
self.assertEqual(F(1, 2), F(1, 10) + F(2, 5))
336335
self.assertEqual(F(-3, 10), F(1, 10) - F(2, 5))
@@ -402,6 +401,8 @@ def testMixedArithmetic(self):
402401
self.assertTypedEquals(2.0 , 4 ** F(1, 2))
403402
self.assertTypedEquals(0.25, 2.0 ** F(-2, 1))
404403
self.assertTypedEquals(1.0 + 0j, (1.0 + 0j) ** F(1, 10))
404+
self.assertRaises(ZeroDivisionError, operator.pow,
405+
F(0, 1), -2)
405406

406407
def testMixingWithDecimal(self):
407408
# Decimal refuses mixed arithmetic (but not mixed comparisons)

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ Core and Builtins
2929
Library
3030
-------
3131

32+
- Issue #21136: Avoid unnecessary normalization of Fractions resulting from
33+
power and other operations. Patch by Raymond Hettinger.
34+
3235
- Issue #17621: Introduce importlib.util.LazyLoader.
3336

3437
- Issue #21076: signal module constants were turned into enums.

0 commit comments

Comments
 (0)