From b2e64f903d451b7ed6907d1555d95acc497c11a2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 8 Nov 2016 20:34:22 +0200 Subject: [PATCH] Issue #28621: Sped up converting int to float by reusing faster bits counting implementation. Patch by Adrian Wielgosik. --- Misc/NEWS | 3 +++ Objects/longobject.c | 60 +++++++++++++++++++++----------------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/Misc/NEWS b/Misc/NEWS index 94500c240e7..91b97eb6e78 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1 Core and Builtins ----------------- +- Issue #28621: Sped up converting int to float by reusing faster bits counting + implementation. Patch by Adrian Wielgosik. + - Issue #28580: Optimize iterating split table values. Patch by Xiang Zhang. diff --git a/Objects/longobject.c b/Objects/longobject.c index 6e569b218dc..10dde726a29 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -708,12 +708,33 @@ _PyLong_Sign(PyObject *vv) return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); } +/* bits_in_digit(d) returns the unique integer k such that 2**(k-1) <= d < + 2**k if d is nonzero, else 0. */ + +static const unsigned char BitLengthTable[32] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 +}; + +static int +bits_in_digit(digit d) +{ + int d_bits = 0; + while (d >= 32) { + d_bits += 6; + d >>= 6; + } + d_bits += (int)BitLengthTable[d]; + return d_bits; +} + size_t _PyLong_NumBits(PyObject *vv) { PyLongObject *v = (PyLongObject *)vv; size_t result = 0; Py_ssize_t ndigits; + int msd_bits; assert(v != NULL); assert(PyLong_Check(v)); @@ -724,12 +745,10 @@ _PyLong_NumBits(PyObject *vv) if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT) goto Overflow; result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT; - do { - ++result; - if (result == 0) - goto Overflow; - msd >>= 1; - } while (msd); + msd_bits = bits_in_digit(msd); + if (SIZE_MAX - msd_bits < result) + goto Overflow; + result += msd_bits; } return result; @@ -1414,26 +1433,6 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) Py_RETURN_NOTIMPLEMENTED; \ } while(0) -/* bits_in_digit(d) returns the unique integer k such that 2**(k-1) <= d < - 2**k if d is nonzero, else 0. */ - -static const unsigned char BitLengthTable[32] = { - 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 -}; - -static int -bits_in_digit(digit d) -{ - int d_bits = 0; - while (d >= 32) { - d_bits += 6; - d >>= 6; - } - d_bits += (int)BitLengthTable[d]; - return d_bits; -} - /* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] * is modified in place, by adding y to it. Carries are propagated as far as * x[m-1], and the remaining carry (0 or 1) is returned. @@ -5079,7 +5078,8 @@ static PyObject * long_bit_length(PyLongObject *v) { PyLongObject *result, *x, *y; - Py_ssize_t ndigits, msd_bits = 0; + Py_ssize_t ndigits; + int msd_bits; digit msd; assert(v != NULL); @@ -5090,11 +5090,7 @@ long_bit_length(PyLongObject *v) return PyLong_FromLong(0); msd = v->ob_digit[ndigits-1]; - while (msd >= 32) { - msd_bits += 6; - msd >>= 6; - } - msd_bits += (long)(BitLengthTable[msd]); + msd_bits = bits_in_digit(msd); if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits);