Skip to content

Commit ccdbe59

Browse files
committed
bpo-31031: Unify duplicate bits_in_digit and bit_length
1 parent 3924377 commit ccdbe59

File tree

4 files changed

+38
-59
lines changed

4 files changed

+38
-59
lines changed

Include/pymath.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,4 +215,10 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short);
215215
(X) == -Py_HUGE_VAL))
216216
#endif
217217

218+
/* Return the smallest integer k such that n < 2**k, or 0 if n == 0.
219+
* Equivalent to floor(lg(x))+1. Also equivalent to: bitwidth_of_type -
220+
* count_leading_zero_bits(x)
221+
*/
222+
extern unsigned int _Py_bit_length(unsigned long d);
223+
218224
#endif /* Py_PYMATH_H */

Modules/mathmodule.c

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,28 +1419,6 @@ math_fsum(PyObject *module, PyObject *seq)
14191419
#undef NUM_PARTIALS
14201420

14211421

1422-
/* Return the smallest integer k such that n < 2**k, or 0 if n == 0.
1423-
* Equivalent to floor(lg(x))+1. Also equivalent to: bitwidth_of_type -
1424-
* count_leading_zero_bits(x)
1425-
*/
1426-
1427-
/* XXX: This routine does more or less the same thing as
1428-
* bits_in_digit() in Objects/longobject.c. Someday it would be nice to
1429-
* consolidate them. On BSD, there's a library function called fls()
1430-
* that we could use, and GCC provides __builtin_clz().
1431-
*/
1432-
1433-
static unsigned long
1434-
bit_length(unsigned long n)
1435-
{
1436-
unsigned long len = 0;
1437-
while (n != 0) {
1438-
++len;
1439-
n >>= 1;
1440-
}
1441-
return len;
1442-
}
1443-
14441422
static unsigned long
14451423
count_set_bits(unsigned long n)
14461424
{
@@ -1519,7 +1497,7 @@ count_set_bits(unsigned long n)
15191497

15201498
/* factorial_partial_product: Compute product(range(start, stop, 2)) using
15211499
* divide and conquer. Assumes start and stop are odd and stop > start.
1522-
* max_bits must be >= bit_length(stop - 2). */
1500+
* max_bits must be >= _Py_bit_length(stop - 2). */
15231501

15241502
static PyObject *
15251503
factorial_partial_product(unsigned long start, unsigned long stop,
@@ -1534,14 +1512,14 @@ factorial_partial_product(unsigned long start, unsigned long stop,
15341512
* the answer.
15351513
*
15361514
* Storing some integer z requires floor(lg(z))+1 bits, which is
1537-
* conveniently the value returned by bit_length(z). The
1515+
* conveniently the value returned by _Py_bit_length(z). The
15381516
* product x*y will require at most
1539-
* bit_length(x) + bit_length(y) bits to store, based
1517+
* _Py_bit_length(x) + _Py_bit_length(y) bits to store, based
15401518
* on the idea that lg product = lg x + lg y.
15411519
*
15421520
* We know that stop - 2 is the largest number to be multiplied. From
1543-
* there, we have: bit_length(answer) <= num_operands *
1544-
* bit_length(stop - 2)
1521+
* there, we have: _Py_bit_length(answer) <= num_operands *
1522+
* _Py_bit_length(stop - 2)
15451523
*/
15461524

15471525
num_operands = (stop - start) / 2;
@@ -1558,7 +1536,7 @@ factorial_partial_product(unsigned long start, unsigned long stop,
15581536
/* find midpoint of range(start, stop), rounded up to next odd number. */
15591537
midpoint = (start + num_operands) | 1;
15601538
left = factorial_partial_product(start, midpoint,
1561-
bit_length(midpoint - 2));
1539+
_Py_bit_length(midpoint - 2));
15621540
if (left == NULL)
15631541
goto error;
15641542
right = factorial_partial_product(midpoint, stop, max_bits);
@@ -1588,7 +1566,7 @@ factorial_odd_part(unsigned long n)
15881566
Py_INCREF(outer);
15891567

15901568
upper = 3;
1591-
for (i = bit_length(n) - 2; i >= 0; i--) {
1569+
for (i = _Py_bit_length(n) - 2; i >= 0; i--) {
15921570
v = n >> i;
15931571
if (v <= 2)
15941572
continue;
@@ -1598,7 +1576,7 @@ factorial_odd_part(unsigned long n)
15981576
/* Here inner is the product of all odd integers j in the range (0,
15991577
n/2**(i+1)]. The factorial_partial_product call below gives the
16001578
product of all odd integers j in the range (n/2**(i+1), n/2**i]. */
1601-
partial = factorial_partial_product(lower, upper, bit_length(upper-2));
1579+
partial = factorial_partial_product(lower, upper, _Py_bit_length(upper-2));
16021580
/* inner *= partial */
16031581
if (partial == NULL)
16041582
goto error;

Objects/longobject.c

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -720,26 +720,6 @@ _PyLong_Sign(PyObject *vv)
720720
return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1);
721721
}
722722

723-
/* bits_in_digit(d) returns the unique integer k such that 2**(k-1) <= d <
724-
2**k if d is nonzero, else 0. */
725-
726-
static const unsigned char BitLengthTable[32] = {
727-
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
728-
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
729-
};
730-
731-
static int
732-
bits_in_digit(digit d)
733-
{
734-
int d_bits = 0;
735-
while (d >= 32) {
736-
d_bits += 6;
737-
d >>= 6;
738-
}
739-
d_bits += (int)BitLengthTable[d];
740-
return d_bits;
741-
}
742-
743723
size_t
744724
_PyLong_NumBits(PyObject *vv)
745725
{
@@ -757,7 +737,7 @@ _PyLong_NumBits(PyObject *vv)
757737
if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT)
758738
goto Overflow;
759739
result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT;
760-
msd_bits = bits_in_digit(msd);
740+
msd_bits = _Py_bit_length(msd);
761741
if (SIZE_MAX - msd_bits < result)
762742
goto Overflow;
763743
result += msd_bits;
@@ -1823,7 +1803,7 @@ long_format_binary(PyObject *aa, int base, int alternate,
18231803
return -1;
18241804
}
18251805
size_a_in_bits = (size_a - 1) * PyLong_SHIFT +
1826-
bits_in_digit(a->ob_digit[size_a - 1]);
1806+
_Py_bit_length(a->ob_digit[size_a - 1]);
18271807
/* Allow 1 character for a '-' sign. */
18281808
sz = negative + (size_a_in_bits + (bits - 1)) / bits;
18291809
}
@@ -2639,7 +2619,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
26392619

26402620
/* normalize: shift w1 left so that its top digit is >= PyLong_BASE/2.
26412621
shift v1 left by the same amount. Results go into w and v. */
2642-
d = PyLong_SHIFT - bits_in_digit(w1->ob_digit[size_w-1]);
2622+
d = PyLong_SHIFT - _Py_bit_length(w1->ob_digit[size_w-1]);
26432623
carry = v_lshift(w->ob_digit, w1->ob_digit, size_w, d);
26442624
assert(carry == 0);
26452625
carry = v_lshift(v->ob_digit, v1->ob_digit, size_v, d);
@@ -2760,7 +2740,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e)
27602740
*e = 0;
27612741
return 0.0;
27622742
}
2763-
a_bits = bits_in_digit(a->ob_digit[a_size-1]);
2743+
a_bits = _Py_bit_length(a->ob_digit[a_size-1]);
27642744
/* The following is an overflow-free version of the check
27652745
"if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */
27662746
if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 &&
@@ -3889,8 +3869,8 @@ long_true_divide(PyObject *v, PyObject *w)
38893869
/* Extreme underflow */
38903870
goto underflow_or_zero;
38913871
/* Next line is now safe from overflowing a Py_ssize_t */
3892-
diff = diff * PyLong_SHIFT + bits_in_digit(a->ob_digit[a_size - 1]) -
3893-
bits_in_digit(b->ob_digit[b_size - 1]);
3872+
diff = diff * PyLong_SHIFT + _Py_bit_length(a->ob_digit[a_size - 1]) -
3873+
_Py_bit_length(b->ob_digit[b_size - 1]);
38943874
/* Now diff = a_bits - b_bits. */
38953875
if (diff > DBL_MAX_EXP)
38963876
goto overflow;
@@ -3966,7 +3946,7 @@ long_true_divide(PyObject *v, PyObject *w)
39663946
}
39673947
x_size = Py_ABS(Py_SIZE(x));
39683948
assert(x_size > 0); /* result of division is never zero */
3969-
x_bits = (x_size-1)*PyLong_SHIFT+bits_in_digit(x->ob_digit[x_size-1]);
3949+
x_bits = (x_size-1)*PyLong_SHIFT+_Py_bit_length(x->ob_digit[x_size-1]);
39703950

39713951
/* The number of extra bits that have to be rounded away. */
39723952
extra_bits = Py_MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG;
@@ -4629,7 +4609,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg)
46294609
alloc_b = Py_SIZE(b);
46304610
/* reduce until a fits into 2 digits */
46314611
while ((size_a = Py_SIZE(a)) > 2) {
4632-
nbits = bits_in_digit(a->ob_digit[size_a-1]);
4612+
nbits = _Py_bit_length(a->ob_digit[size_a-1]);
46334613
/* extract top 2*PyLong_SHIFT bits of a into x, along with
46344614
corresponding bits of b into y */
46354615
size_b = Py_SIZE(b);
@@ -5144,7 +5124,7 @@ int_bit_length_impl(PyObject *self)
51445124
return PyLong_FromLong(0);
51455125

51465126
msd = ((PyLongObject *)self)->ob_digit[ndigits-1];
5147-
msd_bits = bits_in_digit(msd);
5127+
msd_bits = _Py_bit_length(msd);
51485128

51495129
if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT)
51505130
return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits);

Python/pymath.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,18 @@ round(double x)
7777
return copysign(y, x);
7878
}
7979
#endif /* HAVE_ROUND */
80+
81+
static const unsigned int BitLengthTable[32] = {
82+
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
83+
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
84+
};
85+
86+
unsigned int _Py_bit_length(unsigned long d) {
87+
unsigned int d_bits = 0;
88+
while (d >= 32) {
89+
d_bits += 6;
90+
d >>= 6;
91+
}
92+
d_bits += BitLengthTable[d];
93+
return d_bits;
94+
}

0 commit comments

Comments
 (0)