there are many reasons to manipulate bits even in high level languages like python. However this note will mostly be about bitmasking.

Why?

Nothing is more efficient than bit manipulation. Most of the times, it happens under the hood, but sometimes you gotta do it yourself.

Combinations with caching

The bitarraysused below are mutable objects and can therefore not be hashed/cached. However you can send over the strings (of 0s and 1s) and convert those inside of that function to be able to cache that function. It is less efficient though. To remedy this, consider using the inbuilt type "byte" https://www.w3schools.com/python/ref_func_bytes.asp which is immutable.

converting data like characters to bits/bitmasks usually leads to more generic operation, that will repeat over and over again. Caching them can therefore be interesting.

Bit-masking

Imagine you have a binary value, and you want to isolate just a few specific bits. By creating a mask, another binary number where bits are set to 0 where you want to keep information and 0 where you don't, you can use a bitwise and operation to extract only those bits.

Example:

Pasted image 20241218161225.png

remember, bool(1) = True and bool(0) = False

Pasted image 20241218161441.png

Implementation (in python)

{shell} pip install bitarray

from bitarray import bitarray

ba = bitarray('1100101')

Bitwise AND:

a = bitarray('1100')
b = bitarray('1010')

result = a & b
print(result)

Bitwise OR:

a = bitarray('1100')
b = bitarray('1010')

result = a | b

Bit shifts

this is where it gets interesting from an efficiency standpoint. Instead of multiplying a really high number by 2^n arithmetically, we are using encoding properties to do it instantly.
def leftshift(ba, count):
    return ba[count:] + (bitarray('0') * count)

def rightshift(ba, count):
    return (bitarray('0') * count) + ba[:-count]

def leftshiftfromindex(ba, count, start_index):
	# we are adding zeroes (effectively leftshifting) in the middle.
	return ba[0:start_index] + (bitarray('0') * count) + ba[start_index:]
I needed the leftshiftfrom index for a specific task where I was padding bitmasks, but you should consider why you need this even, usually there's no reason to bitshift in the center of bitarrays