Digital · Signed numbers · 7 min

How Computers Store Negative Numbers: Sign-Magnitude vs One’s vs Two’s Complement

Binary digits are just 0s and 1s — there is no minus sign. To store a negative number you have to encode the sign into the bits themselves, and over the years three schemes were used: sign-magnitude, one’s complement, and two’s complement. Two’s complement won — it has a single zero and lets a CPU subtract using the same adder it uses to add. This guide walks all three with one consistent 4-bit and 8-bit example, then sends the bit patterns to the Two’s Complement Calculator.

The problem: no minus sign

A byte is just a row of bits — eight cells that each hold 0 or 1. Nothing in there is a "−". So to represent a negative integer we dedicate the most-significant bit (MSB) — the leftmost one — as the sign bit: 0 means positive, 1 means negative. The interesting question is what the remaining bits mean once you have decided the sign. Three historic answers exist, and they disagree on exactly how a negative value is laid out.

Sign-magnitude

The simplest idea: the MSB is the sign, and the remaining bits are the plain unsigned magnitude. So in 4 bits:

The range for n bits is symmetric: −(2^(n−1) − 1) … +(2^(n−1) − 1), which for 8 bits is −127 … +127. Two problems sink it. First, there are two zeros: 0000 is +0 and 1000 is −0 — the same numeric value with two bit patterns, wasting a code and forcing equality checks to handle both. Second, addition has to special-case the sign (you have to inspect the sign bits and decide whether to add or subtract magnitudes), which is awkward in hardware.

One’s complement

One’s complement keeps the MSB as the sign but defines negation as flipping every bit (a bitwise NOT). Starting from +5 = 0101, invert each bit:

The range is the same as sign-magnitude: −127 … +127 for 8 bits. And it still has two zeros0000 (+0) and 1111 (−0), since flipping all the zeros gives all ones. Addition is closer to "normal" than sign-magnitude, but a carry off the top must be wrapped back around (the end-around carry), and the duplicate zero remains. Almost there, but not quite.

Two’s complement (the winner)

Two’s complement makes one tiny change to one’s complement that fixes everything: to negate, flip all the bits AND add 1 (invert, then +1). Worked through in 4 bits:

The operation is its own inverse, so negating −5 gives back +5: invert 10110100, add 1 → 0101 = +5. Three properties make this the encoding every modern CPU uses — they are the whole point:

Side-by-side comparison

The same set of 4-bit values under all three encodings. Note that −0 exists only in sign-magnitude and one’s complement (two’s complement has a single zero), and the most-negative value −8 exists only in two’s complement:

Value (4-bit)Sign-magnitudeOne’s complementTwo’s complement
+5010101010101
−5110110101011
+0000000000000
−010001111— none —
−8 (most negative)— n/a —— n/a —1000
+7 (most positive)011101110111

⚠️ Read the table carefully: −5 is 1101 in sign-magnitude, 1010 in one’s complement, but 1011 in two’s complement. Same number, three different bit patterns — which is exactly why you must know which encoding you are looking at before decoding a raw byte.

Negating & reading by hand

To negate a two’s-complement number: invert every bit and add 1. To read a negative two’s-complement value you have two reliable options:

You rarely need to do this by hand twice. The Two’s Complement Calculator converts in either direction for any bit width, the Number Base Converter shows the underlying bit pattern (and how the same bits read as unsigned vs signed), and the Binary Add / Subtract Calculator demonstrates that subtraction is just addition of the complement. For the conversion mechanics between bases, the sibling guide Binary, Hex & Decimal Conversion walks the nibble trick.

In practice: signed char & 0xFF

This is not academic. In C, a signed char is an 8-bit two’s-complement integer, so it runs −128…+127. Increment +127 (0111_1111) and it wraps to 1000_0000 = −128 — the classic signed overflow. And one byte, 1111_1111, prints as 255 when interpreted unsigned but −1 when interpreted as signed two’s complement: same bits, two interpretations. Whenever you see a value flip from a large positive to a negative (or 0xFF showing up as −1), this encoding is the reason.

One boundary so you don’t over-generalize: floating-point negatives are not two’s complement. IEEE 754 floats use a dedicated sign bit with a sign-magnitude-like layout (which is why IEEE 754 has both +0.0 and −0.0). Two’s complement is the rule for integers, not for every numeric type.

FAQ

Why do computers use two’s complement?
Two’s complement has exactly one representation of zero (0000), which avoids the wasted "−0" pattern that both sign-magnitude and one’s complement carry. Even better, subtraction becomes ordinary addition: a − b is computed as a + (−b) using the same binary adder, with no special-case hardware for signs. That is why every modern CPU uses it for signed integers. You can watch this play out in the Binary Add / Subtract Calculator, which performs a subtraction as the addition of a complement.
How do I find the two’s complement of a number?
Take the binary pattern, invert every bit (turn each 0 into a 1 and each 1 into a 0), then add 1. For example, 4-bit +5 is 0101; invert to 1010, add 1 to get 1011, which is −5. The process is its own inverse, so applying it again to 1011 gives back 0101 (+5). The Two’s Complement Calculator does this instantly for any bit width, and the Number Base Converter shows you the resulting bit pattern.
What is the range of a signed 8-bit (two’s complement) number?
A signed 8-bit two’s-complement value runs from −128 to +127. Because there is only one zero (0000_0000), one extra bit pattern is freed up on the negative side, making the range asymmetric: 1000_0000 is −128, 0111_1111 is +127, and 1111_1111 is −1. In general n bits cover −(2^(n−1)) up to +(2^(n−1) − 1).
What’s the difference between one’s and two’s complement?
One’s complement negates a number by inverting every bit only, while two’s complement inverts the bits and then adds 1. One’s complement keeps two zeros (0000 for +0 and 1111 for −0) and needs an end-around carry when adding, so its range is symmetric (−127…+127 for 8-bit). Two’s complement collapses that to a single zero, giving the extra negative value (−128…+127 for 8-bit) and letting subtraction reuse the adder. That single difference — the "+1" — is why two’s complement won.
⚡ Powered by Circflow