Skip to main content

Objects/longobject.c (part 10)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/longobject.c

This annotation covers integer byte and bit operations. See objects_longobject9_detail for int.__pow__, int.__mod__, integer division, and compact int representation.

Map

LinesSymbolRole
1-80int.bit_lengthNumber of bits in the absolute value
81-180int.bit_countPopulation count (number of set bits)
181-300int.to_bytesSerialize to big/little-endian bytes
301-420int.from_bytesDeserialize from bytes
421-500PyLong_AsNativeBytesExport integer as C-native bytes (PEP 757)

Reading

int.bit_length

// CPython: Objects/longobject.c:3480 long_bit_length
static PyObject *
long_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored))
{
/* Number of bits needed to represent |self| in binary, excluding sign. */
PyLongObject *z = (PyLongObject *)self;
Py_ssize_t ndigits = _PyLong_DigitCount(z);
if (ndigits == 0) return PyLong_FromLong(0);
/* Most significant digit determines the bit count */
digit msd = z->long_value.ob_digit[ndigits - 1];
int msd_bits = _Py_bit_length(msd);
return PyLong_FromSsize_t((ndigits - 1) * PyLong_SHIFT + msd_bits);
}

(1024).bit_length() returns 11. (0).bit_length() returns 0. The most significant digit determines the final bit count; other digits contribute PyLong_SHIFT (30) bits each.

int.bit_count

// CPython: Objects/longobject.c:3560 long_bit_count
static PyObject *
long_bit_count(PyObject *self, PyObject *Py_UNUSED(ignored))
{
/* Population count: number of 1-bits in |self| */
PyLongObject *z = (PyLongObject *)self;
Py_ssize_t ndigits = _PyLong_DigitCount(z);
Py_ssize_t count = 0;
for (Py_ssize_t i = 0; i < ndigits; i++) {
count += _Py_popcount(z->long_value.ob_digit[i]);
}
return PyLong_FromSsize_t(count);
}

(255).bit_count() returns 8. Uses _Py_popcount which maps to the hardware POPCNT instruction on x86-64.

int.to_bytes

// CPython: Objects/longobject.c:3680 long_to_bytes
static PyObject *
long_to_bytes_impl(PyObject *self, Py_ssize_t length, PyObject *byteorder_obj,
int signed_)
{
/* Convert integer to exactly 'length' bytes in the specified byte order.
Raises OverflowError if the integer doesn't fit. */
int little_endian = (byteorder == "little");
PyObject *bytes = PyBytes_FromStringAndSize(NULL, length);
_PyLong_AsByteArray((PyLongObject *)self, (unsigned char *)buf,
length, little_endian, signed_);
return bytes;
}

(256).to_bytes(2, 'big') returns b'\x01\x00'. (256).to_bytes(1, 'big') raises OverflowError. signed=True uses two's complement representation.

gopy notes

int.bit_length is objects.LongBitLength in objects/long.go. It uses bits.Len on the most significant word. int.bit_count uses bits.OnesCount. int.to_bytes converts via big.Int.Bytes() then reverses for little-endian. int.from_bytes uses big.Int.SetBytes().