Issue #28621: Sped up converting int to float by reusing faster bits counting

implementation.  Patch by Adrian Wielgosik.
This commit is contained in:
Serhiy Storchaka 2016-11-08 20:34:22 +02:00
parent b74fecc396
commit b2e64f903d
2 changed files with 31 additions and 32 deletions

View File

@ -10,6 +10,9 @@ What's New in Python 3.7.0 alpha 1
Core and Builtins 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. - Issue #28580: Optimize iterating split table values.
Patch by Xiang Zhang. Patch by Xiang Zhang.

View File

@ -708,12 +708,33 @@ _PyLong_Sign(PyObject *vv)
return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); 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 size_t
_PyLong_NumBits(PyObject *vv) _PyLong_NumBits(PyObject *vv)
{ {
PyLongObject *v = (PyLongObject *)vv; PyLongObject *v = (PyLongObject *)vv;
size_t result = 0; size_t result = 0;
Py_ssize_t ndigits; Py_ssize_t ndigits;
int msd_bits;
assert(v != NULL); assert(v != NULL);
assert(PyLong_Check(v)); assert(PyLong_Check(v));
@ -724,12 +745,10 @@ _PyLong_NumBits(PyObject *vv)
if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT) if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT)
goto Overflow; goto Overflow;
result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT; result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT;
do { msd_bits = bits_in_digit(msd);
++result; if (SIZE_MAX - msd_bits < result)
if (result == 0) goto Overflow;
goto Overflow; result += msd_bits;
msd >>= 1;
} while (msd);
} }
return result; return result;
@ -1414,26 +1433,6 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
Py_RETURN_NOTIMPLEMENTED; \ Py_RETURN_NOTIMPLEMENTED; \
} while(0) } 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] /* 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 * 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. * x[m-1], and the remaining carry (0 or 1) is returned.
@ -5079,7 +5078,8 @@ static PyObject *
long_bit_length(PyLongObject *v) long_bit_length(PyLongObject *v)
{ {
PyLongObject *result, *x, *y; PyLongObject *result, *x, *y;
Py_ssize_t ndigits, msd_bits = 0; Py_ssize_t ndigits;
int msd_bits;
digit msd; digit msd;
assert(v != NULL); assert(v != NULL);
@ -5090,11 +5090,7 @@ long_bit_length(PyLongObject *v)
return PyLong_FromLong(0); return PyLong_FromLong(0);
msd = v->ob_digit[ndigits-1]; msd = v->ob_digit[ndigits-1];
while (msd >= 32) { msd_bits = bits_in_digit(msd);
msd_bits += 6;
msd >>= 6;
}
msd_bits += (long)(BitLengthTable[msd]);
if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT)
return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits); return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits);