So for starters bit manipulation is doing operations on binary form of a number one could ask why would we need that, under the hood all decimal looking operations occur in binary
There are 6 major operations:
- AND(&): This returns true if everything is true.
- OR(|): This returns true if anything is true.
- XOR(^): This return true if there are odd trues.
- NOT(~): This returns the complement (1 if 0 and vise-versa).
- RIGHT SHIFT(>>k): Divides(floor) the number by 2, k times, shifts bits by k positions to the right.
- LEFT SHIFT(<<K): Multiplies the number by 2, k times, shifts bits by k positions to the left.
Common tasks that one has to do:
- SET bit i: x |= (1ULL<<i);
your doing or with (00000100000) where this thing has bit i set. - CLEAR bit i: x &= ~(1ULL<<i);
your doing and with (11111011111) where this thing has all bits set but i. - TOGGLE bit i: x ^= (1ULL<<i);
your doing or with (00000100000) where this thing has bit i set. - CHECK bit i: x&(1ULL<<i)!=0;
your doing and with (00000100000) where this thing has bit i set and checking if resultant is 0 or not.
CAUTION USE BELOW AFTER CHECKING NOT 0 - ISOLATE LOWEST SET bit: x & (-x);
This works because -x is stored as (~x+1) in twos complement.
So if x = 1011000, ~x = 0100111, then -x = (~x+1) = 0101000, x & (~x) = 0001000 - CLEAR LOWEST SET bit: x & (x-1);
This works because when we subtract 1 from a number LSB becomes 0 and 0's to the right become 1
So if x = 1011000, x-1 = 1010111 , then x&(x-1) = 1010000
Builtin functions in cpp that are a life saver:
- __builtin_popcountll(x): gives the number of set bits in x.
- __builtin_ctzll(x): gives number of 0's on right of LSB , undefined if x==0.
- __builtin_clzll(x): gives number of 0's on the left of MSB , undefined if x==0.
- __builtin_parity(x): gives 1 if odd 1's are present else 0.







