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

Skip to content

Commit 0d250bc

Browse files
Issue #25971: Optimized creating Fractions from floats by 2 times and from
Decimals by 3 times. Unified error messages in float.as_integer_ratio(), Decimal.as_integer_ratio(), and Fraction constructors.
1 parent 5aab44b commit 0d250bc

5 files changed

Lines changed: 22 additions & 45 deletions

File tree

Lib/_pydecimal.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,11 +1026,9 @@ def as_integer_ratio(self):
10261026
"""
10271027
if self._is_special:
10281028
if self.is_nan():
1029-
raise ValueError("Cannot pass NaN "
1030-
"to decimal.as_integer_ratio.")
1029+
raise ValueError("cannot convert NaN to integer ratio")
10311030
else:
1032-
raise OverflowError("Cannot pass infinity "
1033-
"to decimal.as_integer_ratio.")
1031+
raise OverflowError("cannot convert Infinity to integer ratio")
10341032

10351033
if not self:
10361034
return 0, 1

Lib/fractions.py

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,9 @@ def __new__(cls, numerator=0, denominator=None, _normalize=True):
125125
self._denominator = numerator.denominator
126126
return self
127127

128-
elif isinstance(numerator, float):
129-
# Exact conversion from float
130-
value = Fraction.from_float(numerator)
131-
self._numerator = value._numerator
132-
self._denominator = value._denominator
133-
return self
134-
135-
elif isinstance(numerator, Decimal):
136-
value = Fraction.from_decimal(numerator)
137-
self._numerator = value._numerator
138-
self._denominator = value._denominator
128+
elif isinstance(numerator, (float, Decimal)):
129+
# Exact conversion
130+
self._numerator, self._denominator = numerator.as_integer_ratio()
139131
return self
140132

141133
elif isinstance(numerator, str):
@@ -210,10 +202,6 @@ def from_float(cls, f):
210202
elif not isinstance(f, float):
211203
raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
212204
(cls.__name__, f, type(f).__name__))
213-
if math.isnan(f):
214-
raise ValueError("Cannot convert %r to %s." % (f, cls.__name__))
215-
if math.isinf(f):
216-
raise OverflowError("Cannot convert %r to %s." % (f, cls.__name__))
217205
return cls(*f.as_integer_ratio())
218206

219207
@classmethod
@@ -226,19 +214,7 @@ def from_decimal(cls, dec):
226214
raise TypeError(
227215
"%s.from_decimal() only takes Decimals, not %r (%s)" %
228216
(cls.__name__, dec, type(dec).__name__))
229-
if dec.is_infinite():
230-
raise OverflowError(
231-
"Cannot convert %s to %s." % (dec, cls.__name__))
232-
if dec.is_nan():
233-
raise ValueError("Cannot convert %s to %s." % (dec, cls.__name__))
234-
sign, digits, exp = dec.as_tuple()
235-
digits = int(''.join(map(str, digits)))
236-
if sign:
237-
digits = -digits
238-
if exp >= 0:
239-
return cls(digits * 10 ** exp)
240-
else:
241-
return cls(digits, 10 ** -exp)
217+
return cls(*dec.as_integer_ratio())
242218

243219
def limit_denominator(self, max_denominator=1000000):
244220
"""Closest Fraction to self with denominator at most max_denominator.

Lib/test/test_fractions.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,13 @@ def testFromFloat(self):
263263
nan = inf - inf
264264
# bug 16469: error types should be consistent with float -> int
265265
self.assertRaisesMessage(
266-
OverflowError, "Cannot convert inf to Fraction.",
266+
OverflowError, "cannot convert Infinity to integer ratio",
267267
F.from_float, inf)
268268
self.assertRaisesMessage(
269-
OverflowError, "Cannot convert -inf to Fraction.",
269+
OverflowError, "cannot convert Infinity to integer ratio",
270270
F.from_float, -inf)
271271
self.assertRaisesMessage(
272-
ValueError, "Cannot convert nan to Fraction.",
272+
ValueError, "cannot convert NaN to integer ratio",
273273
F.from_float, nan)
274274

275275
def testFromDecimal(self):
@@ -284,16 +284,16 @@ def testFromDecimal(self):
284284

285285
# bug 16469: error types should be consistent with decimal -> int
286286
self.assertRaisesMessage(
287-
OverflowError, "Cannot convert Infinity to Fraction.",
287+
OverflowError, "cannot convert Infinity to integer ratio",
288288
F.from_decimal, Decimal("inf"))
289289
self.assertRaisesMessage(
290-
OverflowError, "Cannot convert -Infinity to Fraction.",
290+
OverflowError, "cannot convert Infinity to integer ratio",
291291
F.from_decimal, Decimal("-inf"))
292292
self.assertRaisesMessage(
293-
ValueError, "Cannot convert NaN to Fraction.",
293+
ValueError, "cannot convert NaN to integer ratio",
294294
F.from_decimal, Decimal("nan"))
295295
self.assertRaisesMessage(
296-
ValueError, "Cannot convert sNaN to Fraction.",
296+
ValueError, "cannot convert NaN to integer ratio",
297297
F.from_decimal, Decimal("snan"))
298298

299299
def testLimitDenominator(self):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ Core and Builtins
126126
Library
127127
-------
128128

129+
- Issue #25971: Optimized creating Fractions from floats by 2 times and from
130+
Decimals by 3 times.
131+
129132
- Issue #25802: Document as deprecated the remaining implementations of
130133
importlib.abc.Loader.load_module().
131134

Objects/floatobject.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,14 +1466,14 @@ float_as_integer_ratio(PyObject *v, PyObject *unused)
14661466
CONVERT_TO_DOUBLE(v, self);
14671467

14681468
if (Py_IS_INFINITY(self)) {
1469-
PyErr_SetString(PyExc_OverflowError,
1470-
"Cannot pass infinity to float.as_integer_ratio.");
1471-
return NULL;
1469+
PyErr_SetString(PyExc_OverflowError,
1470+
"cannot convert Infinity to integer ratio");
1471+
return NULL;
14721472
}
14731473
if (Py_IS_NAN(self)) {
1474-
PyErr_SetString(PyExc_ValueError,
1475-
"Cannot pass NaN to float.as_integer_ratio.");
1476-
return NULL;
1474+
PyErr_SetString(PyExc_ValueError,
1475+
"cannot convert NaN to integer ratio");
1476+
return NULL;
14771477
}
14781478

14791479
PyFPE_START_PROTECT("as_integer_ratio", goto error);

0 commit comments

Comments
 (0)