Bit Manipulation in C++
Binary & Bits
Section titled βBinary & BitsβInteger to Binary Conversion
- Method 1: Using
bitset(fixed length only)
# include <bitset>cout << bitset<8>(18); // Output: 00010010 (8-bit)- Method 2: Custom Function (Dynamic length):
// Convert to Binarystring toBinary(int n) { if (n == 0) { return "" } string bin = ""; while (n > 0) { bin = char(n % 2 + '0') + bin; n /= 2; } return bin}
// Calling FunctiontoBinary(num); // output 1010Find the number of bits required to Represent a decimal number
int countBits(int n) { int count = 0; while (n > 0) { count++; // n = n>>1 n >>= 1; // right shift by n by 1 bit, and Assign the shifted value back to `n` } return count;}Bit Manipulation
Section titled βBit ManipulationβBit Manipulation Property: XOR from 0 to x
Section titled βBit Manipulation Property: XOR from 0 to xβ- When you compute the XOR of all numbers from
0tox:0β1β2β...βx0 - It follows a repeating pattern based on the value of
x % 4.
Key Property
- The result of XOR from
0toxdepends onx % 4:
int xorFrom0ToX(int x) { if (x % 4 == 0) return x; // x if x % 4 == 0 if (x % 4 == 1) return 1; // 1 if x % 4 == 1 if (x % 4 == 2) return x + 1; // x + 1 if x % 4 == 2 return 0; // 0 if x % 4 == 3}Explanation of the Pattern: The XOR result forms a cyclic pattern with a period of 4:
- For
x % 4 == 0: XOR(0,1,2,β¦,x) = x - For
x % 4 == 1: XOR(0,1,2,β¦,x) = 1 - For
x % 4 == 2: XOR(0,1,2,β¦,x) = x + 1 - For
x % 4 == 3: XOR(0,1,2,β¦,x) = 0
Visual Pattern: For values from 0 to 7
x = 0 β 0 β 0 % 4 == 0 β 0x = 1 β 0^1 β 1 % 4 == 1 β 1x = 2 β 0^1^2 β 2 % 4 == 2 β 3x = 3 β 0^1^2^3 β 3 % 4 == 3 β 0
x = 4 β 0^1^2^3^4 β 4 % 4 == 0 β 4x = 5 β 0^1^2^3^4^5 β 5 % 4 == 1 β 1x = 6 β 0^1^2^3^4^5^6 β 6 % 4 == 2 β 7x = 7 β 0^1^2^3^4^5^6^7 β 7 % 4 == 3 β 0Mathematical Reason: The XOR from 0 to x behaves cyclically because:
- XOR properties:
aβa = 0aβ0 = a
- The pairs cancel out periodically every
4numbers, creating a cycle.
Use Cases
- Finding if XOR from
0toxequalsx:
if (xorFrom0ToX(x) == x) { cout << x << " is beautiful" << endl;}- Efficient XOR range calculation:
- Instead of iterating from
0tox(O(N) time complexity), this formula allows you to compute it in O(1) time.
Time Complexity Analysis
- Naive Method: O(N) for iterating through
0tox - Optimized Method: O(1) using
x % 4pattern
Bit Manipulation β Complete Guide with All Important Properties and Tricks
Section titled βBit Manipulation β Complete Guide with All Important Properties and TricksβBasic Bitwise Operators
Section titled βBasic Bitwise OperatorsβBitwise operations manipulate individual bits of integers.
| Operator | Symbol | Operation | Example (x = 5, y = 3) |
|---|---|---|---|
| AND | & | Bitwise AND | 5 & 3 = 1 (101 & 011 = 001) |
| OR | | | Bitwise OR | 5 | 3 = 7 (101 | 011 = 111) |
| XOR | ^ | Bitwise XOR | 5 ^ 3 = 6 (101 ^ 011 = 110) |
| NOT | ~ | Bitwise Complement (Flip bits) | ~5 = -6 (Inverts bits) |
| Left Shift | << | Shifts bits to the left | 5 << 1 = 10 (101 β 1010) |
| Right Shift | >> | Shifts bits to the right | 5 >> 1 = 2 (101 β 10) |
Bitwise AND &
- AND sets bits to
1only if both bits are1. - Properties:
a & 0 = 0a & 1 = a(bit remains the same)a & a = aa & ~a = 0
- β
Use cases:
-
Checking if a number is even/odd:
if (x & 1) cout << "Odd"; // LSB = 1 β oddelse cout << "Even"; // LSB = 0 β even
-
Bitwise OR |
-
OR sets bits to
1if either of the bits is1. -
Properties:
a | 0 = aa | 1 = 1a | a = aa | ~a = ~0(all bits set to 1)
-
Use cases: Setting specific bits
x = 5; // `101`x = x | (1 << 1); // Sets the 2nd bit β `111` (7)
Bitwise XOR ^
-
XOR sets bits to
1if the bits are different. -
Properties:
a ^ 0 = aa ^ 1 = ~aa ^ a = 0a ^ ~a = ~0
-
Use cases: Swapping two numbers without a temp variable
int a = 5, b = 7;a = a ^ b;b = a ^ b; // Now b = 5a = a ^ b; // Now a = 7
Bitwise NOT ~
-
NOT flips all bits of a number.
-
Properties:
~0 = -1~a = -a - 1(twoβs complement)
-
Use cases: Finding negative of a number
int x = 5;cout << ~x; // Output: -6
Left Shift <<
-
Shifts bits to the left, filling with
0on the right. -
Properties:
a << nreturns the left-shifted value ofabynpositions but does not change the value ofa.a << nsamea * (2^n)
-
Use cases: Multiplying by powers of 2
int x = 5; // `101`cout << (x << 1); // `1010` β 10
Right Shift >>
-
Shifts bits to the right.
-
Properties:
a << nreturns the right-shifted value ofabynpositions but does not change the value ofa.a >> nsame asa / (2^n)
-
Use cases: Dividing by powers of 2
int x = 10; // `1010`cout << (x >> 1); // `101` β 5
Masking and Clearing Bits
- Masking β Set or check specific bits using AND.
- Clearing β Clear specific bits using AND with NOT.
// Masking (checking if the 2nd bit is set)int x = 5; // `101`if (x & (1 << 1)) cout << "2nd bit is set";
// Clearing (resetting the 2nd bit)x = x & ~(1 << 1); // `101` β `001` (1)Toggle Bits
- Toggle a bit using XOR with
1:
int x = 5; // `101`x = x ^ (1 << 1); // Toggle the 2nd bit β `111` (7)10. Checking Powers of 2
- A power of
2has only 1 bit set.
bool isPowerOfTwo(int x) { return (x && !(x & (x - 1)));}Counting Set Bits (__builtin_popcount)
#include <iostream>using namespace std;
int main() { int x = 7; // `111` cout << __builtin_popcount(x); // Output: 3 return 0;}Checking the Parity (Even/Odd Set Bits)
- Use XOR:
bool isOddParity(int x) { return (__builtin_popcount(x) & 1);}Reverse Bits
uint32_t reverseBits(uint32_t n) { uint32_t res = 0; for (int i = 0; i < 32; i++) { res = (res << 1) | (n & 1); n >>= 1; } return res;}Isolating the Rightmost 1
int isolateRightmostOne(int x) { return x & (-x);}Clearing the Rightmost 1
int clearRightmostOne(int x) { return x & (x - 1);}Setting the Rightmost 0
int setRightmostZero(int x) { return x | (x + 1);}Rounding Up to the Next Power of 2
int nextPowerOfTwo(int n) { n--; n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; return n + 1;}Bit Manipulation in STL
__builtin_clz(x)β Count leading zeros__builtin_ctz(x)β Count trailing zeros__builtin_popcount(x)β Count set bits__builtin_parity(x)β Parity of set bits