← Binary Course — Part C, lesson 1 of 5 (Negative numbers)
9. Sign-Magnitude, and Its Awkward Downside
The concept
Every number in Parts A and B has been non-negative — a bit pattern always meant "how much," never "how much, and in which direction." Real programs need negative values too (a temperature below zero, a debit, an offset behind the start of something), so a word needs some way to carry a sign as well as a magnitude.
The most direct idea borrows exactly how numbers are written on paper: a
sign, plus a magnitude, side by side. Sign-magnitude reserves the
leftmost bit of the word as a sign flag — 0 for positive or zero, 1
for negative, matching NOTATION.md's general sign-bit convention — and
treats the remaining bits as an ordinary unsigned magnitude, exactly like
every number in Parts A and B. In 8 bits, that's 1 sign bit and 7
magnitude bits, so the magnitude alone can hold 0-127.
That sign bit is not stored anywhere separate from the rest of the word — it's bit 7, at a fixed position inside the very same 8 bits, no different in kind from bit 6 or bit 3. What the bit pattern never announces on its own is whether it should be read as sign-magnitude (or any signed scheme) at all: the same eight bits mean something else entirely as a plain unsigned number (Parts A-B). That choice of convention lives outside the bits, in whichever operation reads the word — a theme Part E returns to directly.
This lesson works through why sign-magnitude, despite being the most intuitive scheme, is not what most real machines settled on. Two problems show up almost immediately: it wastes a bit pattern on a second, redundant zero, and it turns addition into something far more involved than the position-by-position bit tricks Part B spent four lessons building up.
Example 1 — Representing a value and its negation
+5 and -5 in 8-bit sign-magnitude:
+5: 0 0000101 -> 0000 0101
-5: 1 0000101 -> 1000 0101
The magnitude bits (0000101 = 5) are identical in both; only the sign
bit differs. Negating a sign-magnitude number is genuinely easy — flip
one bit, leave the rest alone. That simplicity is real, and it's the
whole reason sign-magnitude is the first scheme worth trying. The
problems below are what happen next.
Example 2 — Two bit patterns for zero
Encode +0 and -0 the same way Example 1 encoded ±5:
+0: 0 0000000 -> 0000 0000
-0: 1 0000000 -> 1000 0000
Both represent the same value, zero, but they are two different bit
patterns. Every other lesson in this course has relied on one bit pattern
meaning exactly one value — that's what made Lesson 2's place-value
counting work, and what every AND/OR/XOR/shift trick in Part B assumed
without saying so. Sign-magnitude breaks that: comparing two words bit by
bit for equality no longer agrees with comparing the numbers they
represent, and one whole bit pattern (1000 0000) is spent re-describing
a value another pattern already covers, rather than encoding a new one.
Example 3 — Same-sign addition happens to work
Add +5 and +3 the ordinary way — just add the two 8-bit patterns as
plain binary numbers, ignoring that they're sign-magnitude:
0000 0101 (+5)
- 0000 0011 (+3)
0000 1000
Read as sign-magnitude, 0000 1000 is sign 0, magnitude 8 — +8,
which is correct (5 + 3 = 8). This works because both sign bits were
0 and the magnitudes summed to something that still fits in 7 bits, so
nothing spilled into the sign position. It's a coincidence of this
particular case, not a general method — Example 4 shows it break.
Example 4 — Different-sign addition breaks the same trick
Add +5 and -3, the same naive way — plain binary addition of the raw
bit patterns:
0000 0101 (+5)
- 1000 0011 (-3)
1000 1000
Read as sign-magnitude, 1000 1000 is sign 1, magnitude 8 — -8.
The correct answer to 5 + (-3) is +2. Plain addition doesn't just
round wrong here, it gets both the sign and the magnitude wrong, because
the sign bit was never special to the addition — it got added in as
though it were one more magnitude bit, and 0 + 1 in that position
produced a 1 that a reader could easily mistake for an overflow/carry
bit — but it isn't one; it's just an ordinary sum bit that happens to
land on the position sign-magnitude has designated as special.
Getting the right answer takes an actual algorithm, not a single add-the-patterns step: compare the two magnitudes, subtract the smaller from the larger, and give the result the sign of whichever magnitude was larger.
larger magnitude: 5 (sign +) smaller magnitude: 3
5 - 3 = 2
result takes the sign of the larger: +2 -> 0000 0010
That's a magnitude comparison and a subtraction, on top of the sign bookkeeping — real extra machinery Part B's tools never needed, because none of Part B's operations ever had to treat one bit differently from all the others.
Exercises
Exercise 1. Represent +19 and -19 in 8-bit sign-magnitude.
Exercise 2. Give the 8-bit sign-magnitude pattern for -19 (from
Exercise 1) in hex, using Lesson 3's nibble table.
Exercise 3. A classmate adds +6 and -6 the naive way from
Example 4 — plain binary addition of 0000 0110 and 1000 0110, no
sign-magnitude-aware algorithm. What word do they get, and what does it
decode to? What should the correct answer actually be — and when the
correct compare-and-subtract algorithm is used instead, what value do the
two magnitudes' difference come out to, and which of Example 2's two zero
patterns should that result use?
Show Answer Key
1. Magnitude of 19 in 7 bits: 0010011. +19 = 0 0010011 =
0001 0011. -19 = 1 0010011 = 1001 0011.
2. 1001 0011, converted nibble by nibble (Lesson 3): 1001 → 9,
0011 → 3. -19 = 0x93. (Worth noticing: 0x93 alone doesn't announce
that it means "-19" — that meaning only holds under the sign-magnitude
convention. The same eight bits mean something else entirely as a plain
unsigned number, a theme this course returns to directly in Part E.)
3. 0000 0110 + 1000 0110 = 1000 1100 by plain binary addition.
Decoded as sign-magnitude: sign 1, magnitude 0001100 = 12, so -12
— nowhere close to the correct answer. 6 + (-6) should be 0. Using
the correct algorithm instead: the two magnitudes are equal (6 and
6), so their difference is 0 — and now there's a genuine question of
which sign to attach to that 0, since sign-magnitude has two zero
patterns to choose from (Example 2). There's no magnitude left to inherit
a sign from; the choice has to be made by convention (typically +0),
not derived from the arithmetic itself. That's the two-zeros problem
showing up again, this time from inside the "fix" for the addition
problem rather than as a separate complaint.
Sign-magnitude's two flaws — a wasted, ambiguous zero, and addition that needs a full comparison-and-subtraction algorithm instead of a single pass over the bits — are exactly what the next few lessons address. Lesson 10 looks at one's complement, a first attempt at a fix that solves addition's awkwardness partway but not fully; Lesson 11 introduces two's complement, the scheme real machines actually use, and why it avoids both problems at once.
Sign in to mark lessons complete and keep your progress.