Objects/longobject.c (part 8)
Source:
cpython 3.14 @ ab2d84fe1023/Objects/longobject.c
This annotation covers the bit-manipulation and byte-conversion methods. See objects_longobject7_detail for division, __mod__, __pow__, and gcd.
Map
| Lines | Symbol | Role |
|---|---|---|
| 1-80 | int.bit_length | Number of bits required to represent abs(n) |
| 81-160 | int.bit_count | Number of 1-bits in abs(n) (population count) |
| 161-300 | int.to_bytes | Convert integer to a bytes object |
| 301-440 | int.from_bytes | Class method: interpret bytes as an integer |
| 441-600 | int.as_integer_ratio | Return (n, 1) for exact rational representation |
Reading
int.bit_length
// CPython: Objects/longobject.c:5880 long_bit_length
static PyObject *
long_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored))
{
/* Number of bits in abs(self), ignoring leading zeros. */
PyLongObject *a = (PyLongObject *)self;
Py_ssize_t ndigits = _PyLong_DigitCount(a);
if (ndigits == 0) return PyLong_FromLong(0);
/* Most-significant digit contributes its bit length */
digit msd = a->long_value.ob_digit[ndigits - 1];
return PyLong_FromSsize_t((ndigits - 1) * PyLong_SHIFT +
_Py_bit_length(msd));
}
(1024).bit_length() returns 11 (2^10 = 1024). Used by math.log2 and cryptographic code.
int.bit_count
// CPython: Objects/longobject.c:5940 long_bit_count
static PyObject *
long_bit_count(PyObject *self, PyObject *Py_UNUSED(ignored))
{
/* Count 1-bits in abs(self). Uses popcount per digit. */
PyLongObject *a = (PyLongObject *)self;
Py_ssize_t ndigits = _PyLong_DigitCount(a);
Py_ssize_t count = 0;
for (Py_ssize_t i = 0; i < ndigits; i++) {
count += _Py_popcount32(a->long_value.ob_digit[i]);
}
return PyLong_FromSsize_t(count);
}
(7).bit_count() returns 3 (binary 111). Added in Python 3.10. On platforms with hardware popcount, _Py_popcount32 compiles to a single POPCNT instruction.
int.to_bytes
// CPython: Objects/longobject.c:5980 long_to_bytes
static PyObject *
long_to_bytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
PyObject *kwnames)
{
/* to_bytes(length, byteorder, *, signed=False) */
Py_ssize_t length = PyLong_AsSsize_t(args[0]);
const char *byteorder = PyUnicode_AsUTF8(args[1]);
int is_signed = 0; /* from kwnames */
/* Check value fits in length bytes */
int overflow;
_PyLong_AsByteArray((PyLongObject *)self,
(unsigned char *)PyBytes_AS_STRING(result),
length, little_endian, is_signed, &overflow);
...
return result;
}
(1024).to_bytes(2, 'big') returns b'\x04\x00'. _PyLong_AsByteArray traverses the digit array in the correct byte order, handling sign extension for signed conversion.
int.from_bytes
// CPython: Objects/longobject.c:6060 long_from_bytes
static PyObject *
long_from_bytes(PyTypeObject *type, PyObject *const *args, Py_ssize_t nargs,
PyObject *kwnames)
{
/* from_bytes(bytes, byteorder, *, signed=False) — class method */
Py_buffer buf;
PyObject_GetBuffer(args[0], &buf, PyBUF_SIMPLE);
const char *byteorder = PyUnicode_AsUTF8(args[1]);
PyObject *result = _PyLong_FromByteArray(
(const unsigned char *)buf.buf, buf.len,
little_endian, is_signed);
PyBuffer_Release(&buf);
return result;
}
int.from_bytes(b'\x04\x00', 'big') returns 1024. Works with any bytes-like object via the buffer protocol.
int.as_integer_ratio
// CPython: Objects/longobject.c:6140 long_as_integer_ratio
static PyObject *
long_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored))
{
/* Always (n, 1) for integers — exact rational representation. */
return PyTuple_Pack(2, self, _PyLong_GetOne());
}
(42).as_integer_ratio() returns (42, 1). This satisfies the numbers.Rational interface, allowing integers to be used wherever a rational number is expected.
gopy notes
int.bit_length is objects.LongBitLength in objects/long_bitop.go. int.bit_count uses bits.OnesCount from Go's math/bits. int.to_bytes/from_bytes use big-endian or little-endian byte slices. int.as_integer_ratio returns a tuple (self, One).