]> granicus.if.org Git - python/commitdiff
Issue #25971: Optimized creating Fractions from floats by 2 times and from
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 29 Dec 2015 20:34:23 +0000 (22:34 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 29 Dec 2015 20:34:23 +0000 (22:34 +0200)
Decimals by 3 times.
Unified error messages in float.as_integer_ratio(), Decimal.as_integer_ratio(),
and Fraction constructors.

Lib/_pydecimal.py
Lib/fractions.py
Lib/test/test_fractions.py
Misc/NEWS
Objects/floatobject.c

index eb7bba8e93a7fa6cc976bb1550c98c70efb5e582..02365cad2c3cd214738f45d35d54ff07218c9e77 100644 (file)
@@ -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
index 60b072880703c246005be2c48e17046e71d84e47..64d746b842e268fb629e628b91319073586ccd06 100644 (file)
@@ -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.
index 16998522160b960c72cecc2b985c7c4ea6e3aeaa..73d2dd3031e552ebcf5c8a3bf66aa638bb4a50f0 100644 (file)
@@ -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):
index 6ec585ac0736dcc3daab7b87e19840efbb72131b..6333401c6abf90eec692e8533e01a82eace61e02 100644 (file)
--- 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().
 
index d92bec35b5f8819270bd9152ad11cbd8bdc1b6dd..2949174c99dc9e54f955c24849886f08129c60f2 100644 (file)
@@ -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);