summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2016-08-29 16:26:43 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2016-08-29 16:26:43 (GMT)
commit4e1de16f88cd8b99b2d154e647b63f2f6f8b58ae (patch)
treef67c47fff4c9a4f00a94f9c9522b4ead0c4fc19a
parent583c6e860c1f9eee81ebf09fd87e0f921e8c0dd2 (diff)
downloadcpython-4e1de16f88cd8b99b2d154e647b63f2f6f8b58ae.zip
cpython-4e1de16f88cd8b99b2d154e647b63f2f6f8b58ae.tar.gz
cpython-4e1de16f88cd8b99b2d154e647b63f2f6f8b58ae.tar.bz2
Issue #25402: in int-to-decimal-string conversion, reduce intermediate storage requirements and relax restriction on converting large integers. Patch by Serhiy Storchaka.
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/longobject.c19
2 files changed, 15 insertions, 8 deletions
diff --git a/Misc/NEWS b/Misc/NEWS
index 32144d1..9873abb 100644
--- 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.
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 89b6862..ba23599 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -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;