From 9cc62f7c849f4e0d60efb71f8eec6bd4933ec1d7 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Fri, 10 Feb 2023 09:51:07 +0300 Subject: [PATCH 01/11] gh-101773: Optimize creation of Fraction's in private methods --- Lib/fractions.py | 70 +++++++++++-------- Lib/test/test_fractions.py | 1 + Lib/test/test_numeric_tower.py | 2 +- ...-02-10-11-59-13.gh-issue-101773.J_kI7y.rst | 1 + 4 files changed, 42 insertions(+), 32 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst diff --git a/Lib/fractions.py b/Lib/fractions.py index 49a3f2841a2ed4..174b1e0215619e 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -183,7 +183,7 @@ class Fraction(numbers.Rational): __slots__ = ('_numerator', '_denominator') # We're immutable, so use __new__ not __init__ - def __new__(cls, numerator=0, denominator=None, *, _normalize=True): + def __new__(cls, numerator=0, denominator=None): """Constructs a Rational. Takes a string like '3/2' or '1.5', another Rational instance, a @@ -279,12 +279,11 @@ def __new__(cls, numerator=0, denominator=None, *, _normalize=True): if denominator == 0: raise ZeroDivisionError('Fraction(%s, 0)' % numerator) - if _normalize: - g = math.gcd(numerator, denominator) - if denominator < 0: - g = -g - numerator //= g - denominator //= g + g = math.gcd(numerator, denominator) + if denominator < 0: + g = -g + numerator //= g + denominator //= g self._numerator = numerator self._denominator = denominator return self @@ -315,6 +314,13 @@ def from_decimal(cls, dec): (cls.__name__, dec, type(dec).__name__)) return cls(*dec.as_integer_ratio()) + @classmethod + def _from_pair(cls, num, den): + obj = super(Fraction, cls).__new__(cls) + obj._numerator = num + obj._denominator = den + return obj + def is_integer(self): """Return True if the Fraction is an integer.""" return self._denominator == 1 @@ -380,9 +386,9 @@ def limit_denominator(self, max_denominator=1000000): # the distance from p1/q1 to self is d/(q1*self._denominator). So we # need to compare 2*(q0+k*q1) with self._denominator/d. if 2*d*(q0+k*q1) <= self._denominator: - return Fraction(p1, q1, _normalize=False) + return Fraction._from_pair(p1, q1) else: - return Fraction(p0+k*p1, q0+k*q1, _normalize=False) + return Fraction._from_pair(p0+k*p1, q0+k*q1) @property def numerator(a): @@ -703,13 +709,13 @@ def _add(a, b): nb, db = b._numerator, b._denominator g = math.gcd(da, db) if g == 1: - return Fraction(na * db + da * nb, da * db, _normalize=False) + return Fraction._from_pair(na * db + da * nb, da * db) s = da // g t = na * (db // g) + nb * s g2 = math.gcd(t, g) if g2 == 1: - return Fraction(t, s * db, _normalize=False) - return Fraction(t // g2, s * (db // g2), _normalize=False) + return Fraction._from_pair(t, s * db) + return Fraction._from_pair(t // g2, s * (db // g2)) __add__, __radd__ = _operator_fallbacks(_add, operator.add) @@ -719,13 +725,13 @@ def _sub(a, b): nb, db = b._numerator, b._denominator g = math.gcd(da, db) if g == 1: - return Fraction(na * db - da * nb, da * db, _normalize=False) + return Fraction._from_pair(na * db - da * nb, da * db) s = da // g t = na * (db // g) - nb * s g2 = math.gcd(t, g) if g2 == 1: - return Fraction(t, s * db, _normalize=False) - return Fraction(t // g2, s * (db // g2), _normalize=False) + return Fraction._from_pair(t, s * db) + return Fraction._from_pair(t // g2, s * (db // g2)) __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub) @@ -741,15 +747,17 @@ def _mul(a, b): if g2 > 1: nb //= g2 da //= g2 - return Fraction(na * nb, db * da, _normalize=False) + return Fraction._from_pair(na * nb, db * da) __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul) def _div(a, b): """a / b""" # Same as _mul(), with inversed b. - na, da = a._numerator, a._denominator nb, db = b._numerator, b._denominator + if nb == 0: + raise ZeroDivisionError('Fraction(%s, 0)' % db) + na, da = a._numerator, a._denominator g1 = math.gcd(na, nb) if g1 > 1: na //= g1 @@ -761,7 +769,7 @@ def _div(a, b): n, d = na * db, nb * da if d < 0: n, d = -n, -d - return Fraction(n, d, _normalize=False) + return Fraction._from_pair(n, d) __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv) @@ -798,17 +806,17 @@ def __pow__(a, b): if b.denominator == 1: power = b.numerator if power >= 0: - return Fraction(a._numerator ** power, - a._denominator ** power, - _normalize=False) - elif a._numerator >= 0: - return Fraction(a._denominator ** -power, - a._numerator ** -power, - _normalize=False) + return Fraction._from_pair(a._numerator ** power, + a._denominator ** power) + elif a._numerator > 0: + return Fraction._from_pair(a._denominator ** -power, + a._numerator ** -power) + elif a._numerator == 0: + raise ZeroDivisionError('Fraction(%s, 0)' % + a._denominator ** -power) else: - return Fraction((-a._denominator) ** -power, - (-a._numerator) ** -power, - _normalize=False) + return Fraction._from_pair((-a._denominator) ** -power, + (-a._numerator) ** -power) else: # A fractional power will generally produce an # irrational number. @@ -832,15 +840,15 @@ def __rpow__(b, a): def __pos__(a): """+a: Coerces a subclass instance to Fraction""" - return Fraction(a._numerator, a._denominator, _normalize=False) + return Fraction._from_pair(a._numerator, a._denominator) def __neg__(a): """-a""" - return Fraction(-a._numerator, a._denominator, _normalize=False) + return Fraction._from_pair(-a._numerator, a._denominator) def __abs__(a): """abs(a)""" - return Fraction(abs(a._numerator), a._denominator, _normalize=False) + return Fraction._from_pair(abs(a._numerator), a._denominator) def __int__(a, _index=operator.index): """int(a)""" diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py index 3bc6b409e05dc3..e112f49d2e7944 100644 --- a/Lib/test/test_fractions.py +++ b/Lib/test/test_fractions.py @@ -488,6 +488,7 @@ def testArithmetic(self): self.assertEqual(F(5, 6), F(2, 3) * F(5, 4)) self.assertEqual(F(1, 4), F(1, 10) / F(2, 5)) self.assertEqual(F(-15, 8), F(3, 4) / F(-2, 5)) + self.assertRaises(ZeroDivisionError, operator.truediv, F(1), F(0)) self.assertTypedEquals(2, F(9, 10) // F(2, 5)) self.assertTypedEquals(10**23, F(10**23, 1) // F(1)) self.assertEqual(F(5, 6), F(7, 3) % F(3, 2)) diff --git a/Lib/test/test_numeric_tower.py b/Lib/test/test_numeric_tower.py index 9cd85e13634c2b..af9b3ab7f47d66 100644 --- a/Lib/test/test_numeric_tower.py +++ b/Lib/test/test_numeric_tower.py @@ -145,7 +145,7 @@ def test_fractions(self): # The numbers ABC doesn't enforce that the "true" division # of integers produces a float. This tests that the # Rational.__float__() method has required type conversions. - x = F(DummyIntegral(1), DummyIntegral(2), _normalize=False) + x = F._from_pair(DummyIntegral(1), DummyIntegral(2)) self.assertRaises(TypeError, lambda: x.numerator/x.denominator) self.assertEqual(float(x), 0.5) diff --git a/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst b/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst new file mode 100644 index 00000000000000..1741b4a10ba24b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst @@ -0,0 +1 @@ +Optimize :class:`fractions.Fraction` for small components. From 3625d34155b4d6d8665c665a85ccd701af47d336 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 11 Feb 2023 14:04:55 +0300 Subject: [PATCH 02/11] Adjust signature of _from_pair() and add docstring --- Lib/fractions.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 174b1e0215619e..6afeb2cc16edc1 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -315,10 +315,15 @@ def from_decimal(cls, dec): return cls(*dec.as_integer_ratio()) @classmethod - def _from_pair(cls, num, den): + def _from_pair(cls, numerator, denominator, /): + """Convert a pair of int's to a rational number. + + The ratio of integers should be in lowest terms and + the denominator is positive. + """ obj = super(Fraction, cls).__new__(cls) - obj._numerator = num - obj._denominator = den + obj._numerator = numerator + obj._denominator = denominator return obj def is_integer(self): From 9e66b5a1c11ba432518acc23b17a7cf447870989 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 11 Feb 2023 14:09:08 +0300 Subject: [PATCH 03/11] Use new helper in from_float/Decimal --- Lib/fractions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 6afeb2cc16edc1..ffbd16f601304d 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -300,7 +300,7 @@ def from_float(cls, f): elif not isinstance(f, float): raise TypeError("%s.from_float() only takes floats, not %r (%s)" % (cls.__name__, f, type(f).__name__)) - return cls(*f.as_integer_ratio()) + return cls._from_pair(*f.as_integer_ratio()) @classmethod def from_decimal(cls, dec): @@ -312,7 +312,7 @@ def from_decimal(cls, dec): raise TypeError( "%s.from_decimal() only takes Decimals, not %r (%s)" % (cls.__name__, dec, type(dec).__name__)) - return cls(*dec.as_integer_ratio()) + return cls._from_pair(*dec.as_integer_ratio()) @classmethod def _from_pair(cls, numerator, denominator, /): From 43243910dc37b3dbdcf2bfe776eb0689028565be Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 11 Feb 2023 15:06:17 +0300 Subject: [PATCH 04/11] Restore back _normalize kwarg for the Fraction.__new__() --- Lib/fractions.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index ffbd16f601304d..6a0f8a038b71ca 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -183,7 +183,7 @@ class Fraction(numbers.Rational): __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 @@ -279,11 +279,12 @@ def __new__(cls, numerator=0, denominator=None): if denominator == 0: raise ZeroDivisionError('Fraction(%s, 0)' % numerator) - g = math.gcd(numerator, denominator) - if denominator < 0: - g = -g - numerator //= g - denominator //= g + if _normalize: + g = math.gcd(numerator, denominator) + if denominator < 0: + g = -g + numerator //= g + denominator //= g self._numerator = numerator self._denominator = denominator return self From b0dca38aa3e0af061127bac6a1225cb05eaadfa4 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Sat, 11 Feb 2023 15:23:42 +0300 Subject: [PATCH 05/11] Amend 3625d34155 --- Lib/fractions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 6a0f8a038b71ca..48429a8e838634 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -317,7 +317,7 @@ def from_decimal(cls, dec): @classmethod def _from_pair(cls, numerator, denominator, /): - """Convert a pair of int's to a rational number. + """Convert a pair of int's to a rational number, for internal use. The ratio of integers should be in lowest terms and the denominator is positive. From 3a8506dc2b5962600fbe140956b03c495910e41c Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 27 Feb 2023 06:14:20 +0300 Subject: [PATCH 06/11] Nitpick on docstring (int's -> ints) --- Lib/fractions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 48429a8e838634..4a99087f0099cb 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -317,7 +317,7 @@ def from_decimal(cls, dec): @classmethod def _from_pair(cls, numerator, denominator, /): - """Convert a pair of int's to a rational number, for internal use. + """Convert a pair of ints to a rational number, for internal use. The ratio of integers should be in lowest terms and the denominator is positive. From 13262af7b792160a5ffec326c7be140afe1dbb40 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 27 Feb 2023 06:18:21 +0300 Subject: [PATCH 07/11] Revert "Restore back _normalize kwarg for the Fraction.__new__()" This reverts commit 43243910dc37b3dbdcf2bfe776eb0689028565be. --- Lib/fractions.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 4a99087f0099cb..3d332194521227 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -183,7 +183,7 @@ class Fraction(numbers.Rational): __slots__ = ('_numerator', '_denominator') # We're immutable, so use __new__ not __init__ - def __new__(cls, numerator=0, denominator=None, *, _normalize=True): + def __new__(cls, numerator=0, denominator=None): """Constructs a Rational. Takes a string like '3/2' or '1.5', another Rational instance, a @@ -279,12 +279,11 @@ def __new__(cls, numerator=0, denominator=None, *, _normalize=True): if denominator == 0: raise ZeroDivisionError('Fraction(%s, 0)' % numerator) - if _normalize: - g = math.gcd(numerator, denominator) - if denominator < 0: - g = -g - numerator //= g - denominator //= g + g = math.gcd(numerator, denominator) + if denominator < 0: + g = -g + numerator //= g + denominator //= g self._numerator = numerator self._denominator = denominator return self From 4e8977af55780ef517d8600719caaf6c2e0d23d9 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 27 Feb 2023 06:21:15 +0300 Subject: [PATCH 08/11] Rename: _from_pair -> _from_coprime_ints --- Lib/fractions.py | 44 +++++++++++++++++----------------- Lib/test/test_numeric_tower.py | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 3d332194521227..08fe99962c84d0 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -300,7 +300,7 @@ def from_float(cls, f): elif not isinstance(f, float): raise TypeError("%s.from_float() only takes floats, not %r (%s)" % (cls.__name__, f, type(f).__name__)) - return cls._from_pair(*f.as_integer_ratio()) + return cls._from_coprime_ints(*f.as_integer_ratio()) @classmethod def from_decimal(cls, dec): @@ -312,10 +312,10 @@ def from_decimal(cls, dec): raise TypeError( "%s.from_decimal() only takes Decimals, not %r (%s)" % (cls.__name__, dec, type(dec).__name__)) - return cls._from_pair(*dec.as_integer_ratio()) + return cls._from_coprime_ints(*dec.as_integer_ratio()) @classmethod - def _from_pair(cls, numerator, denominator, /): + def _from_coprime_ints(cls, numerator, denominator, /): """Convert a pair of ints to a rational number, for internal use. The ratio of integers should be in lowest terms and @@ -391,9 +391,9 @@ def limit_denominator(self, max_denominator=1000000): # the distance from p1/q1 to self is d/(q1*self._denominator). So we # need to compare 2*(q0+k*q1) with self._denominator/d. if 2*d*(q0+k*q1) <= self._denominator: - return Fraction._from_pair(p1, q1) + return Fraction._from_coprime_ints(p1, q1) else: - return Fraction._from_pair(p0+k*p1, q0+k*q1) + return Fraction._from_coprime_ints(p0+k*p1, q0+k*q1) @property def numerator(a): @@ -714,13 +714,13 @@ def _add(a, b): nb, db = b._numerator, b._denominator g = math.gcd(da, db) if g == 1: - return Fraction._from_pair(na * db + da * nb, da * db) + return Fraction._from_coprime_ints(na * db + da * nb, da * db) s = da // g t = na * (db // g) + nb * s g2 = math.gcd(t, g) if g2 == 1: - return Fraction._from_pair(t, s * db) - return Fraction._from_pair(t // g2, s * (db // g2)) + return Fraction._from_coprime_ints(t, s * db) + return Fraction._from_coprime_ints(t // g2, s * (db // g2)) __add__, __radd__ = _operator_fallbacks(_add, operator.add) @@ -730,13 +730,13 @@ def _sub(a, b): nb, db = b._numerator, b._denominator g = math.gcd(da, db) if g == 1: - return Fraction._from_pair(na * db - da * nb, da * db) + return Fraction._from_coprime_ints(na * db - da * nb, da * db) s = da // g t = na * (db // g) - nb * s g2 = math.gcd(t, g) if g2 == 1: - return Fraction._from_pair(t, s * db) - return Fraction._from_pair(t // g2, s * (db // g2)) + return Fraction._from_coprime_ints(t, s * db) + return Fraction._from_coprime_ints(t // g2, s * (db // g2)) __sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub) @@ -752,7 +752,7 @@ def _mul(a, b): if g2 > 1: nb //= g2 da //= g2 - return Fraction._from_pair(na * nb, db * da) + return Fraction._from_coprime_ints(na * nb, db * da) __mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul) @@ -774,7 +774,7 @@ def _div(a, b): n, d = na * db, nb * da if d < 0: n, d = -n, -d - return Fraction._from_pair(n, d) + return Fraction._from_coprime_ints(n, d) __truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv) @@ -811,17 +811,17 @@ def __pow__(a, b): if b.denominator == 1: power = b.numerator if power >= 0: - return Fraction._from_pair(a._numerator ** power, - a._denominator ** power) + return Fraction._from_coprime_ints(a._numerator ** power, + a._denominator ** power) elif a._numerator > 0: - return Fraction._from_pair(a._denominator ** -power, - a._numerator ** -power) + return Fraction._from_coprime_ints(a._denominator ** -power, + a._numerator ** -power) elif a._numerator == 0: raise ZeroDivisionError('Fraction(%s, 0)' % a._denominator ** -power) else: - return Fraction._from_pair((-a._denominator) ** -power, - (-a._numerator) ** -power) + return Fraction._from_coprime_ints((-a._denominator) ** -power, + (-a._numerator) ** -power) else: # A fractional power will generally produce an # irrational number. @@ -845,15 +845,15 @@ def __rpow__(b, a): def __pos__(a): """+a: Coerces a subclass instance to Fraction""" - return Fraction._from_pair(a._numerator, a._denominator) + return Fraction._from_coprime_ints(a._numerator, a._denominator) def __neg__(a): """-a""" - return Fraction._from_pair(-a._numerator, a._denominator) + return Fraction._from_coprime_ints(-a._numerator, a._denominator) def __abs__(a): """abs(a)""" - return Fraction._from_pair(abs(a._numerator), a._denominator) + return Fraction._from_coprime_ints(abs(a._numerator), a._denominator) def __int__(a, _index=operator.index): """int(a)""" diff --git a/Lib/test/test_numeric_tower.py b/Lib/test/test_numeric_tower.py index af9b3ab7f47d66..337682d6bac96c 100644 --- a/Lib/test/test_numeric_tower.py +++ b/Lib/test/test_numeric_tower.py @@ -145,7 +145,7 @@ def test_fractions(self): # The numbers ABC doesn't enforce that the "true" division # of integers produces a float. This tests that the # Rational.__float__() method has required type conversions. - x = F._from_pair(DummyIntegral(1), DummyIntegral(2)) + x = F._from_coprime_ints(DummyIntegral(1), DummyIntegral(2)) self.assertRaises(TypeError, lambda: x.numerator/x.denominator) self.assertEqual(float(x), 0.5) From 4b4a386bbd8f69bc08d26433315eacbcd7094f52 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 27 Feb 2023 12:24:26 +0300 Subject: [PATCH 09/11] Update Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst Co-authored-by: Pieter Eendebak --- .../next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst b/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst index 1741b4a10ba24b..31341c0e47c538 100644 --- a/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst +++ b/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst @@ -1 +1 @@ -Optimize :class:`fractions.Fraction` for small components. +Optimize :class:`fractions.Fraction` for small components. The private argument `_normalize` of the `Fraction` constructor has been removed. From 580b1be3bb5126ec729badbaf6fc662e45f4fff2 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 27 Feb 2023 12:34:18 +0300 Subject: [PATCH 10/11] +1 --- .../Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst b/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst index 31341c0e47c538..b577d93d28c2ae 100644 --- a/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst +++ b/Misc/NEWS.d/next/Library/2023-02-10-11-59-13.gh-issue-101773.J_kI7y.rst @@ -1 +1,2 @@ -Optimize :class:`fractions.Fraction` for small components. The private argument `_normalize` of the `Fraction` constructor has been removed. +Optimize :class:`fractions.Fraction` for small components. The private argument +``_normalize`` of the :class:`fractions.Fraction` constructor has been removed. From 53d5e9407f0588bc2e12f3b919e66a49985be9b9 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Mon, 27 Feb 2023 18:20:06 +0000 Subject: [PATCH 11/11] Tweak docstring wording --- Lib/fractions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/fractions.py b/Lib/fractions.py index 08fe99962c84d0..f718b35639beee 100644 --- a/Lib/fractions.py +++ b/Lib/fractions.py @@ -318,8 +318,8 @@ def from_decimal(cls, dec): def _from_coprime_ints(cls, numerator, denominator, /): """Convert a pair of ints to a rational number, for internal use. - The ratio of integers should be in lowest terms and - the denominator is positive. + The ratio of integers should be in lowest terms and the denominator + should be positive. """ obj = super(Fraction, cls).__new__(cls) obj._numerator = numerator pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy