Skip to content

Commit 7b4198c

Browse files
committed
bpo-31031: Unify duplicate bits_in_digit and bit_length
1 parent 5ae299a commit 7b4198c

File tree

4 files changed

+35
-54
lines changed

4 files changed

+35
-54
lines changed

Include/pymath.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,4 +227,12 @@ PyAPI_FUNC(void) _Py_set_387controlword(unsigned short);
227227
* behavior. */
228228
#define _Py_InIntegralTypeRange(type, v) (_Py_IntegralTypeMin(type) <= v && v <= _Py_IntegralTypeMax(type))
229229

230+
/* Return the smallest integer k such that n < 2**k, or 0 if n == 0.
231+
* Equivalent to floor(log2(x))+1. Also equivalent to: bitwidth_of_type -
232+
* count_leading_zero_bits(x)
233+
*/
234+
#ifndef Py_LIMITED_API
235+
PyAPI_FUNC(unsigned int) _Py_bit_length(unsigned long d);
236+
#endif
237+
230238
#endif /* Py_PYMATH_H */

Modules/mathmodule.c

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,28 +1443,6 @@ math_fsum(PyObject *module, PyObject *seq)
14431443
#undef NUM_PARTIALS
14441444

14451445

1446-
/* Return the smallest integer k such that n < 2**k, or 0 if n == 0.
1447-
* Equivalent to floor(lg(x))+1. Also equivalent to: bitwidth_of_type -
1448-
* count_leading_zero_bits(x)
1449-
*/
1450-
1451-
/* XXX: This routine does more or less the same thing as
1452-
* bits_in_digit() in Objects/longobject.c. Someday it would be nice to
1453-
* consolidate them. On BSD, there's a library function called fls()
1454-
* that we could use, and GCC provides __builtin_clz().
1455-
*/
1456-
1457-
static unsigned long
1458-
bit_length(unsigned long n)
1459-
{
1460-
unsigned long len = 0;
1461-
while (n != 0) {
1462-
++len;
1463-
n >>= 1;
1464-
}
1465-
return len;
1466-
}
1467-
14681446
static unsigned long
14691447
count_set_bits(unsigned long n)
14701448
{
@@ -1879,7 +1857,7 @@ factorial_partial_product(unsigned long start, unsigned long stop,
18791857
/* find midpoint of range(start, stop), rounded up to next odd number. */
18801858
midpoint = (start + num_operands) | 1;
18811859
left = factorial_partial_product(start, midpoint,
1882-
bit_length(midpoint - 2));
1860+
_Py_bit_length(midpoint - 2));
18831861
if (left == NULL)
18841862
goto error;
18851863
right = factorial_partial_product(midpoint, stop, max_bits);
@@ -1909,7 +1887,7 @@ factorial_odd_part(unsigned long n)
19091887
Py_INCREF(outer);
19101888

19111889
upper = 3;
1912-
for (i = bit_length(n) - 2; i >= 0; i--) {
1890+
for (i = _Py_bit_length(n) - 2; i >= 0; i--) {
19131891
v = n >> i;
19141892
if (v <= 2)
19151893
continue;
@@ -1919,7 +1897,7 @@ factorial_odd_part(unsigned long n)
19191897
/* Here inner is the product of all odd integers j in the range (0,
19201898
n/2**(i+1)]. The factorial_partial_product call below gives the
19211899
product of all odd integers j in the range (n/2**(i+1), n/2**i]. */
1922-
partial = factorial_partial_product(lower, upper, bit_length(upper-2));
1900+
partial = factorial_partial_product(lower, upper, _Py_bit_length(upper-2));
19231901
/* inner *= partial */
19241902
if (partial == NULL)
19251903
goto error;

Objects/longobject.c

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

790-
/* bits_in_digit(d) returns the unique integer k such that 2**(k-1) <= d <
791-
2**k if d is nonzero, else 0. */
792-
793-
static const unsigned char BitLengthTable[32] = {
794-
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
795-
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
796-
};
797-
798-
static int
799-
bits_in_digit(digit d)
800-
{
801-
int d_bits = 0;
802-
while (d >= 32) {
803-
d_bits += 6;
804-
d >>= 6;
805-
}
806-
d_bits += (int)BitLengthTable[d];
807-
return d_bits;
808-
}
809-
810790
size_t
811791
_PyLong_NumBits(PyObject *vv)
812792
{
@@ -824,7 +804,7 @@ _PyLong_NumBits(PyObject *vv)
824804
if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT)
825805
goto Overflow;
826806
result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT;
827-
msd_bits = bits_in_digit(msd);
807+
msd_bits = _Py_bit_length(msd);
828808
if (SIZE_MAX - msd_bits < result)
829809
goto Overflow;
830810
result += msd_bits;
@@ -1985,7 +1965,7 @@ long_format_binary(PyObject *aa, int base, int alternate,
19851965
return -1;
19861966
}
19871967
size_a_in_bits = (size_a - 1) * PyLong_SHIFT +
1988-
bits_in_digit(a->ob_digit[size_a - 1]);
1968+
_Py_bit_length(a->ob_digit[size_a - 1]);
19891969
/* Allow 1 character for a '-' sign. */
19901970
sz = negative + (size_a_in_bits + (bits - 1)) / bits;
19911971
}
@@ -2805,7 +2785,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem)
28052785

28062786
/* normalize: shift w1 left so that its top digit is >= PyLong_BASE/2.
28072787
shift v1 left by the same amount. Results go into w and v. */
2808-
d = PyLong_SHIFT - bits_in_digit(w1->ob_digit[size_w-1]);
2788+
d = PyLong_SHIFT - _Py_bit_length(w1->ob_digit[size_w-1]);
28092789
carry = v_lshift(w->ob_digit, w1->ob_digit, size_w, d);
28102790
assert(carry == 0);
28112791
carry = v_lshift(v->ob_digit, v1->ob_digit, size_v, d);
@@ -2926,7 +2906,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e)
29262906
*e = 0;
29272907
return 0.0;
29282908
}
2929-
a_bits = bits_in_digit(a->ob_digit[a_size-1]);
2909+
a_bits = _Py_bit_length(a->ob_digit[a_size-1]);
29302910
/* The following is an overflow-free version of the check
29312911
"if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */
29322912
if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 &&
@@ -4020,8 +4000,8 @@ long_true_divide(PyObject *v, PyObject *w)
40204000
/* Extreme underflow */
40214001
goto underflow_or_zero;
40224002
/* Next line is now safe from overflowing a Py_ssize_t */
4023-
diff = diff * PyLong_SHIFT + bits_in_digit(a->ob_digit[a_size - 1]) -
4024-
bits_in_digit(b->ob_digit[b_size - 1]);
4003+
diff = diff * PyLong_SHIFT + _Py_bit_length(a->ob_digit[a_size - 1]) -
4004+
_Py_bit_length(b->ob_digit[b_size - 1]);
40254005
/* Now diff = a_bits - b_bits. */
40264006
if (diff > DBL_MAX_EXP)
40274007
goto overflow;
@@ -4097,7 +4077,7 @@ long_true_divide(PyObject *v, PyObject *w)
40974077
}
40984078
x_size = Py_ABS(Py_SIZE(x));
40994079
assert(x_size > 0); /* result of division is never zero */
4100-
x_bits = (x_size-1)*PyLong_SHIFT+bits_in_digit(x->ob_digit[x_size-1]);
4080+
x_bits = (x_size-1)*PyLong_SHIFT+_Py_bit_length(x->ob_digit[x_size-1]);
41014081

41024082
/* The number of extra bits that have to be rounded away. */
41034083
extra_bits = Py_MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG;
@@ -4805,7 +4785,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg)
48054785
alloc_b = Py_SIZE(b);
48064786
/* reduce until a fits into 2 digits */
48074787
while ((size_a = Py_SIZE(a)) > 2) {
4808-
nbits = bits_in_digit(a->ob_digit[size_a-1]);
4788+
nbits = _Py_bit_length(a->ob_digit[size_a-1]);
48094789
/* extract top 2*PyLong_SHIFT bits of a into x, along with
48104790
corresponding bits of b into y */
48114791
size_b = Py_SIZE(b);
@@ -5322,7 +5302,7 @@ int_bit_length_impl(PyObject *self)
53225302
return PyLong_FromLong(0);
53235303

53245304
msd = ((PyLongObject *)self)->ob_digit[ndigits-1];
5325-
msd_bits = bits_in_digit(msd);
5305+
msd_bits = _Py_bit_length(msd);
53265306

53275307
if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT)
53285308
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
@@ -79,3 +79,18 @@ round(double x)
7979
return copysign(y, x);
8080
}
8181
#endif /* HAVE_ROUND */
82+
83+
static const unsigned int BitLengthTable[32] = {
84+
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4,
85+
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5
86+
};
87+
88+
unsigned int _Py_bit_length(unsigned long d) {
89+
unsigned int d_bits = 0;
90+
while (d >= 32) {
91+
d_bits += 6;
92+
d >>= 6;
93+
}
94+
d_bits += BitLengthTable[d];
95+
return d_bits;
96+
}

0 commit comments

Comments
 (0)