Introduction: The Problem of Negative Numbers
Computers work with binary—sequences of 0s and 1s. This works perfectly for counting: 0, 1, 10, 11, 100... But what about negative numbers? There's no "minus sign" in binary. How does a computer know the difference between 5 and -5?
This seemingly simple question has a surprisingly deep answer. Over the decades, computer scientists developed three major approaches to representing negative numbers in binary. Each has tradeoffs, and understanding them reveals fundamental insights about how computers really work.
The Core Challenge
Binary only has two symbols: 0 and 1. We need to encode the concept of "negative" using only these two symbols. Whatever method we choose must work efficiently with computer hardware—ideally using the same circuits for both positive and negative numbers.
In this comprehensive guide, we'll explore all three methods:
- Sign-Magnitude: The intuitive approach (like how we write -5)
- One's Complement: An improvement with a clever trick
- Two's Complement: The modern standard used in virtually all computers
By the end, you'll understand not just how these systems work, but why two's complement became the universal choice, and how to perform arithmetic with signed binary numbers confidently.
Unsigned vs. Signed: The Fundamental Choice
Before we can represent negative numbers, we need to understand the distinction between unsigned and signed integers.
Unsigned Integers
Unsigned integers can only represent zero and positive numbers. All n bits contribute to the magnitude:
| Bits | Minimum Value | Maximum Value | Total Values |
|---|---|---|---|
| 8 bits | 0 | 255 | 256 |
| 16 bits | 0 | 65,535 | 65,536 |
| 32 bits | 0 | 4,294,967,295 | ~4.3 billion |
| 64 bits | 0 | 18,446,744,073,709,551,615 | ~18 quintillion |
Signed Integers
Signed integers can represent negative, zero, and positive numbers. This requires "spending" some of the bit patterns on negative values:
| Bits | Minimum Value | Maximum Value | Total Values |
|---|---|---|---|
| 8 bits (signed) | -128 | +127 | 256 |
| 16 bits (signed) | -32,768 | +32,767 | 65,536 |
| 32 bits (signed) | -2,147,483,648 | +2,147,483,647 | ~4.3 billion |
| 64 bits (signed) | -9,223,372,036,854,775,808 | +9,223,372,036,854,775,807 | ~18 quintillion |
The Tradeoff
Signed and unsigned integers of the same bit width can represent the same number of values, but different ranges. An unsigned 8-bit integer goes 0 to 255; a signed 8-bit integer goes -128 to +127. You trade away half your positive range to gain negative numbers.
When to Use Each
- Unsigned: Memory sizes, array indices, bit flags, color values, ages, counts of things
- Signed: Temperatures, coordinates, differences, financial values, positions relative to origin
Sign-Magnitude Representation
The most intuitive approach to representing negative numbers mirrors how humans write them: use one bit as a "sign" and the rest as the magnitude.
How It Works
In sign-magnitude representation:
- The leftmost bit (most significant bit) indicates the sign: 0 = positive, 1 = negative
- The remaining bits represent the absolute value (magnitude)
4-Bit Sign-Magnitude Examples
0 1 0 1 → + 5 (sign bit 0 = positive, magnitude 101 = 5)
1 1 0 1 → - 5 (sign bit 1 = negative, magnitude 101 = 5)
0 1 1 1 → + 7 (maximum positive)
1 1 1 1 → - 7 (minimum negative)
0 0 0 0 → + 0 (positive zero)
1 0 0 0 → - 0 (negative zero!)
Complete 4-Bit Sign-Magnitude Table
| Binary | Decimal | Binary | Decimal |
|---|---|---|---|
| 0000 | +0 | 1000 | -0 |
| 0001 | +1 | 1001 | -1 |
| 0010 | +2 | 1010 | -2 |
| 0011 | +3 | 1011 | -3 |
| 0100 | +4 | 1100 | -4 |
| 0101 | +5 | 1101 | -5 |
| 0110 | +6 | 1110 | -6 |
| 0111 | +7 | 1111 | -7 |
The Problems with Sign-Magnitude
1. Two Representations of Zero
Both 0000 (+0) and 1000 (-0) represent zero. This wastes one bit pattern and complicates comparisons—is -0 equal to +0? The answer should be yes, but the bits are different.
2. Complex Addition Circuitry
Adding two numbers requires checking signs first. If signs match, add magnitudes. If signs differ, subtract the smaller from the larger and use the sign of the larger. This requires separate subtraction hardware.
3. Comparison Complexity
You can't simply compare bits to determine which number is larger. 1001 (-1) looks "bigger" than 0001 (+1) as a bit pattern, but it's actually smaller as a number.
Arithmetic Complications
Example: 5 + (-3) in Sign-Magnitude
5 = 0101 (positive)
-3 = 1011 (negative)
Step 1: Signs differ, so we need to subtract magnitudes
Step 2: |5| > |3|, so result is positive
Step 3: 5 - 3 = 2
Step 4: Apply positive sign: 0010
Result: +2 = 0010 ✓
Notice how much logic is required! We can't just add the numbers directly. The hardware must check signs, compare magnitudes, select the operation, and determine the result's sign.
Where Sign-Magnitude is Still Used
Despite its flaws for integers, sign-magnitude is used in floating-point numbers (IEEE 754). The exponent and mantissa have separate meanings, so the simplicity of sign-magnitude makes sense there.
One's Complement
One's complement improves on sign-magnitude by using a simple rule: to negate a number, flip all its bits. This creates a more symmetric representation and simplifies some operations.
How It Works
To find the one's complement (negative) of a binary number:
- Take the original binary number
- Flip every bit: 0 becomes 1, 1 becomes 0
One's Complement Examples
+5 = 0101
↓ flip all bits
-5 = 1010
+7 = 0111
↓ flip all bits
-7 = 1000
+1 = 0001
↓ flip all bits
-1 = 1110
Complete 4-Bit One's Complement Table
| Binary | Decimal | Binary | Decimal |
|---|---|---|---|
| 0000 | +0 | 1111 | -0 |
| 0001 | +1 | 1110 | -1 |
| 0010 | +2 | 1101 | -2 |
| 0011 | +3 | 1100 | -3 |
| 0100 | +4 | 1011 | -4 |
| 0101 | +5 | 1010 | -5 |
| 0110 | +6 | 1001 | -6 |
| 0111 | +7 | 1000 | -7 |
Notice that positive numbers start with 0, negative numbers start with 1—the most significant bit still indicates the sign, but the relationship to magnitude is different from sign-magnitude.
Arithmetic with One's Complement
One's complement allows us to use the same addition hardware for both addition and subtraction! To subtract, we add the one's complement of the number.
Example: 5 - 3 using One's Complement
5 - 3 = 5 + (-3)
5 = 0101
-3 = 1100 (one's complement of 0011)
0 1 0 1 (+5)
+ 1 1 0 0 (-3)
---------
1 0 0 0 1 (5 bits!)
↑
Carry out
The carry out must be added back (end-around carry):
0 0 0 1 (4-bit result without carry)
+ 1 (carry)
---------
0 0 1 0 = +2 ✓
The End-Around Carry Problem
The "end-around carry" is one's complement's peculiarity: when addition produces a carry out, that carry must be added back to the result. This requires an extra addition step.
Example: (-2) + (-3) in One's Complement
-2 = 1101 (one's complement of 0010)
-3 = 1100 (one's complement of 0011)
1 1 0 1 (-2)
+ 1 1 0 0 (-3)
---------
1 1 0 0 1 (5 bits, carry out)
End-around carry:
1 0 0 1 (4-bit result)
+ 1 (carry)
---------
1 0 1 0 = -5 ✓
Verify: 1010 flipped = 0101 = 5, so 1010 = -5 ✓
Remaining Problem: Two Zeros
One's complement still has two representations of zero: 0000 (+0) and 1111 (-0). This complicates comparisons and wastes one bit pattern.
Historical Use
One's complement was used in some early computers, including the UNIVAC 1101 (1950) and the CDC 6600 (1964). The Internet Protocol checksum still uses one's complement arithmetic because it has useful properties for error detection.
Two's Complement: The Modern Standard
Two's complement is the representation used in virtually all modern computers. It solves both problems of previous methods: there's only one zero, and arithmetic works without special cases.
How It Works
To find the two's complement (negative) of a binary number:
- Take the one's complement (flip all bits)
- Add 1 to the result
Alternatively, starting from the right: copy all bits up to and including the first 1, then flip the remaining bits.
Two's Complement Conversion Examples
Finding -5 from +5:
+5 = 0101
↓ flip all bits (one's complement)
1010
↓ add 1
-5 = 1011 ✓
Finding -3 from +3:
+3 = 0011
↓ flip all bits
1100
↓ add 1
-3 = 1101 ✓
Finding -1 from +1:
+1 = 0001
↓ flip all bits
1110
↓ add 1
-1 = 1111 ✓
Shortcut Method: Copy and Flip
Finding -6 from +6:
+6 = 0110
↓ From right: copy until first 1, then flip
0 1 1 0 (original)
↑ copy this 0
↑ copy this 1 (first 1 found)
↑ flip this 1 → 0
↑ flip this 0 → 1
-6 = 1010 ✓
Verify: 1010 → flip = 0101, add 1 = 0110 = 6 ✓
Complete 4-Bit Two's Complement Table
| Binary | Unsigned | Signed (2's comp) |
|---|---|---|
| 0000 | 0 | 0 |
| 0001 | 1 | +1 |
| 0010 | 2 | +2 |
| 0011 | 3 | +3 |
| 0100 | 4 | +4 |
| 0101 | 5 | +5 |
| 0110 | 6 | +6 |
| 0111 | 7 | +7 |
| 1000 | 8 | -8 |
| 1001 | 9 | -7 |
| 1010 | 10 | -6 |
| 1011 | 11 | -5 |
| 1100 | 12 | -4 |
| 1101 | 13 | -3 |
| 1110 | 14 | -2 |
| 1111 | 15 | -1 |
Key Observations
- Only one zero: 0000 is the only representation of zero
- Asymmetric range: -8 to +7 (one more negative than positive)
- Sign bit: MSB is still 0 for positive, 1 for negative
- -1 is all 1s: 1111 = -1 (this is useful!)
Why Two's Complement Works
Two's complement isn't arbitrary—it's mathematically elegant. Consider 4-bit arithmetic as a circle with 16 positions:
Imagine the numbers 0-15 arranged in a circle. When you add 1 to 15, you wrap around to 0. Two's complement simply relabels half the circle as negative:
Unsigned: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [wrap to 0]
Signed: 0 +1 +2 +3 +4 +5 +6 +7 -8 -7 -6 -5 -4 -3 -2 -1 [wrap to 0]
Adding 1 to -1 (1111) gives 10000. Discarding the overflow bit gives 0000 = 0. It just works!
The mathematical basis is modular arithmetic. In n-bit arithmetic, all operations are performed modulo 2ⁿ. A negative number -x is represented as 2ⁿ - x, which is exactly what two's complement computes.
Why -3 = 1101 in 4-bit Two's Complement
In 4-bit arithmetic, everything is mod 16.
-3 is represented as 16 - 3 = 13 = 1101₂
Adding +5 and -3:
5 + 13 = 18
18 mod 16 = 2 ✓
In binary:
0101 + 1101 = 10010
Discard overflow bit: 0010 = 2 ✓
Converting To and From Two's Complement
Reading a Negative Number
To find the decimal value of a negative two's complement number:
What is 1011 in two's complement?
Method 1: Convert back to positive
1011 → flip bits → 0100 → add 1 → 0101 = 5
Therefore, 1011 = -5
Method 2: Use the formula
For n bits: value = -2^(n-1) × MSB + remaining bits
1011: -2³ × 1 + 2¹ × 1 + 2⁰ × 1
= -8 + 2 + 1
= -5 ✓
Method 3: Subtract from 2ⁿ
1011₂ = 11₁₀ (as unsigned)
16 - 11 = 5
Therefore it represents -5 ✓
Range of Two's Complement Numbers
For an n-bit two's complement number:
- Minimum value: -2^(n-1)
- Maximum value: 2^(n-1) - 1
| Bits | Range | Most Negative | Most Positive |
|---|---|---|---|
| 4 | -8 to +7 | 1000 | 0111 |
| 8 | -128 to +127 | 10000000 | 01111111 |
| 16 | -32768 to +32767 | 1000...0 | 0111...1 |
| 32 | -2.1B to +2.1B | 1000...0 | 0111...1 |
The Asymmetry Explained
There's one more negative number than positive because zero is considered "positive" (its bit pattern starts with 0). With 4 bits we have: one zero, seven positives (1-7), and eight negatives (-8 to -1).
Signed Arithmetic in Detail
The magic of two's complement is that addition and subtraction work exactly the same as with unsigned numbers. The hardware doesn't need to know whether numbers are signed or unsigned!
Addition with Signed Numbers
Example 1: (+5) + (+3) = +8 (positive + positive)
Using 5-bit two's complement:
0 0 1 0 1 (+5)
+ 0 0 0 1 1 (+3)
-----------
0 1 0 0 0 (+8) ✓
Example 2: (+5) + (-3) = +2 (positive + negative)
Using 5-bit two's complement:
-3 = flip(00011) + 1 = 11100 + 1 = 11101
0 0 1 0 1 (+5)
+ 1 1 1 0 1 (-3)
-----------
1 0 0 0 1 0
↑
Discard overflow carry (normal in 2's complement)
0 0 0 1 0 (+2) ✓
Example 3: (-5) + (-3) = -8 (negative + negative)
Using 5-bit two's complement:
-5 = 11011
-3 = 11101
1 1 0 1 1 (-5)
+ 1 1 1 0 1 (-3)
-----------
1 1 1 0 0 0
↑
Discard overflow carry
1 1 0 0 0 (= -8) ✓
Verify: 11000 → flip = 00111, add 1 = 01000 = 8
Therefore 11000 = -8 ✓
Example 4: (-7) + (+3) = -4
Using 5-bit two's complement:
-7 = 11001
+3 = 00011
1 1 0 0 1 (-7)
+ 0 0 0 1 1 (+3)
-----------
1 1 1 0 0 (-4) ✓
Verify: flip(11100) + 1 = 00011 + 1 = 00100 = 4 ✓
Subtraction with Signed Numbers
Subtraction is simply addition of the two's complement:
A - B = A + (-B) = A + (two's complement of B)
Example: 7 - 4 = 3
Using 4-bit two's complement:
7 = 0111
4 = 0100, so -4 = 1100
7 - 4 = 7 + (-4):
0 1 1 1 (7)
+ 1 1 0 0 (-4)
---------
1 0 0 1 1
↑
Discard carry
0 0 1 1 = 3 ✓
Example: 3 - 7 = -4
Using 4-bit two's complement:
3 = 0011
7 = 0111, so -7 = 1001
3 - 7 = 3 + (-7):
0 0 1 1 (3)
+ 1 0 0 1 (-7)
---------
1 1 0 0 = -4 ✓
Verify: flip(1100) + 1 = 0011 + 1 = 0100 = 4 ✓
Multiplication Considerations
Multiplication of signed numbers requires care. You can't simply multiply the bit patterns as if they were unsigned:
Example: (-3) × 2 = -6
Using 4-bit values:
-3 = 1101
2 = 0010
If we multiply as unsigned:
1101 × 0010 = 11010 (26 in unsigned!)
Correct method: Sign-extend and use larger result:
-3 = 11111101 (8-bit)
2 = 00000010 (8-bit)
Or: Multiply magnitudes, determine sign separately:
3 × 2 = 6
Signs: (negative) × (positive) = negative
Result: -6 = 1010 (4-bit) ✓
Hardware Support
CPUs typically have separate multiply instructions for signed (IMUL) and unsigned (MUL) multiplication. The bit manipulation is different internally, even though the operands look the same.
Signed Overflow: The Silent Killer
Signed overflow is more subtle than unsigned overflow. It occurs when the result of an operation falls outside the representable range, causing the sign to change unexpectedly.
When Overflow Occurs
- Adding two positives → negative: Overflow (result too large)
- Adding two negatives → positive: Overflow (result too small)
- Adding positive and negative: Never overflows!
Example: Positive Overflow in 4-bit
5 + 6 should equal 11, but 4-bit signed max is 7:
0 1 0 1 (+5)
+ 0 1 1 0 (+6)
---------
1 0 1 1 = -5 in two's complement!
Two positives gave a negative = OVERFLOW!
Example: Negative Overflow in 4-bit
(-5) + (-4) should equal -9, but 4-bit signed min is -8:
1 0 1 1 (-5)
+ 1 1 0 0 (-4)
---------
1 0 1 1 1
↑
Discard carry
0 1 1 1 = +7!
Two negatives gave a positive = OVERFLOW!
Detecting Signed Overflow
Overflow occurs when the carry into the sign bit differs from the carry out of the sign bit:
| Carry In | Carry Out | Overflow? |
|---|---|---|
| 0 | 0 | No |
| 0 | 1 | Yes (positive overflow) |
| 1 | 0 | Yes (negative overflow) |
| 1 | 1 | No |
CPUs set an "overflow flag" (OF or V) when this condition is detected, allowing programs to check for overflow after arithmetic operations.
Sign Extension
When you need to represent a number with more bits (e.g., converting 8-bit to 16-bit), you must preserve the sign. This is called sign extension.
How Sign Extension Works
Copy the sign bit (MSB) into all the new positions:
Positive Number Extension
+5 in 4-bit: 0101
+5 in 8-bit: 00000101 (fill with 0s)
+5 in 16-bit: 0000000000000101
The sign bit is 0, so we extend with 0s.
Negative Number Extension
-5 in 4-bit: 1011
-5 in 8-bit: 11111011 (fill with 1s)
-5 in 16-bit: 1111111111111011
The sign bit is 1, so we extend with 1s.
Verify: 11111011
Flip: 00000100
Add 1: 00000101 = 5
Therefore 11111011 = -5 ✓
Why Sign Extension Preserves Value
In two's complement, the sign bit has a negative weight: -2^(n-1). When you extend the number, you add more negative bits at the top, but they cancel out: -2^n + 2^(n-1) = -2^(n-1). The value remains unchanged!
Zero Extension vs. Sign Extension
- Zero extension: For unsigned numbers, fill new bits with 0
- Sign extension: For signed numbers, fill with the sign bit
Using the wrong extension type causes serious bugs:
Wrong Extension Example
-5 in 4-bit (signed): 1011
Zero-extended to 8-bit: 00001011 = +11 (WRONG!)
Sign-extended to 8-bit: 11111011 = -5 (CORRECT)
Comparing Representations
Let's summarize all three signed representations:
| Property | Sign-Magnitude | One's Complement | Two's Complement |
|---|---|---|---|
| Negation | Flip sign bit | Flip all bits | Flip all + add 1 |
| Zero representations | Two (+0, -0) | Two (+0, -0) | One |
| Range (n bits) | -(2^(n-1)-1) to +(2^(n-1)-1) | -(2^(n-1)-1) to +(2^(n-1)-1) | -2^(n-1) to +(2^(n-1)-1) |
| Addition hardware | Complex (check signs) | Simple + end-around carry | Simple |
| Subtraction | Needs subtractor | Add complement | Add complement |
| Used today? | Floating-point sign | IP checksums | All integer arithmetic |
Why Two's Complement Won
Two's complement requires the simplest hardware—the same adder works for both positive and negative numbers without modification. There's one unique zero. The range is maximally efficient. It's simply the best solution.
Real-World Applications
Programming Languages
| Language | Signed Types | Unsigned Types |
|---|---|---|
| C/C++ | char, short, int, long | unsigned versions |
| Java | byte, short, int, long | None (except char) |
| Python 3 | int (arbitrary precision) | N/A |
| JavaScript | Number (float64) | N/A (bitwise ops use int32) |
| Rust | i8, i16, i32, i64, i128 | u8, u16, u32, u64, u128 |
Common Pitfalls
Mixing Signed and Unsigned
In C, comparing signed and unsigned values can give unexpected results. -1 > 0U is true because -1 is converted to unsigned (becoming a large positive number).
Integer Promotion
Small types are "promoted" to int for calculations. A signed char multiplied by another signed char produces a signed int, not a char.
Negating the Minimum
For 32-bit signed: -(-2147483648) = -2147483648! The minimum value has no positive equivalent, so negation overflows back to itself.
Assembly Language Perspective
At the assembly level, the same bits can be interpreted as signed or unsigned. The CPU provides different instructions:
- JG/JL: Jump if greater/less (signed comparison)
- JA/JB: Jump if above/below (unsigned comparison)
- IMUL: Signed multiply
- MUL: Unsigned multiply
- SAR: Shift arithmetic right (preserves sign)
- SHR: Shift logical right (fills with zeros)
Practice Problems with Solutions
Conversion Problems
Problem 1: What is -42 in 8-bit two's complement?
Show Solution
42 = 00101010
Flip: 11010101
Add 1: 11010110
-42 = 11010110 ✓
Problem 2: What decimal value does 10110101 represent in 8-bit two's complement?
Show Solution
10110101 (MSB is 1, so negative)
Flip: 01001010
Add 1: 01001011 = 75
Therefore 10110101 = -75 ✓
Alternative method:
-128 + 32 + 16 + 4 + 1 = -128 + 53 = -75 ✓
Arithmetic Problems
Problem 3: Calculate (-15) + (+23) in 8-bit two's complement
Show Solution
-15 = 11110001
+23 = 00010111
1 1 1 1 0 0 0 1
+ 0 0 0 1 0 1 1 1
-----------------
1 0 0 0 0 1 0 0 0
↑
Discard carry
0 0 0 0 1 0 0 0 = 8 ✓
Problem 4: Does 01111010 + 00010101 overflow in 8-bit signed?
Show Solution
01111010 = +122
00010101 = +21
Sum should be 143, but max is 127...
0 1 1 1 1 0 1 0
+ 0 0 0 1 0 1 0 1
-----------------
1 0 0 0 1 1 1 1 = -113 (wrong!)
YES, overflow occurred.
Two positives gave a negative = overflow.
Carry into sign bit: 1
Carry out of sign bit: 0
Different carries = overflow detected.
Problem 5: Sign extend 1010 from 4 bits to 8 bits
Show Solution
1010 (4-bit signed = -6)
Sign bit is 1, so extend with 1s:
11111010 (8-bit signed = -6) ✓
Verify: flip(11111010) = 00000101
Add 1: 00000110 = 6
Therefore 11111010 = -6 ✓
Summary
Understanding signed number representation is essential for any serious programmer or computer scientist. Here's what you've learned:
- Sign-magnitude is intuitive but has two zeros and complex arithmetic
- One's complement improves arithmetic but still has two zeros
- Two's complement is the universal standard: one zero, simple arithmetic
- The same addition hardware works for both signed and unsigned numbers
- Overflow detection checks the carry into/out of the sign bit
- Sign extension preserves value when widening signed numbers
With this knowledge, you can reason about how any computer handles negative numbers—from microcontrollers to supercomputers.