changeset: 90152:91d7fadac271 user: Mark Dickinson date: Sat Apr 05 09:29:00 2014 +0100 files: Lib/fractions.py Lib/test/test_fractions.py Misc/NEWS description: Issue #21136: Avoid unnecessary normalization in Fractions resulting from power and other operations. diff -r 087cdbf49e80 -r 91d7fadac271 Lib/fractions.py --- a/Lib/fractions.py Fri Apr 04 21:05:46 2014 +0200 +++ b/Lib/fractions.py Sat Apr 05 09:29:00 2014 +0100 @@ -70,7 +70,7 @@ __slots__ = ('_numerator', '_denominator') # We're immutable, so use __new__ not __init__ - def __new__(cls, numerator=0, denominator=None): + def __new__(cls, numerator=0, denominator=None, _normalize=True): """Constructs a Rational. Takes a string like '3/2' or '1.5', another Rational instance, a @@ -165,9 +165,12 @@ if denominator == 0: raise ZeroDivisionError('Fraction(%s, 0)' % numerator) - g = gcd(numerator, denominator) - self._numerator = numerator // g - self._denominator = denominator // g + if _normalize: + g = gcd(numerator, denominator) + numerator //= g + denominator //= g + self._numerator = numerator + self._denominator = denominator return self @classmethod @@ -453,10 +456,12 @@ power = b.numerator if power >= 0: return Fraction(a._numerator ** power, - a._denominator ** power) + a._denominator ** power, + _normalize=False) else: return Fraction(a._denominator ** -power, - a._numerator ** -power) + a._numerator ** -power, + _normalize=False) else: # A fractional power will generally produce an # irrational number. @@ -480,15 +485,15 @@ def __pos__(a): """+a: Coerces a subclass instance to Fraction""" - return Fraction(a._numerator, a._denominator) + return Fraction(a._numerator, a._denominator, _normalize=False) def __neg__(a): """-a""" - return Fraction(-a._numerator, a._denominator) + return Fraction(-a._numerator, a._denominator, _normalize=False) def __abs__(a): """abs(a)""" - return Fraction(abs(a._numerator), a._denominator) + return Fraction(abs(a._numerator), a._denominator, _normalize=False) def __trunc__(a): """trunc(a)""" diff -r 087cdbf49e80 -r 91d7fadac271 Lib/test/test_fractions.py --- a/Lib/test/test_fractions.py Fri Apr 04 21:05:46 2014 +0200 +++ b/Lib/test/test_fractions.py Sat Apr 05 09:29:00 2014 +0100 @@ -330,7 +330,6 @@ self.assertTypedEquals(F(-2, 10), round(F(-15, 100), 1)) self.assertTypedEquals(F(-2, 10), round(F(-25, 100), 1)) - def testArithmetic(self): self.assertEqual(F(1, 2), F(1, 10) + F(2, 5)) self.assertEqual(F(-3, 10), F(1, 10) - F(2, 5)) @@ -402,6 +401,8 @@ self.assertTypedEquals(2.0 , 4 ** F(1, 2)) self.assertTypedEquals(0.25, 2.0 ** F(-2, 1)) self.assertTypedEquals(1.0 + 0j, (1.0 + 0j) ** F(1, 10)) + self.assertRaises(ZeroDivisionError, operator.pow, + F(0, 1), -2) def testMixingWithDecimal(self): # Decimal refuses mixed arithmetic (but not mixed comparisons) diff -r 087cdbf49e80 -r 91d7fadac271 Misc/NEWS --- a/Misc/NEWS Fri Apr 04 21:05:46 2014 +0200 +++ b/Misc/NEWS Sat Apr 05 09:29:00 2014 +0100 @@ -29,6 +29,9 @@ Library ------- +- Issue #21136: Avoid unnecessary normalization of Fractions resulting from + power and other operations. Patch by Raymond Hettinger. + - Issue #17621: Introduce importlib.util.LazyLoader. - Issue #21076: signal module constants were turned into enums.