Bit Operators

On this page 16

Part I — Foundations · Interview reference

Bitwise operators manipulate individual bits of integer values. Seniors are expected to read flag-heavy APIs, reason about masks/shifts correctly (including sign and overflow), and know when bit tricks are justified versus premature cleverness.


Core operators (must know cold)

OperatorNameMeaningTypical use
&ANDBit set only if set in bothMask / clear / test flags
|ORBit set if set in eitherCombine / set flags
^XORBit set if differentToggle; parity; swap without temp (rarely needed)
~NOTFlip all bitsForm masks; one’s complement pitfalls with signed types
<<Left shiftMultiply by 2ⁿ (unsigned view)Build masks; pack fields
>>Arithmetic right shiftSign-extends (most languages)Signed division by 2ⁿ (careful with negatives)
>>>Logical right shiftZero-fills (Java/JS)Treat value as unsigned bit pattern

Identity / algebra worth memorizing

  • x & 0 = 0, x | 0 = x, x 0 = x, x x = 0
  • x & x = x, x | x = x
  • De Morgan: (a & b) (a | b), (a | b) (a & b) (within fixed width)

Mental models

Flags and masks

Treat an integer as a set of independent booleans packed into bits.

flags |=  MASK;     // set bits in MASK
flags &= ~MASK;     // clear bits in MASK
flags ^=  MASK;     // toggle bits in MASK
bool on = (flags & MASK) != 0;  // test (any)
bool all = (flags & MASK) == MASK; // test (all)

Prefer named constants / enum bitfields over magic numbers. Document which bit means what and whether the API is additive (|) or exclusive.

Packing / unpacking fields

// pack: value in bits [lo, hi)
packed = (packed & ~mask) | ((field << shift) & mask);

// unpack
field = (packed >> shift) & ((1 << width) - 1);

Watch signed shift and width overflow when width == word_size.

Production case study (high volume)

Context: A multi-tenant SaaS API (~50M authz checks/day) packs role + resource-scope capabilities into a 64-bit bitfield carried on every request (similar to Discord’s permission integers or AWS IAM action bitsets in custom PDPs). Why seniors care: A wrong mask silently grants/denies at p99 scale; concurrent flags |= MASK without atomics loses updates under fan-out; signed >> on “unsigned” capability words corrupts high bits. Failure / symptom: Intermittent privilege escalation after a “toggle capability” deploy; metrics show CAS failure spikes on AtomicLong; dumps show plain int RMW on a shared session object. Resolution: Named static final long masks; AtomicLong.getAndUpdate for concurrent updates; property tests for set/clear/test; document MSB numbering and endianness for any cross-service packing. Seen at / similar to: Discord permission bitfields; game/anti-cheat flag packs; Redis BITFIELD / presence bitmaps at Twitter-scale timelines historically.

Two’s complement (interview trap)

  • Negation: -x == (~x) + 1
  • Sign bit is MSB; arithmetic >> preserves it
  • INT_MIN negation overflows in two’s complement; abs/min discussions fail here

Common idioms seniors should recognize

IdiomExpressionNotes
Power of two?(x & (x - 1)) 0 (and x > 0)Classic; fails for x 0
Isolate lowest set bitx & -xTwo’s complement
Clear lowest set bitx & (x - 1)Trailing-zero / popcount loops
Round up to power of 2bit-smear then +1Off-by-one on already-power-of-2
Swap without tempa = b; b = a; a ^= bAvoid; hurts readability; fails if a/b alias same location poorly in some langs
Absolute value (branchless)mask = x >> 31; (x ^ mask) - maskSigned 32-bit; still breaks on INT_MIN
Endian / byte extractshifts + 0xFF masksNetwork byte order conversions

Production case study (high volume)

Context: Ad-exchange / fraud pipeline (~billions of membership tests/day) uses Bloom filters and Roaring bitmaps for “seen device / creative ID” before hitting a KV store. Why seniors care: Wrong popcount/clear-lowest-bit loops on the hot path waste CPU; false-positive rate is a cost knob (extra origin fetches); bitset cardinality bugs show up as revenue leakage, not unit-test failures. Failure / symptom: CPU saturation on filter update threads; p99 spike when filters resized; elevated origin QPS from underestimated FPR after cardinality grew 10×. Resolution: Hardware popcnt / JDK Long.bitCount intrinsified paths; size filters from measured cardinality + target FPR; move presence sets to Roaring/Guava; load-test membership + update together. Seen at / similar to: Ad platforms (Google/Meta-style edge filters); CDN/WAF IP reputation sets; Cassandra/HBase-style Bloom use in LSM read paths.


Language / platform gotchas

TopicExpectation
Signed vs unsignedC/C++: promotion and shift of signed negatives are easy UB/implementation-defined traps. Prefer unsigned for bit ops.
JavaNo unsigned types historically; use >>>, Integer.toUnsignedLong, mask with 0xffffffffL.
WidthShifting by ≥ word size is UB in C; Java masks shift count (& 0x1f / & 0x3f).
FloatsBit ops on floats require reinterpretation (memcpy / bit cast); NaN/endian issues.
SIMD / popcountPrefer hardware popcnt, tzcnt, lzcnt / language intrinsics over hand loops when performance matters.

Java under the hood

ToolWhat it is underneath
Shift countJVM masks: int shifts & 0x1f, long & 0x3f — no UB, but surprising wrap
Integer / Long helpersbitCount, numberOfLeadingZeros, numberOfTrailingZeros, rotateLeft/Right, highestOneBit — HotSpot often intrinsifies to popcnt / lzcnt / tzcnt
Unsigned viewInteger.toUnsignedLong, Integer.divideUnsigned, >>> for logical right shift
BitSetPacked long[] words; grow on demand; good for sparse-ish flag sets over large domains
EnumSetBit vector indexed by enum ordinal — extremely cheap membership for small enums
Concurrent flagsAtomicInteger / AtomicLong bitwise getAndUpdate / updateAndGet (CAS loop) — plain | on a shared int is not thread-safe
Wide integersBigInteger for arbitrary-width bits (heap-backed magnitude array; not a substitute for hot-path masks)
Float bitsFloat.floatToIntBits / Double.doubleToLongBits (and raw variants) for reinterpretation

Prefer named static final int masks or EnumSet over magic numbers. For concurrent bitfields, use atomics — see thread safety.

Production case study (high volume)

Context: Payments risk service on HotSpot evaluates millions of rule flags/sec using EnumSet for rule categories and BitSet for sparse “rule fired” vectors exported to analytics. Why seniors care: EnumSet is a bit vector — seniors must know why it beats HashSet<Enum> under allocation pressure; concurrent plain BitSet is not safe; GC/alloc from boxing kills p99. Failure / symptom: Young-gen thrash and elevated TLAB refill rate after switching flags to HashSet; intermittent lost flag bits under parallel rule evaluation. Resolution: Keep hot-path flags as EnumSet/BitSet copies per request (confine), merge with atomics or thread-local builders; JFR allocation samples confirm the win. Seen at / similar to: Stripe/Adyen-style rules engines; feature-flag packs in large JVM monoliths (Shopify Core historically).


When bit operators belong in production

Use when

  • Protocol / file formats with packed fields
  • Permission / capability flags
  • Bloom filters, bitsets, succinct structures
  • Low-level hashing, CRC, crypto primitives (usually via library)
  • Cache-friendly presence sets (Roaring bitmaps, etc.)

Avoid when

  • Business logic that is clearer with EnumSet, booleans, or small structs
  • “Clever” optimizations without measured hotspots
  • Cross-language APIs without a documented bit layout and endianness

Complexity & performance notes

  • Bit ops are O(1) on machine words; bitsets over n bits are O(n/word_size)
  • Branchless bit tricks can beat branches or lose (branch predictors are good; data dependencies hurt)
  • False clarity cost often exceeds CPU savings — interviewers notice judgment here

What interviewers probe

  1. Explain (n & (n - 1)) and edge cases (0, negatives).
  2. Signed right shift vs logical — and which language you are in.
  3. Set / clear / toggle / test a flag correctly without clobbering others.
  4. Endianness when packing multi-byte fields for the network.
  5. Why bit packing might be wrong for a mutable concurrent flags field (atomicity of RMW, visibility) — link to thread safety.
  6. Count set bits — naive loop vs Kernighan vs hardware popcount; complexity.
  7. Production bitset/Bloom — how FPR and concurrent updates show up in cost and correctness SLOs.

Senior-level expectation: Correctness + clear naming + knowing when not to use bit tricks. Being able to whiteboard a permission mask API and discuss concurrent updates (AtomicInteger bit CAS loops). Tie bit packing to blast radius of authz bugs at millions of checks/day.


Pitfalls checklist

  • Testing flags with == MASK when you meant “any bit”
  • Using ~ without masking back to intended width
  • Arithmetic shift on values you thought were unsigned
  • Shifting into / through the sign bit unexpectedly
  • Assuming left shift cannot overflow silently
  • Documenting bit 0 as “first” without saying MSB vs LSB numbering
  • Using XOR swap or branchless abs in interview code when clarity matters more
  • Plain | / &= on shared flags under concurrency (need atomics)
  • Shipping Bloom filters without sizing for actual cardinality growth

Cross-references

Interview reference — explanation quality and judgment, not syntax memorization.