Bit tricks look like magic until you write the numbers out in binary. Each one below includes the expression, a short explanation, and an 8-bit example you can reproduce in the Binary Bitwise Calculator. They appear in coding interviews, but they also show up in real code: allocators, hash tables, graphics, compression, and kernels.

The examples assume unsigned integers unless stated otherwise.

1. Check if a Number Is Even or Odd

bool odd = n & 1;

Bit 0 is the only bit with an odd place value. 46 = 00101110 ends in 0, so it is even.

2. Check if a Number Is a Power of Two

bool pow2 = n != 0 && (n & (n - 1)) == 0;

A power of two has exactly one 1 bit. Subtracting 1 turns that bit into 0 and every bit below it into 1, so the AND is zero:

n     = 00100000  (32)
n - 1 = 00011111  (31)
AND   = 00000000

For any other number, a higher 1 bit survives the AND.

3. Clear the Lowest Set Bit

n &= n - 1;

The same n − 1 effect, applied to any number. 46 = 00101110 becomes 00101100 (44). Repeating this until n is zero counts the 1 bits, a method known as Kernighan’s algorithm:

int popcount(unsigned n) {
    int count = 0;
    while (n) { n &= n - 1; count++; }
    return count;
}

It loops once per set bit rather than once per bit.

4. Isolate the Lowest Set Bit

unsigned low = n & -n;     /* or n & (~n + 1) */

In two’s complement, −n is ~n + 1. All bits above the lowest 1 are inverted, so only that one bit survives the AND. 46 & −46 = 2. Fenwick trees (binary indexed trees) use this to jump between nodes.

5. Set, Clear, Toggle, and Test Bit k

n |=  (1u << k);           /* set    */
n &= ~(1u << k);           /* clear  */
n ^=  (1u << k);           /* toggle */
bool on = (n >> k) & 1;    /* test   */

These are the four mask operations covered in the Bit Masking Guide.

6. Swap Two Variables With XOR

a ^= b; b ^= a; a ^= b;

It works because XOR is its own inverse. It is a nice puzzle, but in practice a temporary variable is clearer and at least as fast. It also zeroes the value if a and b are the same variable.

7. Check if Two Integers Have Opposite Signs

bool opposite = (a ^ b) < 0;    /* signed ints */

XOR sets the sign bit of the result only when the two sign bits differ.

8. Absolute Value Without Branching

int mask = x >> 31;             /* 0 for x >= 0, -1 for x < 0 (32-bit int) */
int absx = (x + mask) ^ mask;

For negative x, adding −1 and then XORing with all ones is the same as ~(x − 1), which equals −x. This relies on arithmetic right shift of negative values, which is implementation-defined in C (though universal in practice). Modern compilers generate branchless code from abs() anyway, so treat this as a learning exercise.

9. Round Up to the Next Power of Two

uint32_t next_pow2(uint32_t v) {
    v--;
    v |= v >> 1;  v |= v >> 2;  v |= v >> 4;
    v |= v >> 8;  v |= v >> 16;
    return v + 1;
}

The OR cascade copies the highest 1 bit into every position below it, producing a run like 00111111. Adding 1 gives the next power of two. next_pow2(46) returns 64. Hash tables and memory allocators use this to size buckets.

10. Modulo by a Power of Two

unsigned r = n & (size - 1);    /* same as n % size when size is a power of two */

46 & 7 = 6, and 46 % 8 = 6. Ring buffers rely on this to wrap their indexes without division.

11. Enumerate All Subsets of a Set

Represent each subset of n items as an n-bit mask. Counting from 0 to 2^n − 1 visits every subset:

items = ["a", "b", "c"]
for mask in range(1 << len(items)):
    subset = [items[i] for i in range(len(items)) if mask >> i & 1]
    print(f"{mask:03b}", subset)

This prints 8 lines, from 000 [] to 111 ['a', 'b', 'c']. Dynamic-programming solutions over subsets (“bitmask DP”) use exactly this representation.

12. Get the Index of the Highest or Lowest Set Bit

Most compilers and languages expose hardware instructions for these:

TaskC / C++ (GCC, Clang)C++20Python
count 1 bits__builtin_popcount(x)std::popcount(x)x.bit_count()
trailing zeros__builtin_ctz(x)std::countr_zero(x)(x & -x).bit_length() - 1
leading zeros__builtin_clz(x)std::countl_zero(x)32 - x.bit_length()

Use these instead of loops when performance matters. Note that the GCC builtins are undefined for x == 0.

When to Use Bit Tricks

Bit tricks are worth using when they make code shorter and clearer to someone who knows the idiom, such as n & (n − 1) for power-of-two checks, or when profiling shows a real hot spot. They are not worth it when they hide intent. Compilers already turn n % 8 into n & 7 and n * 4 into n << 2 for unsigned values.

A good habit: when you use a trick, add a one-line comment naming it, and test it at the edges (zero, one, the maximum value, and negative numbers for signed types). The Bitwise Calculator is a quick way to check those edge cases at a fixed width.