8000 Merge branch 'main' into fetch-restore-objects · python/cpython@eb45902 · GitHub
[go: up one dir, main page]

Skip to content

Commit eb45902

Browse files
authored
Merge branch 'main' into fetch-restore-objects
2 parents e11d73e + 4624987 commit eb45902

10 files changed

+71
-61
lines changed

Doc/library/fractions.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ another rational number, or from a string.
118118
.. method:: as_integer_ratio()
119119

120120
Return a tuple of two integers, whose ratio is equal
121-
to the Fraction and with a positive denominator.
121+
to the original Fraction. The ratio is in lowest terms
122+
and has a positive denominator.
122123

123124
.. versionadded:: 3.8
124125

Doc/library/stdtypes.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,8 @@ class`. In addition, it provides a few more methods:
602602

603603
.. method:: int.as_integer_ratio()
604604

605-
Return a pair of integers whose ratio is exactly equal to the original
606-
integer and with a positive denominator. The integer ratio of integers
605+
Return a pair of integers whose ratio is equal to the original
606+
integer and has a positive denominator. The integer ratio of integers
607607
(whole numbers) is always the integer as the numerator and ``1`` as the
608608
denominator.
609609

@@ -624,7 +624,7 @@ class`. float also has the following additional methods.
624624
.. method:: float.as_integer_ratio()
625625

626626
Return a pair of integers whose ratio is exactly equal to the
627-
original float and with a positive denominator. Raises
627+
original float. The ratio is in lowest terms and has a positive denominator. Raises
628628
:exc:`OverflowError` on infinities and a :exc:`ValueError` on
629629
NaNs.
630630

Lib/fractions.py

Lines changed: 48 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ class Fraction(numbers.Rational):
183183
__slots__ = ('_numerator', '_denominator')
184184

185185
# We're immutable, so use __new__ not __init__
186-
def __new__(cls, numerator=0, denominator=None, *, _normalize=True):
186+
def __new__(cls, numerator=0, denominator=None):
187187
"""Constructs a Rational.
188188
189189
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):
279279

280280
if denominator == 0:
281281
raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
282-
if _normalize:
283-
g = math.gcd(numerator, denominator)
284-
if denominator < 0:
285-
g = -g
286-
numerator //= g
287-
denominator //= g
282+
g = math.gcd(numerator, denominator)
283+
if denominator < 0:
284+
g = -g
285+
numerator //= g
286+
denominator //= g
288287
self._numerator = numerator
289288
self._denominator = denominator
290289
return self
@@ -301,7 +300,7 @@ def from_float(cls, f):
301300
elif not isinstance(f, float):
302301
raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
303302
(cls.__name__, f, type(f).__name__))
304-
return cls(*f.as_integer_ratio())
303+
return cls._from_coprime_ints(*f.as_integer_ratio())
305304

306305
@classmethod
307306
def from_decimal(cls, dec):
@@ -313,17 +312,28 @@ def from_decimal(cls, dec):
313312
raise TypeError(
314313
"%s.from_decimal() only takes Decimals, not %r (%s)" %
315314
(cls.__name__, dec, type(dec).__name__))
316-
return cls(*dec.as_integer_ratio())
315+
return cls._from_coprime_ints(*dec.as_integer_ratio())
316+
317+
@classmethod
318+
def _from_coprime_ints(cls, numerator, denominator, /):
319+
"""Convert a pair of ints to a rational number, for internal use.
320+
321+
The ratio of integers should be in lowest terms and the denominator
322+
should be positive.
323+
"""
324+
obj = super(Fraction, cls).__new__(cls)
325+
obj._numerator = numerator
326+
obj._denominator = denominator
327+
return obj
317328

318329
def is_integer(self):
319330
"""Return True if the Fraction is an integer."""
320331
return self._denominator == 1
321332

322333
def as_integer_ratio(self):
323-
"""Return the integer ratio as a tuple.
334+
"""Return a pair of integers, whose ratio is equal to the original Fraction.
324335
325-
Return a tuple of two integers, whose ratio is equal to the
326-
Fraction and with a positive denominator.
336+
The ratio is in lowest terms and has a positive denominator.
327337
"""
328338
return (self._numerator, self._denominator)
329339

@@ -380,9 +390,9 @@ def limit_denominator(self, max_denominator=1000000):
380390
# the distance from p1/q1 to self is d/(q1*self._denominator). So we
381391
# need to compare 2*(q0+k*q1) with self._denominator/d.
382392
if 2*d*(q0+k*q1) <= self._denominator:
383-
return Fraction(p1, q1, _normalize=False)
393+
return Fraction._from_coprime_ints(p1, q1)
384394
else:
385-
return Fraction(p0+k*p1, q0+k*q1, _normalize=False)
395+
return Fraction._from_coprime_ints(p0+k*p1, q0+k*q1)
386396

387397
@property
388398
def numerator(a):
@@ -703,13 +713,13 @@ def _add(a, b):
703713
nb, db = b._numerator, b._denominator
704714
g = math.gcd(da, db)
705715
if g == 1:
706-
return Fraction(na * db + da * nb, da * db, _normalize=False)
716+
return Fraction._from_coprime_ints(na * db + da * nb, da * db)
707717
s = da // g
708718
t = na * (db // g) + nb * s
709719
g2 = math.gcd(t, g)
710720
if g2 == 1:
711-
return Fraction(t, s * db, _normalize=False)
712-
return Fraction(t // g2, s * (db // g2), _normalize=False)
721+
return Fraction._from_coprime_ints(t, s * db)
722+
return Fraction._from_coprime_ints(t // g2, s * (db // g2))
713723

714724
__add__, __radd__ = _operator_fallbacks(_add, operator.add)
715725

@@ -719,13 +729,13 @@ def _sub(a, b):
719729
nb, db = b._numerator, b._denominator
720730
g = math.gcd(da, db)
721731
if g == 1:
722-
return Fraction(na * db - da * nb, da * db, _normalize=False)
732+
return Fraction._from_coprime_ints(na * db - da * nb, da * db)
723733
s = da // g
724734
t = na * (db // g) - nb * s
725735
g2 = math.gcd(t, g)
726736
if g2 == 1:
727-
return Fraction(t, s * db, _normalize=False)
728-
return Fraction(t // g2, s * (db // g2), _normalize=False)
737+
return Fraction._from_coprime_ints(t, s * db)
738+
return Fraction._from_coprime_ints(t // g2, s * (db // g2))
729739

730740
__sub__, __rsub__ = _operator_fallbacks(_sub, operator.sub)
731741

@@ -741,15 +751,17 @@ def _mul(a, b):
741751
if g2 > 1:
742752
nb //= g2
743753
da //= g2
744-
return Fraction(na * nb, db * da, _normalize=False)
754+
return Fraction._from_coprime_ints(na * nb, db * da)
745755

746756
__mul__, __rmul__ = _operator_fallbacks(_mul, operator.mul)
747757

748758
def _div(a, b):
749759
"""a / b"""
750760
# Same as _mul(), with inversed b.
751-
na, da = a._numerator, a._denominator
752761
nb, db = b._numerator, b._denominator
762+
if nb == 0:
763+
raise ZeroDivisionError('Fraction(%s, 0)' % db)
764+
na, da = a._numerator, a._denominator
753765
g1 = math.gcd(na, nb)
754766
if g1 > 1:
755767
na //= g1
@@ -761,7 +773,7 @@ def _div(a, b):
761773
n, d = na * db, nb * da
762774
if d < 0:
763775
n, d = -n, -d
764-
return Fraction(n, d, _normalize=False)
776+
return Fraction._from_coprime_ints(n, d)
765777

766778
__truediv__, __rtruediv__ = _operator_fallbacks(_div, operator.truediv)
767779

@@ -798,17 +810,17 @@ def __pow__(a, b):
798810
if b.denominator == 1:
799811
power = b.numerator
800812
if power >= 0:
801-
return Fraction(a._numerator ** power,
802-
a._denominator ** power,
803-
_normalize=False)
804-
elif a._numerator >= 0:
805-
return Fraction(a._denominator ** -power,
806-
a._numerator ** -power,
807-
_normalize=False)
813+
return Fraction._from_coprime_ints(a._numerator ** power,
814+
a._denominator ** power)
815+
elif a._numerator > 0:
816+
return Fraction._from_coprime_ints(a._denominator ** -power,
817+
a._numerator ** -power)
818+
elif a._numerator == 0:
819+
raise ZeroDivisionError('Fraction(%s, 0)' %
820+
a._denominator ** -power)
808821
else:
809-
return Fraction((-a._denominator) ** -power,
810-
(-a._numerator) ** -power,
811-
_normalize=False)
822+
return Fraction._from_coprime_ints((-a._denominator) ** -power,
823+
(-a._numerator) ** -power)
812824
else:
813825
# A fractional power will generally produce an
814826
# irrational number.
@@ -832,15 +844,15 @@ def __rpow__(b, a):
832844

833845
def __pos__(a):
834846
"""+a: Coerces a subclass instance to Fraction"""
835-
return Fraction(a._numerator, a._denominator, _normalize=False)
847+
return Fraction._from_coprime_ints(a._numerator, a._denominator)
836848

837849
def __neg__(a):
838850
"""-a"""
839-
return Fraction(-a._numerator, a._denominator, _normalize=False)
851+
return Fraction._from_coprime_ints(-a._numerator, a._denominator)
840852

841853
def __abs__(a):
842854
"""abs(a)"""
843-
return Fraction(abs(a._numerator), a._denominator, _normalize=False)
855+
return Fraction._from_coprime_ints(abs(a._numerator), a._denominator)
844856

845857
def __int__(a, _index=operator.index):
846858
"""int(a)"""

Lib/test/test_fractions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,7 @@ def testArithmetic(self):
488488
self.assertEqual(F(5, 6), F(2, 3) * F(5, 4))
489489
self.assertEqual(F(1, 4), F(1, 10) / F(2, 5))
490490
self.assertEqual(F(-15, 8), F(3, 4) / F(-2, 5))
491+
self.assertRaises(ZeroDivisionError, operator.truediv, F(1), F(0))
491492
self.assertTypedEquals(2, F(9, 10) // F(2, 5))
492493
self.assertTypedEquals(10**23, F(10**23, 1) // F(1))
493494
self.assertEqual(F(5, 6), F(7, 3) % F(3, 2))

Lib/test/test_numeric_tower.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ def test_fractions(self):
145145
# The numbers ABC doesn't enforce that the "true" division
146146
# of integers produces a float. This tests that the
147147
# Rational.__float__() method has required type conversions.
148-
x = F(DummyIntegral(1), DummyIntegral(2), _normalize=False)
148+
x = F._from_coprime_ints(DummyIntegral(1), DummyIntegral(2))
149149
self.assertRaises(TypeError, lambda: x.numerator/x.denominator)
150150
self.assertEqual(float(x), 0.5)
151151

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Optimize :class:`fractions.Fraction` for small components. The private argument
2+
``_normalize`` of the :class:`fractions.Fraction` constructor has been removed.

Objects/clinic/floatobject.c.h

Lines changed: 4 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/clinic/longobject.c.h

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Objects/floatobject.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,12 +1546,10 @@ float_fromhex(PyTypeObject *type, PyObject *string)
15461546
/*[clinic input]
15471547
float.as_integer_ratio
15481548
1549-
Return integer ratio.
1549+
Return a pair of integers, whose ratio is exactly equal to the original float.
15501550
1551-
Return a pair of integers, whose ratio is exactly equal to the original float
1552-
and with a positive denominator.
1553-
1554-
Raise OverflowError on infinities and a ValueError on NaNs.
1551+
The ratio is in lowest terms and has a positive denominator. Raise
1552+
OverflowError on infinities and a ValueError on NaNs.
15551553
15561554
>>> (10.0).as_integer_ratio()
15571555
(10, 1)
@@ -1563,7 +1561,7 @@ Raise OverflowError CEA6 on infinities and a ValueError on NaNs.
15631561

15641562
static PyObject *
15651563
float_as_integer_ratio_impl(PyObject *self)
1566-
/*[clinic end generated code: output=65f25f0d8d30a712 input=e21d08b4630c2e44]*/
1564+
/*[clinic end generated code: output=65f25f0d8d30a712 input=d5ba7765655d75bd]*/
15671565
{
15681566
double self_double;
15691567
double float_part;

Objects/longobject.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6020,10 +6020,9 @@ int_bit_count_impl(PyObject *self)
60206020
/*[clinic input]
60216021
int.as_integer_ratio
60226022
6023-
Return integer ratio.
6023+
Return a pair of integers, whose ratio is equal to the original int.
60246024
6025-
Return a pair of integers, whose ratio is exactly equal to the original int
6026-
and with a positive denominator.
6025+
The ratio is in lowest terms and has a positive denominator.
60276026
60286027
>>> (10).as_integer_ratio()
60296028
(10, 1)
@@ -6035,7 +6034,7 @@ and with a positive denominator.
60356034

60366035
static PyObject *
60376036
int_as_integer_ratio_impl(PyObject *self)
6038-
/*[clinic end generated code: output=e60803ae1cc8621a input=55ce3058e15de393]*/
6037+
/*[clinic end generated code: output=e60803ae1cc8621a input=384ff1766634bec2]*/
60396038
{
60406039
PyObject *ratio_tuple;
60416040
PyObject *numerator = long_long(self);

0 commit comments

Comments
 (0)
2A1F
0