Python Bitwise Operators on Arbitrary-Precision Integers

Python supports arbitrary-precision integers, meaning numbers can grow as large as available memory allows without suffering from integer overflow. When applying bitwise operators such as XOR (^), AND (&), OR (|), and bit-shifts (<<, >>), Python does not use fixed-width 32-bit or 64-bit registers. Instead, it computes results by simulating a conceptually infinite two's complement binary representation, dynamically allocating memory for the resulting digits.

The Infinite Two's Complement Model

In languages like C, bitwise operations manipulate fixed-size memory registers. If you perform a bitwise NOT or shift beyond 64 bits, bits fall off the edge or wrap around.

Python avoids fixed boundaries by conceptualizing integers as having an infinite number of sign bits extending to the left:

This conceptual model ensures that operations like ~x (bitwise NOT) yield mathematically consistent results: ~x is always equal to -x - 1.

How Python Handles XOR (^)

Bitwise XOR returns 1 where the bits of two operands differ, and 0 where they match.

How Python Handles Bit-Shifting

Bit-shifting adjusts the magnitude of the integer while adjusting the underlying memory layout:

Left Shift (<<)

Left-shifting a number by n places (x << n) is mathematically equivalent to multiplying by \(2^n\).

Right Shift (>>)

Right-shifting a number by n places (x >> n) performs an arithmetic right shift, equivalent to floor division by \(2^n\) (floor(x / 2**n)).

CPython's Internal Mechanism

Under the hood, CPython's int structure (PyLongObject) stores integers using a sign-magnitude representation rather than native two's complement. It holds an array of unsigned digits paired with a separate sign indicator.

To execute bitwise operations correctly:

  1. CPython converts negative operands from sign-magnitude into an on-the-fly two's complement format.
  2. It processes the digits sequentially starting from the least significant digit up to the size of the larger operand.
  3. Once the bitwise logic finishes, CPython normalizes the output back into its native sign-magnitude format, stripping away redundant leading digits.