summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2015-12-29 20:34:23 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2015-12-29 20:34:23 (GMT)
commit0d250bc119489fa7d094d4a3fd2fd2fa0a508145 (patch)
tree713daa0ef460e7a6744de0748ea829fefe6efb12
parent5aab44b301fff2c6a7f00e24944a3360eedd7aa8 (diff)
downloadcpython-0d250bc119489fa7d094d4a3fd2fd2fa0a508145.zip
cpython-0d250bc119489fa7d094d4a3fd2fd2fa0a508145.tar.gz
cpython-0d250bc119489fa7d094d4a3fd2fd2fa0a508145.tar.bz2
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.
-rw-r--r--Lib/_pydecimal.py6
-rw-r--r--Lib/fractions.py32
-rw-r--r--Lib/test/test_fractions.py14
-rw-r--r--Misc/NEWS3
-rw-r--r--Objects/floatobject.c12
5 files changed, 22 insertions, 45 deletions
diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py
index eb7bba8..02365ca 100644
--- a/Lib/_pydecimal.py
+++ b/Lib/_pydecimal.py
@@ -1026,11 +1026,9 @@ class Decimal(object):
"""
if self._is_special:
if self.is_nan():
- raise ValueError("Cannot pass NaN "
- "to decimal.as_integer_ratio.")
+ raise ValueError("cannot convert NaN to integer ratio")
else:
- raise OverflowError("Cannot pass infinity "
- "to decimal.as_integer_ratio.")
+ raise OverflowError("cannot convert Infinity to integer ratio")
if not self:
return 0, 1
diff --git a/Lib/fractions.py b/Lib/fractions.py
index 60b0728..64d746b 100644
--- a/Lib/fractions.py
+++ b/Lib/fractions.py
@@ -125,17 +125,9 @@ class Fraction(numbers.Rational):
self._denominator = numerator.denominator
return self
- elif isinstance(numerator, float):
- # Exact conversion from float
- value = Fraction.from_float(numerator)
- self._numerator = value._numerator
- self._denominator = value._denominator
- return self
-
- elif isinstance(numerator, Decimal):
- value = Fraction.from_decimal(numerator)
- self._numerator = value._numerator
- self._denominator = value._denominator
+ elif isinstance(numerator, (float, Decimal)):
+ # Exact conversion
+ self._numerator, self._denominator = numerator.as_integer_ratio()
return self
elif isinstance(numerator, str):
@@ -210,10 +202,6 @@ class Fraction(numbers.Rational):
elif not isinstance(f, float):
raise TypeError("%s.from_float() only takes floats, not %r (%s)" %
(cls.__name__, f, type(f).__name__))
- if math.isnan(f):
- raise ValueError("Cannot convert %r to %s." % (f, cls.__name__))
- if math.isinf(f):
- raise OverflowError("Cannot convert %r to %s." % (f, cls.__name__))
return cls(*f.as_integer_ratio())
@classmethod
@@ -226,19 +214,7 @@ class Fraction(numbers.Rational):
raise TypeError(
"%s.from_decimal() only takes Decimals, not %r (%s)" %
(cls.__name__, dec, type(dec).__name__))
- if dec.is_infinite():
- raise OverflowError(
- "Cannot convert %s to %s." % (dec, cls.__name__))
- if dec.is_nan():
- raise ValueError("Cannot convert %s to %s." % (dec, cls.__name__))
- sign, digits, exp = dec.as_tuple()
- digits = int(''.join(map(str, digits)))
- if sign:
- digits = -digits
- if exp >= 0:
- return cls(digits * 10 ** exp)
- else:
- return cls(digits, 10 ** -exp)
+ return cls(*dec.as_integer_ratio())
def limit_denominator(self, max_denominator=1000000):
"""Closest Fraction to self with denominator at most max_denominator.
diff --git a/Lib/test/test_fractions.py b/Lib/test/test_fractions.py
index 1699852..73d2dd3 100644
--- a/Lib/test/test_fractions.py
+++ b/Lib/test/test_fractions.py
@@ -263,13 +263,13 @@ class FractionTest(unittest.TestCase):
nan = inf - inf
# bug 16469: error types should be consistent with float -> int
self.assertRaisesMessage(
- OverflowError, "Cannot convert inf to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_float, inf)
self.assertRaisesMessage(
- OverflowError, "Cannot convert -inf to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_float, -inf)
self.assertRaisesMessage(
- ValueError, "Cannot convert nan to Fraction.",
+ ValueError, "cannot convert NaN to integer ratio",
F.from_float, nan)
def testFromDecimal(self):
@@ -284,16 +284,16 @@ class FractionTest(unittest.TestCase):
# bug 16469: error types should be consistent with decimal -> int
self.assertRaisesMessage(
- OverflowError, "Cannot convert Infinity to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_decimal, Decimal("inf"))
self.assertRaisesMessage(
- OverflowError, "Cannot convert -Infinity to Fraction.",
+ OverflowError, "cannot convert Infinity to integer ratio",
F.from_decimal, Decimal("-inf"))
self.assertRaisesMessage(
- ValueError, "Cannot convert NaN to Fraction.",
+ ValueError, "cannot convert NaN to integer ratio",
F.from_decimal, Decimal("nan"))
self.assertRaisesMessage(
- ValueError, "Cannot convert sNaN to Fraction.",
+ ValueError, "cannot convert NaN to integer ratio",
F.from_decimal, Decimal("snan"))
def testLimitDenominator(self):
diff --git a/Misc/NEWS b/Misc/NEWS
index 6ec585a..6333401 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -126,6 +126,9 @@ Core and Builtins
Library
-------
+- Issue #25971: Optimized creating Fractions from floats by 2 times and from
+ Decimals by 3 times.
+
- Issue #25802: Document as deprecated the remaining implementations of
importlib.abc.Loader.load_module().
diff --git a/Objects/floatobject.c b/Objects/floatobject.c
index d92bec3..2949174 100644
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -1466,14 +1466,14 @@ float_as_integer_ratio(PyObject *v, PyObject *unused)
CONVERT_TO_DOUBLE(v, self);
if (Py_IS_INFINITY(self)) {
- PyErr_SetString(PyExc_OverflowError,
- "Cannot pass infinity to float.as_integer_ratio.");
- return NULL;
+ PyErr_SetString(PyExc_OverflowError,
+ "cannot convert Infinity to integer ratio");
+ return NULL;
}
if (Py_IS_NAN(self)) {
- PyErr_SetString(PyExc_ValueError,
- "Cannot pass NaN to float.as_integer_ratio.");
- return NULL;
+ PyErr_SetString(PyExc_ValueError,
+ "cannot convert NaN to integer ratio");
+ return NULL;
}
PyFPE_START_PROTECT("as_integer_ratio", goto error);