Bitwise Operations¶
Since integers are stored in binary, Python allows bitwise operations to manipulate individual bits.
Basic Operators¶
Python provides six bitwise operators for bit-level manipulation.
1. AND (&)¶
Sets each bit to 1 if both bits are 1.
x = 5 # 0b0101
y = 3 # 0b0011
print(x & y) # Bitwise AND: 1 (0b0101 & 0b0011 = 0b0001)
Example: 5 & 3 results in 1 (binary 101 & 011 is 001).
2. OR (|)¶
Sets each bit to 1 if one of the bits is 1.
x = 5 # 0b0101
y = 3 # 0b0011
print(x | y) # Bitwise OR: 7 (0b0101 | 0b0011 = 0b0111)
Example: 5 | 3 results in 7 (binary 101 | 011 is 111).
3. XOR (^)¶
Sets each bit to 1 if only one of the bits is 1.
x = 5 # 0b0101
y = 3 # 0b0011
print(x ^ y) # Bitwise XOR: 6 (0b0101 ^ 0b0011 = 0b0110)
Example: 5 ^ 3 results in 6 (binary 101 ^ 011 is 110).
4. NOT (~)¶
Inverts all the bits.
x = 5 # 0b0101
print(~x) # Bitwise NOT: -6
Example: ~5 results in -6 (binary ~00000101 is 11111010 in two's complement).
5. Left Shift (<<)¶
Shifts the bits to the left, adding zeros on the right.
x = 5 # 0b0101
print(x << 1) # Left shift: 10 (0b0101 << 1 = 0b1010)
Example: 5 << 1 results in 10 (binary 101 becomes 1010).
6. Right Shift (>>)¶
Shifts the bits to the right, discarding bits shifted off.
x = 5 # 0b0101
print(x >> 1) # Right shift: 2 (0b0101 >> 1 = 0b0010)
Example: 5 >> 1 results in 2 (binary 101 becomes 010).
Practical Usage¶
Bitwise operations are useful for bit-level manipulations and optimizations.
1. Set Bit¶
# Set bit at position pos
n |= (1 << pos)
2. Clear Bit¶
# Clear bit at position pos
n &= ~(1 << pos)
3. Toggle Bit¶
# Toggle bit at position pos
n ^= (1 << pos)
4. Check Bit¶
# Check if bit at position pos is set
is_set = n & (1 << pos) != 0
5. Masking¶
# Extract the lower 4 bits
lower_4_bits = n & 0b1111
AND Examples¶
Bitwise AND with positive and negative integers.
1. Positive AND¶
What is the output?
print(f"{10 & 5 = }")
Solution:
print(f"{10 & 5 = }") # Output: 10 & 5 = 0
2. Negative AND¶
What is the output?
print(f"{10 & -5 = }")
Solution:
print(f"{10 & -5 = }") # Output: 10 & -5 = 10
OR Examples¶
Bitwise OR with positive and negative integers.
1. Positive OR¶
What is the output?
print(f"{10 | 5 = }")
Solution:
print(f"{10 | 5 = }") # Output: 10 | 5 = 15
2. Negative OR¶
What is the output?
print(f"{10 | -5 = }")
Solution:
print(f"{10 | -5 = }") # Output: 10 | -5 = -5
XOR Examples¶
Bitwise XOR with positive and negative integers.
1. Positive XOR¶
What is the output?
print(f"{10 ^ 5 = }")
Solution:
print(f"{10 ^ 5 = }") # Output: 10 ^ 5 = 15
2. Negative XOR¶
What is the output?
print(f"{10 ^ -5 = }")
Solution:
print(f"{10 ^ -5 = }") # Output: 10 ^ -5 = -15
NOT Examples¶
Bitwise NOT with different integer types.
1. Regular NOT¶
What is the output?
print(f"{~ 10 = }")
Solution:
print(f"{~ 10 = }") # Output: ~ 10 = -11
2. NumPy uint8¶
What is the output?
print(f"{~ np.array(10, dtype=np.uint8) = }")
Solution:
print(f"{~ np.array(10, dtype=np.uint8) = }") # Output: 245
3. NumPy uint16¶
What is the output?
print(f"{~ np.array(10, dtype=np.uint16) = }")
Solution:
print(f"{~ np.array(10, dtype=np.uint16) = }") # Output: 65525
Right Shift¶
Right shift discards bits shifted off the right end.
1. Positive Shift¶
What is the output?
print(5 >> 1)
print(5 >> 2)
print(5 >> 3)
Solution:
print(5 >> 1) # Output: 2
print(5 >> 2) # Output: 1
print(5 >> 3) # Output: 0
2. Negative Shift¶
What is the output?
print(-5 >> 1)
print(-5 >> 2)
print(-5 >> 3)
Solution:
print(-5 >> 1) # Output: -3
print(-5 >> 2) # Output: -2
print(-5 >> 3) # Output: -1
Left Shift¶
Left shift adds zeros on the right, effectively multiplying by powers of 2.
1. Positive Shift¶
What is the output?
print(5 << 1)
print(5 << 2)
print(5 << 3)
Solution:
print(5 << 1) # Output: 10
print(5 << 2) # Output: 20
print(5 << 3) # Output: 40
2. Negative Shift¶
What is the output?
print(-5 << 1)
print(-5 << 2)
print(-5 << 3)
Solution:
print(-5 << 1) # Output: -10
print(-5 << 2) # Output: -20
print(-5 << 3) # Output: -30
Practical Examples¶
Real-world applications of bitwise operations.
1. Array Sizing¶
def main():
for n in range(4):
memo = [-1] * (1 << (n+1))
print(memo)
if __name__ == "__main__":
main()
2. XOR Swap¶
Swap two variables without a temporary variable.
What is the output?
a = 4
b = 3
print(f"{a = }, {b = }")
a = a ^ b
b = a ^ b
a = a ^ b
print(f"{a = }, {b = }")
Solution:
def main():
a = 4
b = 3
print(f"{a = }, {b = }")
a = a ^ b
b = a ^ b
a = a ^ b
print(f"{a = }, {b = }")
if __name__ == "__main__":
main()
3. Count Bits¶
Count the number of bits in an integer.
What is the output?
def func(num):
count = 0
while num:
count += 1
num >>= 1
return count
def main():
print(f"{func(435)}")
if __name__ == "__main__":
main()
Solution:
def func(num):
count = 0
while num:
count += 1
num >>= 1
return count
def main():
print(f"{func(435)}") # Output: 9
if __name__ == "__main__":
main()
Conclusion¶
Understanding bitwise operations is essential for low-level programming, optimizing performance, and working with hardware and embedded systems. These operations provide efficient ways to manipulate individual bits for tasks like setting flags, masking, and performing fast arithmetic.