Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
bpo-29782: Consolidate _Py_Bit_Length()#20739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
281009c65abb83ce45ff26464ca60bd4265fbaca66436f68bac664bc3279d17525da3de487622a3387615a146f78e3ce6686241f6c7ccbe2dfceaf2fbf01ae991622b462d99598fc7a8File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -7,8 +7,8 @@ | ||
| - _Py_bswap64(uint64_t) | ||
| */ | ||
| #ifndef Py_INTERNAL_BSWAP_H | ||
| #define Py_INTERNAL_BSWAP_H | ||
| #ifndef Py_INTERNAL_BITUTILS_H | ||
| #define Py_INTERNAL_BITUTILS_H | ||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
| @@ -131,8 +131,47 @@ _Py_popcount32(uint32_t x) | ||
| } | ||
| // Return the index of the most significant 1 bit in 'x'. This is the smallest | ||
| // integer k such that x < 2**k. Equivalent to floor(log2(x)) + 1 for x != 0. | ||
| static inline int | ||
| _Py_bit_length(unsigned long x) | ||
| { | ||
| #if (defined(__clang__) || defined(__GNUC__)) | ||
| if (x != 0) { | ||
| // __builtin_clzl() is available since GCC 3.4. | ||
| // Undefined behavior for x == 0. | ||
| return (int)sizeof(unsigned long) * 8 - __builtin_clzl(x); | ||
| } | ||
| else { | ||
| return 0; | ||
| } | ||
| #elif defined(_MSC_VER) | ||
| // _BitScanReverse() is documented to search 32 bits. | ||
| Py_BUILD_ASSERT(sizeof(unsigned long) <= 4); | ||
niklasf marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| unsigned long msb; | ||
| if (_BitScanReverse(&msb, x)) { | ||
| return (int)msb + 1; | ||
| } | ||
| else { | ||
| return 0; | ||
| } | ||
| #else | ||
| const int BIT_LENGTH_TABLE[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 | ||
| }; | ||
| int msb = 0; | ||
| while (x >= 32) { | ||
| msb += 6; | ||
| x >>= 6; | ||
| } | ||
| msb += BIT_LENGTH_TABLE[x]; | ||
| return msb; | ||
vstinner marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| #endif | ||
| } | ||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
| #endif /* !Py_INTERNAL_BSWAP_H */ | ||
| #endif /* !Py_INTERNAL_BITUTILS_H */ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -53,6 +53,7 @@ raised for division by zero and mod by zero. | ||
| */ | ||
| #include "Python.h" | ||
| #include "pycore_bitutils.h" // _Py_bit_length() | ||
| #include "pycore_dtoa.h" | ||
| #include "_math.h" | ||
niklasf marked this conversation as resolved.
Outdated
Uh oh!There was an error while loading. Please reload this page. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -695,6 +695,13 @@ _PyLong_Sign(PyObject *vv) | ||
| return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); | ||
| } | ||
| static int | ||
| bit_length_digit(digit x) | ||
| { | ||
| Py_BUILD_ASSERT(PyLong_SHIFT <= sizeof(unsigned long) * 8); | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice if C provided some standard way to get the width (in the sense of C99 §6.2.6.2p6) of an integer type, so that we didn't have to use | ||
| return _Py_bit_length((unsigned long)x); | ||
| } | ||
| size_t | ||
| _PyLong_NumBits(PyObject *vv) | ||
| { | ||
| @@ -712,7 +719,7 @@ _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; | ||
| msd_bits = _Py_bit_length(msd); | ||
| msd_bits = bit_length_digit(msd); | ||
| if (SIZE_MAX - msd_bits < result) | ||
| goto Overflow; | ||
| result += msd_bits; | ||
| @@ -1822,7 +1829,7 @@ long_format_binary(PyObject *aa, int base, int alternate, | ||
| return -1; | ||
| } | ||
| size_a_in_bits = (size_a - 1) * PyLong_SHIFT + | ||
| _Py_bit_length(a->ob_digit[size_a - 1]); | ||
| bit_length_digit(a->ob_digit[size_a - 1]); | ||
| /* Allow 1 character for a '-' sign. */ | ||
| sz = negative + (size_a_in_bits + (bits - 1)) / bits; | ||
| } | ||
| @@ -2642,7 +2649,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) | ||
| /* normalize: shift w1 left so that its top digit is >= PyLong_BASE/2. | ||
| shift v1 left by the same amount. Results go into w and v. */ | ||
| d = PyLong_SHIFT - _Py_bit_length(w1->ob_digit[size_w-1]); | ||
| d = PyLong_SHIFT - bit_length_digit(w1->ob_digit[size_w-1]); | ||
| carry = v_lshift(w->ob_digit, w1->ob_digit, size_w, d); | ||
| assert(carry == 0); | ||
| carry = v_lshift(v->ob_digit, v1->ob_digit, size_v, d); | ||
| @@ -2764,7 +2771,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) | ||
| *e = 0; | ||
| return 0.0; | ||
| } | ||
| a_bits = _Py_bit_length(a->ob_digit[a_size-1]); | ||
| a_bits = bit_length_digit(a->ob_digit[a_size-1]); | ||
| /* The following is an overflow-free version of the check | ||
| "if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */ | ||
| if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 && | ||
| @@ -3857,8 +3864,8 @@ long_true_divide(PyObject *v, PyObject *w) | ||
| /* Extreme underflow */ | ||
| goto underflow_or_zero; | ||
| /* Next line is now safe from overflowing a Py_ssize_t */ | ||
| diff = diff * PyLong_SHIFT + _Py_bit_length(a->ob_digit[a_size - 1]) - | ||
| _Py_bit_length(b->ob_digit[b_size - 1]); | ||
| diff = diff * PyLong_SHIFT + bit_length_digit(a->ob_digit[a_size - 1]) - | ||
| bit_length_digit(b->ob_digit[b_size - 1]); | ||
| /* Now diff = a_bits - b_bits. */ | ||
| if (diff > DBL_MAX_EXP) | ||
| goto overflow; | ||
| @@ -3934,7 +3941,7 @@ long_true_divide(PyObject *v, PyObject *w) | ||
| } | ||
| x_size = Py_ABS(Py_SIZE(x)); | ||
| assert(x_size > 0); /* result of division is never zero */ | ||
| x_bits = (x_size-1)*PyLong_SHIFT+_Py_bit_length(x->ob_digit[x_size-1]); | ||
| x_bits = (x_size-1)*PyLong_SHIFT+bit_length_digit(x->ob_digit[x_size-1]); | ||
| /* The number of extra bits that have to be rounded away. */ | ||
| extra_bits = Py_MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG; | ||
| @@ -4748,7 +4755,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) | ||
| alloc_b = Py_SIZE(b); | ||
| /* reduce until a fits into 2 digits */ | ||
| while ((size_a = Py_SIZE(a)) > 2) { | ||
| nbits = _Py_bit_length(a->ob_digit[size_a-1]); | ||
| nbits = bit_length_digit(a->ob_digit[size_a-1]); | ||
| /* extract top 2*PyLong_SHIFT bits of a into x, along with | ||
| corresponding bits of b into y */ | ||
| size_b = Py_SIZE(b); | ||
| @@ -5269,7 +5276,7 @@ int_bit_length_impl(PyObject *self) | ||
| return PyLong_FromLong(0); | ||
| msd = ((PyLongObject *)self)->ob_digit[ndigits-1]; | ||
| msd_bits = _Py_bit_length(msd); | ||
| msd_bits = bit_length_digit(msd); | ||
| if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) | ||
| return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits); | ||
Uh oh!
There was an error while loading. Please reload this page.