[Python-checkins] cpython: Issue #25971: Optimized creating Fractions from floats by 2 times and from

serhiy.storchaka python-checkins at python.org
Tue Dec 29 15:34:44 EST 2015


https://hg.python.org/cpython/rev/284026a8af9e
changeset:   99716:284026a8af9e
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Tue Dec 29 22:34:23 2015 +0200
summary:
  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.

files:
  Lib/_pydecimal.py          |   6 +---
  Lib/fractions.py           |  32 +++----------------------
  Lib/test/test_fractions.py |  14 +++++-----
  Misc/NEWS                  |   3 ++
  Objects/floatobject.c      |  12 ++++----
  5 files changed, 22 insertions(+), 45 deletions(-)


diff --git a/Lib/_pydecimal.py b/Lib/_pydecimal.py
--- a/Lib/_pydecimal.py
+++ b/Lib/_pydecimal.py
@@ -1026,11 +1026,9 @@
         """
         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
--- a/Lib/fractions.py
+++ b/Lib/fractions.py
@@ -125,17 +125,9 @@
                 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 @@
         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 @@
             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
--- a/Lib/test/test_fractions.py
+++ b/Lib/test/test_fractions.py
@@ -263,13 +263,13 @@
         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 @@
 
         # 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
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -126,6 +126,9 @@
 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
--- a/Objects/floatobject.c
+++ b/Objects/floatobject.c
@@ -1466,14 +1466,14 @@
     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);

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list