Skip to main content

Objects/longobject.c (part 12)

Source:

cpython 3.14 @ ab2d84fe1023/Objects/longobject.c

This annotation covers conversion and the numeric protocol. See objects_longobject11_detail for bit_length, bit_count, to_bytes, from_bytes.

Map

LinesSymbolRole
1-80int.as_integer_ratioReturn (self, 1) for use in float-like operations
81-160int.__index__Return self for use as sequence index or slice
161-260PyLong_AsLongExtract a C long; raise OverflowError on out-of-range
261-380PyLong_AsDoubleExtract a C double; raise OverflowError for large ints
381-500PyLong_AsUnsignedLong / _AsSize_tUnsigned conversions

Reading

int.as_integer_ratio

// CPython: Objects/longobject.c:4220 long_as_integer_ratio
static PyObject *
long_as_integer_ratio(PyObject *self, PyObject *Py_UNUSED(ignored))
{
/* Integers are exact rationals: n/1 */
return PyTuple_Pack(2, self, _PyLong_GetOne());
}

int.as_integer_ratio() returns (self, 1). This matches float.as_integer_ratio() signature and allows code like Fraction(x) to work uniformly for both int and float inputs. Fraction(3) calls as_integer_ratio() and gets (3, 1).

int.__index__

// CPython: Objects/longobject.c:4280 long___index___impl
static PyObject *
long___index___impl(PyObject *self)
{
/* __index__ is required for use as a sequence index.
For plain int, just return self (already an int).
For int subclasses, convert to plain int. */
if (PyLong_CheckExact(self)) {
return Py_NewRef(self);
}
return _PyLong_Copy((PyLongObject *)self);
}

__index__ is called by list.__getitem__, range, struct.pack, etc. when they require an integer index. numpy.int64.__index__ makes NumPy integers usable as list indices.

PyLong_AsLong

// CPython: Objects/longobject.c:760 PyLong_AsLong
long
PyLong_AsLong(PyObject *vv)
{
PyLongObject *v = (PyLongObject *)vv;
/* Check for compact representation first */
if (_PyLong_IsCompact(v)) {
stwodigits x = _PyLong_CompactValue(v);
if ((long)x == x) return (long)x;
/* Compact but too large for C long: fall through */
}
/* Multi-digit path */
...
if (overflow) {
PyErr_SetString(PyExc_OverflowError,
"Python int too large to convert to C long");
return -1;
}
return result;
}

PyLong_AsLong is the most common C API function. The compact fast path handles small integers in one branch. PyLong_AsLong(PyLong_FromLong(42)) should be essentially free.

PyLong_AsDouble

// CPython: Objects/longobject.c:880 PyLong_AsDouble
double
PyLong_AsDouble(PyObject *vv)
{
if (_PyLong_IsCompact((PyLongObject *)vv)) {
return (double)_PyLong_CompactValue((PyLongObject *)vv);
}
/* Multi-digit: use _PyLong_Frexp to get (mantissa, exponent) */
double x;
int e;
x = _PyLong_Frexp((PyLongObject *)vv, &e);
if (e > DBL_MAX_EXP) {
PyErr_SetString(PyExc_OverflowError,
"int too large to convert to float");
return -1.0;
}
return ldexp(x, e);
}

PyLong_AsDouble raises OverflowError for integers larger than DBL_MAX (~1.8e308). For integers near DBL_MAX, ldexp(mantissa, exponent) computes the double value with correct rounding.

gopy notes

int.as_integer_ratio is objects.LongAsIntegerRatio in objects/long.go. int.__index__ returns self for LongObject or copies for subclasses. PyLong_AsLong is objects.LongAsLong using big.Int.Int64 with overflow check. PyLong_AsDouble uses big.Float.Float64.