Set, Clear, Toggle & Test a Bit
The four single-bit primitives: set with OR, clear with AND-NOT, toggle with XOR, test with AND on a shifted 1.
Overview
All single-bit manipulation is built from one mask, 1 << i, and one operator. Set bit i: x | (1 << i). Clear bit i: x & ~(1 << i). Toggle bit i: x ^ (1 << i). Test bit i: (x >> i) & 1 or (x & (1 << i)) != 0.
Two related primitives appear constantly: clear the lowest set bit with x & (x - 1) and isolate the lowest set bit with x & -x. Ranges follow the same shape: x & ((1 << k) - 1) keeps the low k bits; x | ((1 << k) - 1) sets them; x >> k << k clears them.
These operations power Bit Masks, Count Set Bits (Popcount), Fenwick Tree indexing (i & -i), and every "bit trick" that follows.
Intuition
A mental model before the formal terms.
A mask 1 << i is a stencil with a single hole at position i. OR paints through the hole (that bit becomes 1, everything else untouched). AND with the *inverted* stencil erases through the hole. XOR flips whatever is under the hole. AND with the stencil looks through the hole to see what is there.
How it works
- Build the mask
m = 1 << i— a single 1 at positioni, zeros elsewhere. - Set:
x | m. Every bit ofxsurvives (b | 0 = b) except positioni, forced to 1 (b | 1 = 1). - Clear:
x & ~m.~mis all ones except a 0 ati;b & 1 = bkeeps others,b & 0 = 0clearsi. - Toggle:
x ^ m.b ^ 0 = b,b ^ 1 = not b. - Test:
(x >> i) & 1shifts the bit of interest to position 0 and masks everything else away. - Lowest set bit:
x - 1flips the trailing zeros to ones and the lowest 1 to 0, sox & (x - 1)drops it;-xis~x + 1, which agrees withxonly at the lowest set bit, sox & -xisolates it.
Why it works
The identities b | 0 = b, b & 1 = b, b ^ 0 = b are what make each operator a no-op outside the mask, and b | 1 = 1, b & 0 = 0, b ^ 1 = ¬b are what make it act inside the mask. Because bit positions are independent there is no interaction between them.
For x & (x - 1): subtracting 1 borrows from the lowest set bit, turning it into 0 and every lower 0 into 1. Higher bits are unchanged, so ANDing keeps them and zeroes the lowest 1 and everything below (which was already 0).
Recognition
How to tell a problem wants this.
- The problem mentions the "i-th bit", "flip bit", "binary representation", or asks to update a bit in place.
- You are implementing a compact visited set, a permission system, or a flags field.
- The phrase "rightmost set bit" or "lowest set bit" appears — it is
x & -x.
Interactive visualization
Play, step, change the input. ← → and space work too.
1mask = 1 << k2set = n | mask3clear = n & ~mask4toggle = n ^ mask5test = (n >> k) & 1Pseudocode
1mask = 1 << i2set(x, i) = x | mask3clear(x, i) = x & ~mask4toggle(x, i) = x ^ mask5test(x, i) = (x >> i) & 16lowest_set(x) = x & -x7drop_lowest(x) = x & (x - 1)8low_k_bits(x, k) = x & ((1 << k) - 1)Implementations
11 · Set, clear, toggle2def set_bit(x: int, i: int) -> int:3 return x | (1 << i)4 5 6def clear_bit(x: int, i: int) -> int:7 return x & ~(1 << i)8 9 10def toggle_bit(x: int, i: int) -> int:11 return x ^ (1 << i)12 13 142 · Test and branch-free update15def test_bit(x: int, i: int) -> bool:16 return (x >> i) & 1 == 117 18 19def update_bit(x: int, i: int, value: bool) -> int:20 return (x & ~(1 << i)) | (int(value) << i)21 22 233 · Lowest-set-bit tricks24def lowest_set_bit(x: int) -> int:25 return x & -x26 27 28def drop_lowest_set_bit(x: int) -> int:29 return x & (x - 1)30 31 32def low_k_bits(x: int, k: int) -> int:33 return x & ((1 << k) - 1) # any k works: ints are unbounded34 35 364 · Demo37if __name__ == "__main__":38 x = 0b1010 # 1039 assert set_bit(x, 0) == 0b101140 assert clear_bit(x, 1) == 0b100041 assert toggle_bit(x, 3) == 0b001042 assert test_bit(x, 1) and not test_bit(x, 0)43 assert update_bit(x, 0, True) == 0b101144 assert lowest_set_bit(12) == 4 # 1100 -> 010045 assert drop_lowest_set_bit(12) == 8 # 1100 -> 100046 assert low_k_bits(0xFF, 4) == 0xF- Python ints are unbounded, so
1 << iworks for anyi, and~(1 << i)has infinitely many leading ones — harmless for&. update_bitusesint(value)to turn theboolinto0/1before shifting (aboolwould shift too, sinceboolsubclassesint).x & -xworks for negativextoo because Python negation is exact two's complement of infinite width.low_k_bitsneeds no guard;(1 << 100) - 1is a legal 100-bit mask.
O(number of digits) for huge ints; constant for values below 2^60.
- No
bitsetin the stdlib; ints as masks are the idiom.int.bit_length()gives the position of the highest set bit + 1. - Chained comparisons:
(x >> i) & 1 == 1binds as(x >> i) & (1 == 1)— here it happens to work becauseTrue == 1, but parenthesize for clarity. - Negative shift counts raise
ValueError.
- Printing
~xand expecting a bit pattern — it is a negative number; mask with(1 << w) - 1first. - Relying on
x & 1 == 0for parity: it evaluates tox & False, which is0, always falsy. - Emulating a fixed-width register and forgetting to mask after
<<.
- Bit index range: C++
uint32_tneeds1u << iwithi < 32(UB otherwise); JS/TS1 << iwrapsimod 32 and bit 31 produces a negative number; Python accepts any non-negativei. - Lowest set bit
x & -x: Python and JS work directly on signed values; in C++ prefer unsigned types (x & (0u - x)) to avoid signed-negation UB onINT_MIN. - All-ones mask of
kbits: C++/JS must guardk >= 32(1 << 32is UB in C++ and equals1in JS); Python(1 << k) - 1always works. - Precedence trap
x & 1 == 0exists in all four languages; parenthesize(x & 1) == 0.
Complexity
When to use — and when not to
- Any time a boolean flag lives inside an integer: visited masks, permission bits, packed state.
- Inside loops that enumerate set bits or strip the lowest bit — see Count Set Bits (Popcount) and Subset Generation with Bitmasks.
- Fenwick tree navigation:
i += i & -iandi -= i & -i— see Fenwick Tree.
- When a plain boolean array is clearer and the universe is not tiny — bit-packing is an optimization, not a default.
- When bit index may reach or exceed the word width;
1 << 40is256in JavaScript and undefined in C++ with 32-bit int.
Alternatives
Common mistakes
- Clearing with
x & (1 << i)instead ofx & ~(1 << i)— the former isolates the bit. - Treating the result of
x & (1 << i)as 0/1; compare with!= 0or shift first. - Zero-based vs one-based bit indexing; bit 0 is the least significant.
- In Java,
1 << 31onintis negative, andx >> 31sign-extends; use1L/>>>for a clean test.
Interview patterns
- Set/clear a bit at a given position in a stream of updates (design questions with packed state).
- Insert
mintonat bitsi..j: clear the range with a mask, then OR inm << i. - Position of the rightmost set bit:
log2(x & -x), or count trailing zeros. - Alternating bits check:
y = x ^ (x >> 1)has all ones iffxalternates; test with(y & (y + 1)) == 0.