]> granicus.if.org Git - python/commitdiff
Issue #25402: in int-to-decimal-string conversion, reduce intermediate storage requir...
authorMark Dickinson <dickinsm@gmail.com>
Mon, 29 Aug 2016 16:26:43 +0000 (17:26 +0100)
committerMark Dickinson <dickinsm@gmail.com>
Mon, 29 Aug 2016 16:26:43 +0000 (17:26 +0100)
Misc/NEWS
Objects/longobject.c

index 32144d1311fd2bb9b9bedb01f40428c4d5ee46ec..9873abbab8ec793bf9c4295e4c8d8cf4f4b0395d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@ What's New in Python 3.6.0 beta 1
 Core and Builtins
 -----------------
 
+- Issue #25402: In int-to-decimal-string conversion, improve the estimate
+  of the intermediate memory required, and remove an unnecessarily strict
+  overflow check. Patch by Serhiy Storchaka.
+
 - Issue #27214: In long_invert, be more careful about modifying object
   returned by long_add, and remove an unnecessary check for small longs.
   Thanks Oren Milman for analysis and patch.
index 89b68626057633939a471a4d4290182ed98722c5..ba23599535934cc0d7a70b02708cf21d0a63a002 100644 (file)
@@ -1591,6 +1591,7 @@ long_to_decimal_string_internal(PyObject *aa,
     Py_ssize_t size, strlen, size_a, i, j;
     digit *pout, *pin, rem, tenpow;
     int negative;
+    int d;
     enum PyUnicode_Kind kind;
 
     a = (PyLongObject *)aa;
@@ -1608,15 +1609,17 @@ long_to_decimal_string_internal(PyObject *aa,
 
        But log2(a) < size_a * PyLong_SHIFT, and
        log2(_PyLong_DECIMAL_BASE) = log2(10) * _PyLong_DECIMAL_SHIFT
-                                  > 3 * _PyLong_DECIMAL_SHIFT
+                                  > 3.3 * _PyLong_DECIMAL_SHIFT
+
+         size_a * PyLong_SHIFT / (3.3 * _PyLong_DECIMAL_SHIFT) =
+             size_a + size_a / d < size_a + size_a / floor(d),
+       where d = (3.3 * _PyLong_DECIMAL_SHIFT) /
+                 (PyLong_SHIFT - 3.3 * _PyLong_DECIMAL_SHIFT)
     */
-    if (size_a > PY_SSIZE_T_MAX / PyLong_SHIFT) {
-        PyErr_SetString(PyExc_OverflowError,
-                        "int too large to format");
-        return -1;
-    }
-    /* the expression size_a * PyLong_SHIFT is now safe from overflow */
-    size = 1 + size_a * PyLong_SHIFT / (3 * _PyLong_DECIMAL_SHIFT);
+    d = (33 * _PyLong_DECIMAL_SHIFT) /
+        (10 * PyLong_SHIFT - 33 * _PyLong_DECIMAL_SHIFT);
+    assert(size_a < PY_SSIZE_T_MAX/2);
+    size = 1 + size_a + size_a / d;
     scratch = _PyLong_New(size);
     if (scratch == NULL)
         return -1;