Interview Prep Zoneby CuriouserLabs

Question 1 of 5 · senior level

How are integers represented in hardware? Explain two's complement and why overflow behaves the way it does.

🎤 Say this first

Two's complement represents −x as ~x + 1, which makes the top bit act as −2ⁿ⁻¹ and — the reason it won — lets one adder circuit handle signed and unsigned addition identically; subtraction is 'negate and add'. The ranges are asymmetric (int: −2³¹ … 2³¹−1), so −Integer.MIN_VALUE overflows to itself (Math.abs can return a negative number!). Overflow is silent wraparound in Java (defined behavior, mod 2³²) — the famous consequence: (low + high) / 2 breaks at ~2³¹ elements, a bug that sat in the JDK's own binary search for a decade. When money or safety is involved: Math.addExact, longs, or BigDecimal.

The full picture

The greatest hits of silent wraparound
Math.abs(Integer.MIN_VALUE)      // -2147483648  (still negative!)
Integer.MAX_VALUE + 1            // Integer.MIN_VALUE — wrap, no exception

int mid = (low + high) / 2;      // overflows for low+high > 2^31-1
int mid = low + (high - low) / 2;            // classic fix
int mid = (low + high) >>> 1;                // JDK's fix: unsigned shift

// The senior toolkit:
Math.addExact(a, b)              // throws ArithmeticException on overflow
Math.toIntExact(longValue)       // narrowing with a guard
Long.compareUnsigned(a, b)       // unsigned views without an unsigned type
  • Why two's complement beat sign-magnitude/ones' complement: single zero (no +0/−0), and addition is the same wires regardless of sign — the hardware-simplicity argument that decided it, worth stating as such.
  • Sign extension and narrowing: (byte) 200 → −56; widening a negative byte drags the sign bit — the source of 'why is my parsed byte negative' bugs in binary protocol code; mask with & 0xFF when treating bytes as unsigned.
  • Language contrast for depth: Java defines wrap; C makes signed overflow undefined (compilers delete your overflow checks!); Rust panics in debug and wraps explicitly (wrapping_add) in release — three philosophies about the same circuit.
  • Hash-adjacent trivia that connects: Integer.MIN_VALUE's asymmetry is why careful code writes x == Integer.MIN_VALUE guards in abs/negate paths (see Math.negateExact).

🔄 Likely follow-up questions

  • Why does C treat signed overflow as undefined when the hardware wraps?
  • How would you implement saturating arithmetic for a metrics counter?
  • What does (a & 0xFF) actually do and when do you need it?