Bit Manipulation Basics Every Developer Should Know
Bit manipulation uses operators like AND, OR, XOR, and shifts to work directly on binary representations — the basics behind flags, masks, and fast math.
Bit manipulation is the direct use of a value’s binary representation to perform operations — combining flags, checking individual bits, or doing arithmetic — using operators like AND, OR, XOR, NOT, and bit shifts. It’s lower-level than most day-to-day application code needs, but it shows up constantly underneath: permission flags, hash functions, compact data structures, and performance-critical loops all lean on it.
The basic operators
Every mainstream language exposes the same core set of bitwise operators, working on the binary digits of an integer directly:
- AND (
&) — each result bit is 1 only if both input bits are 1. Used to check or clear specific bits. - OR (
|) — each result bit is 1 if either input bit is 1. Used to set specific bits. - XOR (
^) — each result bit is 1 if exactly one input bit is 1. Used to toggle bits and, notably, to swap values without a temporary variable. - NOT (
~) — flips every bit. On signed integers this also flips the sign due to two’s complement representation. - Left shift (
<<) — shifts bits left, filling with zeros. Equivalent to multiplying by a power of two. - Right shift (
>>) — shifts bits right. For signed integers, this typically preserves the sign bit (arithmetic shift); an unsigned right shift (>>>in JavaScript) fills with zeros regardless of sign.
Reading and setting individual bits
A single integer can pack many independent true/false flags, one per bit, instead of using a separate boolean for each:
Bit position: 7 6 5 4 3 2 1 0
Value 0b00000101 has bits 0 and 2 set.
To check whether bit n is set, AND the value with a mask that has only bit n set:
const isSet = (value, n) => (value & (1 << n)) !== 0;
To set bit n, OR it in:
const setBit = (value, n) => value | (1 << n);
To clear bit n, AND with the inverse of the mask:
const clearBit = (value, n) => value & ~(1 << n);
To toggle bit n, XOR it:
const toggleBit = (value, n) => value ^ (1 << n);
This pattern — a set of named bit positions combined with bitwise OR — is how permission flags and configuration options are frequently represented in systems programming, protocol headers, and file formats: one integer instead of a dozen booleans, checked and combined with a handful of fast operations.
Why shifts are multiplication and division
Because binary is positional just like decimal, shifting digits left multiplies by the base, and shifting right divides by it. In binary, the base is 2, so x << n is equivalent to x * 2^n, and x >> n is equivalent to integer division by 2^n. This used to be a common manual optimization, since a shift is typically a single, very fast CPU instruction. Modern compilers already perform this substitution automatically when they can prove it’s safe, so hand-writing shifts for multiplication mostly hurts readability today without a real performance win — it remains useful to know because it explains why the operation is fast, and it still matters in contexts like embedded or kernel code where you’re working close to the hardware.
XOR’s most useful property
XOR has a property that makes it disproportionately useful: a ^ a = 0, and a ^ 0 = a, and XOR is both commutative and associative. This is the basis of the classic swap-without-a-temp trick:
a = a ^ b;
b = a ^ b; // b is now the original a
a = a ^ b; // a is now the original b
More practically, this same property underlies “find the element that appears an odd number of times” interview problems, simple checksums, and one-time-pad style encryption, where the same key XORed twice recovers the original data.
Where this shows up in real systems
Bit manipulation isn’t just an interview topic — it’s load-bearing in several places you’re likely to encounter directly:
- Bloom filters set and check individual bits across a large bit array using hash functions, trading a small false-positive rate for extremely compact set-membership tests.
- Hash functions frequently use shifts and XOR to mix bits and spread input values evenly across the output range, which matters for how well a hash table distributes keys across its buckets.
- Networking and file formats pack multiple fields into a single byte or word — IP header flags, image format metadata — and bitwise operators are how you read and write them.
- Low-level performance code, including SIMD-style batch operations, relies on bitwise tricks to process many values in fewer instructions; see SIMD and vectorization for the broader technique this supports.
The takeaway
Bit manipulation is a small set of operators — AND, OR, XOR, NOT, and shifts — applied directly to a value’s binary representation. The individual operations are simple, but they compose into powerful, compact patterns: packing many flags into one integer, swapping values without extra memory, and building space-efficient structures like bloom filters. You won’t reach for it in most application code, but recognizing the pattern is what lets you understand what’s actually happening in the systems built on top of it.
Keep reading
The Lycoris Team · · 4 min read The KMP Algorithm: Fast String Matching Explained
The Knuth-Morris-Pratt algorithm finds a pattern inside a text in linear time by never re-examining characters it has already matched.
The Lycoris Team · · 5 min read What Is a Ring Buffer?
A ring buffer is a fixed-size array that wraps its read and write pointers around, giving O(1) enqueue and dequeue without ever resizing.
The Lycoris Team · · 5 min read Fenwick Trees (Binary Indexed Trees), Explained
A Fenwick tree, or binary indexed tree, answers prefix-sum queries and point updates in O(log n) with far less memory than a segment tree.