Two's complement, explained
Binary has no minus sign. Two's complement is the convention nearly all hardware
uses to represent negative integers — and once you see why it was chosen, several
confusing things (like −1 being 0xFF) become obvious.
The problem: where does the sign go?
With 8 bits you can write 256 patterns. If you want negative numbers, you must spend some patterns on them. The naive idea — reserve the top bit as a sign flag and keep the rest as magnitude — creates two zeros (+0 and −0) and breaks ordinary addition. Two's complement fixes both.
The rule
To negate a number: invert every bit, then add one. For −42 in 8 bits:
- 42 = 0010 1010
- invert → 1101 0101
- +1 → 1101 0110 = -42
The top bit still tells you the sign — patterns starting with 1 are negative —
but it isn't just a flag: it carries the value −2⁷. Formally, in 8 bits the leading
bit is worth −128 and the rest are positive powers of two:
1101 0110 = −128 + 64 + 16 + 4 + 2 = −42.
Why −1 is all ones
- 1 = 0000 0001
- invert → 1111 1110
- +1 → 1111 1111 = -1
That's why −1 prints as 0xFF in a byte, 0xFFFFFFFF in
32 bits, and 0xFFFFFFFFFFFFFFFF in 64. Same idea, wider register.
Why hardware loves it
Addition just works: -42 + 50 is plain binary addition of
1101 0110 + 0011 0010, carry falls off the end, result
0000 1000 = 8. No special circuitry for signs, no minus-zero.
Subtraction becomes "negate and add".
Overflow: the range is asymmetric
8 bits hold −128…127. Note the asymmetry: −128 exists but +128 doesn't. If you add
127 + 1 in signed 8-bit arithmetic you wrap to −128 — that's signed
overflow, and it's the kind of bug that hides until the worst moment. The
HexCalculator app checks 64-bit overflow on every operation and shows an error
instead of a silently wrapped result.
One pattern, two meanings
1101 0110 is −42 signed and 214 unsigned. Bits don't know which one
you mean — the interpretation is yours. Try it in the
two's complement calculator: it shows both
readings side by side for any width from 8 to 64 bits.
Sign extension
Widening a signed value copies the sign bit into the new bits:
−42 goes from 1101 0110 (8-bit) to
1111 1111 1101 0110 (16-bit). Widening an unsigned value pads with
zeros. Mixing those two up is a classic source of "why is my number suddenly huge"
bugs when casting in C.
Keep exploring
- Two's complement calculator — every example above, interactive.
- Bitwise operations explained — AND, OR, XOR and shifts on these patterns.
- Hex calculator — 64-bit signed/unsigned arithmetic with overflow detection.