8000 bpo-29882: Add an efficient popcount method for integers by niklasf · Pull Request #771 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-29882: Add an efficient popcount method for integers #771

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

Merged
merged 13 commits into from
May 29, 2020
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Minor cleanups of the core code
  • Loading branch information
mdickinson committed May 27, 2020
commit 48084e75790a44f36bc61ab3488e0d118e52c476
25 changes: 14 additions & 11 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -5447,30 +5447,33 @@ static PyObject *
int_bit_count_impl(PyObject *self)
/*[clinic end generated code: output=2e571970daf1e5c3 input=a428900d3e39a606]*/
{
Py_ssize_t ndigits, i, bit_count = 0;
PyLongObject *result, *x, *y;

assert(self != NULL);
assert(PyLong_Check(self));

ndigits = Py_ABS(Py_SIZE(self));
PyLongObject *z = (PyLongObject *)self;
Py_ssize_t ndigits = Py_ABS(Py_SIZE(self));
Py_ssize_t bit_count = 0;

for (i = 0; i < ndigits && i < PY_SSIZE_T_MAX/PyLong_SHIFT; i++) {
bit_count += popcount_digit(((PyLongObject *)self)->ob_digit[i]);
/* Each digit has up to PyLong_SHIFT ones, so the accumulated bit count
from the first PY_SSIZE_T_MAX/PyLong_SHIFT digits can't overflow a
Py_ssize_t. */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice comment, thanks! Before the comment, I was surprised by the two loops.

Py_ssize_t ndigits_fast = Py_MIN(ndigits, PY_SSIZE_T_MAX/PyLong_SHIFT);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I proposed to work use size_t for bit_count, but then I realzied that i is a Py_ssize_t, so it's better to leave the code as it is: work on Py_ssize_t for i and bit_count.

for (Py_ssize_t i = 0; i < ndigits_fast; i++) {
bit_count += popcount_digit(z->ob_digit[i]);
}

result = (PyLongObject *)PyLong_FromSsize_t(bit_count);
PyObject *result = PyLong_FromSsize_t(bit_count);
if (result == NULL) {
return NULL;
}

/* Use Python integers if bit_count would overflow. */
for (; i < ndigits; i++) {
x = (PyLongObject *)PyLong_FromLong(popcount_digit(((PyLongObject *)self)->ob_digit[i]));
for (Py_ssize_t i = ndigits_fast; i < ndigits; i++) {
PyObject *x = PyLong_FromLong(popcount_digit(z->ob_digit[i]));
if (x == NULL) {
goto error;
}
y = (PyLongObject *)long_add(result, x);
PyObject *y = long_add((PyLongObject *)result, (PyLongObject *)x);
Py_DECREF(x);
if (y == NULL) {
goto error;
Expand All @@ -5479,7 +5482,7 @@ int_bit_count_impl(PyObject *self)
result = y;
}

return (PyObject *)result;
return result;

error:
Py_DECREF(result);
Expand Down
0