Bitwise Operators in Python

August 18, 2021

The following bitwise operators are available in Python:

• & (AND)
• | (OR)
• ^ (XOR)
• ~ (NOT)
• « (LEFT SHIFT)
• » (RIGHT SHIFT)

All six operators work with numbers, but rather than treating a given number as a single, numerical value, it is treated as a string of bits written in two’s complement binary. As a quick recap, this is the same as traditional binary representation for positive integers, but slightly different for negative numbers with a leading one (1) instead of a leading zero (0). In other words, two’s complement binary for positive integers looks like

• 0 is written as “0”
• 1 is written as “1”
• 2 is written as “10”
• 4 is written as “100”
• 775 is written as “1100000111”

whereas two’s complement binary for negative integers, in Python, looks like

• -1 is written as “…1111”
• -2 is written as “…1110”
• -4 is written as “…11100”
• -775 is written as “…111100000111”

The reason for the many leading 1’s is that Python no longer uses $x$-bit numbers. Instead, in pursuit of increased portability and to attain arbitrary precision, Python uses an infinite number of bits. Thanks to an implementation detail, however, Python does not actually store infinitely many bits in memory. Additionally, since an infinite string of 1s cannot be printed, it is presented with a minus sign instead. If we require a binary representation of a specific width, we can use bin() to convert an integer to binary and otherwise specify the width using modulo or bitmasking.

>>> bin(-5)
'-0b101'
>>> bin(-5 % (1 << 32))
'0b11111111111111111111111111111011'
>>> bin(-5 & 0xffffffff)
'0b11111111111111111111111111111011'


& Bitwise AND

The & operator computes a bitwise and. This means that each bit of the output is 1 iff the corresponding bit of x & y is 1, otherwise it is 0.

>>> x = 5
>>> y = 6
>>> x & y
4
>>> bin(x)
'0b101'
>>> bin(y)
'0b110'
>>> bin(x & y)
'0b100'


| Bitwise OR

The | operator computes a bitwise or. This means that each bit of the output is 0 iff the corresponding bit of x & y is 0, otherwise it is 1.

>>> x = 5
>>> y = 6
>>> x | y
7
>>> bin(x)
'0b101'
>>> bin(y)
'0b110'
>>> bin(x | y)
'0b111'


^ Bitwise XOR

The ^ operator computes a bitwise exclusive or (XOR). This means that each bit of the output is the same as the corresponding bit in x if that bit in y is 0 and it is the complement of the bit in x if that bit in y is 1.

>>> x = 5
>>> y = 6
>>> x ^ y
3
>>> bin(x)
'0b101'
>>> bin(y)
'0b110'
>>> bin(x ^ y)
'0b11'


~ Bitwise NOT

The ~ operator returns the complement of x. That is, the number we get by swapping each 1 with a 0 and vice versa. This is equivalent to computing $-x-1$.

>>> x = 5
>>> ~x
-6
>>> bin(x)
'0b101'
>>> bin(~x)
'-0b110'


<< Bitwise LEFT SHIFT

The « operator returns x with the bits shifted to the left by y places. New bits on the right-hand side will be 0’s. This is equivalent to computing $x \times 2^y$.

>>> x = 5
>>> y = 6
>>> x << y
320
>>> x * 2 ** y
320
>>> bin(x)
'0b101'
>>> bin(y)
'0b110'
>>> bin(x << y)
'0b101000000'


>> Bitwise RIGHT SHIFT

The » operator returns x with the bits shifted to the right by y places. New bits on the right-hand side will be 0’s. This is equivalent to computing $x \div 2^y$.

>>> x = 5
>>> x >> 1
2
>>> x // 2 ** 1
2
>>> bin(x)
'0b101'
>>> bin(1)
'0b1'
>>> bin(x >> 1)
'0b10'


In both « and » shifting, the sign bit is expanded and shifted when dealing with negative values. The positive and negative signs do not change, however. As noted above, negative values are considered to have an infinite number of 1’s on the left-hand side.