Skip to content
Merged
18 changes: 18 additions & 0 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,24 @@ class`. In addition, it provides a few more methods:

.. versionadded:: 3.1

.. method:: int.bit_count()

Return the number of ones in the binary representation of the absolute
value of the integer::

>>> n = -19
>>> bin(n)
'-0b10011'
>>> n.bit_count()
3

Equivalent to::

def bit_count(self):
return bin(self).count("1")

.. versionadded:: 3.10

.. method:: int.to_bytes(length, byteorder, \*, signed=False)

Return an array of bytes representing an integer.
Expand Down
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ New Features
Other Language Changes
======================

* The :class:`int` type has a new method :meth:`int.bit_count`, returning the
number of ones in the binary expansion of a given integer, also known
as the population count. (Contributed by Niklas Fiekas in :issue:`29882`.)


New Modules
Expand Down
3 changes: 2 additions & 1 deletion Lib/test/test_doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -669,7 +669,7 @@ def non_Python_modules(): r"""
True
>>> real_tests = [t for t in tests if len(t.examples) > 0]
>>> len(real_tests) # objects that actually have doctests
13
14
>>> for t in real_tests:
... print('{} {}'.format(len(t.examples), t.name))
...
Expand All @@ -682,6 +682,7 @@ def non_Python_modules(): r"""
1 builtins.hex
1 builtins.int
3 builtins.int.as_integer_ratio
2 builtins.int.bit_count
2 builtins.int.bit_length
5 builtins.memoryview.hex
1 builtins.oct
Expand Down
11 changes: 11 additions & 0 deletions Lib/test/test_long.py
Original file line number Diff line number Diff line change
Expand Up @@ -1016,6 +1016,17 @@ def test_bit_length(self):
self.assertEqual((a+1).bit_length(), i+1)
self.assertEqual((-a-1).bit_length(), i+1)

def test_bit_count(self):
for a in range(-1000, 1000):
self.assertEqual(a.bit_count(), bin(a).count("1"))

for exp in [10, 17, 63, 64, 65, 1009, 70234, 1234567]:
a = 2**exp
self.assertEqual(a.bit_count(), 1)
self.assertEqual((a - 1).bit_count(), exp)
self.assertEqual((a ^ 63).bit_count(), 7)
self.assertEqual(((a - 1) ^ 510).bit_count(), exp - 8)

def test_round(self):
# check round-half-even algorithm. For round to nearest ten;
# rounding map is invariant under adding multiples of 20
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :meth:`int.bit_count()`, counting the number of ones in the binary
representation of an integer. Patch by Niklas Fiekas.
25 changes: 24 additions & 1 deletion Objects/clinic/longobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

65 changes: 65 additions & 0 deletions Objects/longobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -811,6 +811,17 @@ _PyLong_Sign(PyObject *vv)
return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1);
}

static int
popcount_digit(digit d)
{
/* 32bit SWAR popcount. */
uint32_t u = d;
u -= (u >> 1) & 0x55555555;
u = (u & 0x33333333) + ((u >> 2) & 0x33333333);
u = (u + (u >> 4)) & 0x0f0f0f0f;
return (u * 0x01010101) >> 24;
}

size_t
_PyLong_NumBits(PyObject *vv)
{
Expand Down Expand Up @@ -5421,6 +5432,59 @@ int_bit_length_impl(PyObject *self)
return NULL;
}

/*[clinic input]
int.bit_count

Number of ones in the binary representation of self.

>>> bin(13)
'0b1101'
>>> (13).bit_count()
3
[clinic start generated code]*/

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));

for (i = 0; i < ndigits && i < PY_SSIZE_T_MAX/PyLong_SHIFT; i++) {
bit_count += popcount_digit(((PyLongObject *)self)->ob_digit[i]);
}

result = (PyLongObject *)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]));
if (x == NULL) {
goto error;
}
y = (PyLongObject *)long_add(result, x);
Py_DECREF(x);
if (y == NULL) {
goto error;
}
Py_DECREF(result);
result = y;
}

return (PyObject *)result;

error:
Py_DECREF(result);
return NULL;
}

/*[clinic input]
int.as_integer_ratio
Expand Down Expand Up @@ -5577,6 +5641,7 @@ static PyMethodDef long_methods[] = {
{"conjugate", long_long_meth, METH_NOARGS,
"Returns self, the complex conjugate of any int."},
INT_BIT_LENGTH_METHODDEF
INT_BIT_COUNT_METHODDEF
INT_TO_BYTES_METHODDEF
INT_FROM_BYTES_METHODDEF
INT_AS_INTEGER_RATIO_METHODDEF
Expand Down