← Binary Course — Part E, lesson 1 of 4 (Reading real machine words)
18. A Word Is Just Bits, Until You Decide What It Means
The concept
Every operation across Parts B, C, and D — AND/OR/XOR/NOT, shifts,
two's-complement addition and subtraction, fixed-point arithmetic — has
worked the same way: purely positionally, on wherever the bits sit,
never once asking what those bits are supposed to represent. Along the
way, three separate lessons each noticed the same gap from a different
angle. Lesson 9 pointed out that a word's bits never announce whether
they should be read as sign-magnitude, or as a plain unsigned number, or
under any other convention — "that choice of convention lives outside
the bits, in whichever operation reads the word." Lesson 14 showed the
identical six bits reading as 24 or as 0.75 depending only on where
a point is imagined. Lesson 16 stated it for scale specifically: "the
point never appears inside the stored bits on a real machine; it only
ever exists in the program's (or programmer's) bookkeeping." This lesson
makes that recurring observation the explicit, central subject: a
stored word is not self-explanatory. Its meaning always comes from
somewhere outside the bits themselves.
That "somewhere outside" is never mysterious — it's one of a few concrete things:
- Which instruction reads the word. A signed-compare instruction and an unsigned-compare instruction can read the identical bits and reach opposite conclusions about which of two numbers is larger.
- A convention stated alongside the program, the way Lesson 16 insisted a fixed-point value's scale always be written in words next to the word itself, because nothing in the bits carries it.
- The layout a programmer or compiler chose, the way Lesson 8's packed word only means "three small fields" because something decided in advance to slice it that way — the same eight bits are just as validly one number.
By now this course has built the machinery for several distinct readings of the same raw bits: a plain unsigned integer (Parts A-B), a signed integer under sign-magnitude, one's complement, or two's complement (Part C), a fixed-point value at some stated scale (Part D), and a packed record of independent fields (Lesson 8). Real machines layer on more — a character code, a memory address, an instruction's own opcode and operand — but every one of them is the same story: a convention, chosen externally, applied to bits that would otherwise sit there meaning nothing in particular.
It's worth naming one refinement here, because it's tempting to think some formats escape this entirely. Some encodings do carry part of their own description inside the word — floating point is the standard example, where a portion of the bits is reserved to record that value's own scale, so it travels with the number instead of living in separate program bookkeeping the way Part D's fixed point does. That's a real difference, but it only narrows the gap; it doesn't close it. Reading those scale bits correctly still depends on already knowing the word is a float in the first place, rather than a plain integer using those same bit positions for something else entirely — and that first-order decision is made exactly the same way as everywhere else in this lesson: by which instruction the program issues to read the word, never by anything the word itself announces.
This has a sharp practical consequence. Nothing at the hardware or assembly level stops a program from reading a word under the wrong convention. There's no error, no crash — the operation runs, produces a bit pattern, and that pattern gets decoded as whatever convention the instruction assumed, correct or not. A confidently wrong number is the only symptom. Higher-level languages exist partly to close this gap: a type system tracks which convention applies to which value and only ever emits instructions that match, refusing to compile code that would read a value under the wrong one (short of an explicit, deliberate unsafe cast). That's a guarantee the language adds on top; the hardware itself, underneath, enforces nothing at all.
Example 1 — One word, four different signed readings
Take the 8-bit word 1001 0011 — Lesson 9's own worked value, 0x93,
carried through Lessons 9-11 as the running comparison of how the three
signed schemes encode -19. Read here with no assumed convention at
all, decoded four different ways:
plain unsigned: 1001 0011 = 147
sign-magnitude: sign 1, magnitude 0010011 (19) -> -19
one's complement: invert -> 0110 1100 (108) -> -108
two's complement: invert, +1 -> 0110 1101 (109) -> -109
Four different numeric values, from the exact same eight bits, with no step of the decoding process touching the bits themselves differently — only the rule applied after reading them changes. This is the payoff Lesson 9's answer key pointed toward without naming yet: "the clearest possible demonstration that a bit pattern's meaning is never self-announcing."
Example 2 — Scale is a second, independent choice on top of sign
The same word, now also read at a stated fixed-point scale of 2^-4
(point after bit 4, Lesson 16's convention), stacked on top of two of
Example 1's sign readings:
unsigned reading (147) at scale 2^-4: 147 / 16 = 9.1875
two's-complement reading (-109) at scale 2^-4: -109 / 16 = -6.8125
Sign convention and scale are separate decisions, made independently — nothing forces one to imply the other. Four sign readings from Example 1, each of which could in principle be paired with its own stated scale, means one 8-bit pattern already supports far more than four distinct values depending on what's decided about it. None of that branching exists inside the bits; it's entirely a property of the conventions brought to them.
Example 3 — A convention that doesn't always apply
Conventions don't just disagree on value — sometimes one simply has
nothing to say about a given pattern. Read 0110 0001 under the
7-bit ASCII character-code convention:
0110 0001 = 97 (unsigned) -> the character 'a'
That works cleanly: 97 is a defined ASCII code point. Now apply the
same convention to Example 1's word, 1001 0011 (147 unsigned):
standard 7-bit ASCII only assigns meanings to the range 0-127, and
147 falls outside it entirely. There is no letter this represents
under that convention — not "the wrong letter," but no defined answer
at all. And exactly as the concept section warned, nothing stops a
program from trying anyway: it will hand back whatever bit pattern
happens to live at that position in some extended table, or garbage,
with no error raised to flag that the convention never covered this
input to begin with.
Example 4 — Even the format itself is an external decision
Suppose a stored 32-bit word holds a floating-point value — reserving, say, some of its bits for an exponent that records that number's own scale, the self-describing detail the concept section named. A program has two different instructions available that can both read those exact same 32 bits: an integer-add instruction, which treats every bit as an ordinary two's-complement magnitude bit the way Part C's rules do, and a float-add instruction, which treats some of those same bits as the self-carried exponent instead. Both instructions will run. Both will produce a result. Only one of them corresponds to what the value actually stores — and which one is correct depends entirely on which instruction the compiler chose to emit, based on the source language's declared type for that value, never on anything readable from the 32 bits themselves. The exponent field solves how to recover a float's scale once you know it's a float; it does nothing to solve whether a given word is a float at all.
Exercises
Exercise 1. Decode the word 1010 1100 (Lesson 6's running value)
three ways, using Example 1's method: as a plain unsigned integer, as
sign-magnitude, and as two's complement.
Exercise 2. Using Exercise 1's word and Example 2's method, give its
value at a stated fixed-point scale of 2^-4, once under the unsigned
reading and once under the two's-complement reading.
Exercise 3. A program reads a stored 32-bit value using an integer instruction when the value was actually written as a float. Using Example 4, explain why this doesn't produce a crash or an error at the hardware level, what happens instead, and name the mechanism most high-level languages rely on to stop this particular mistake from compiling in the first place.
Exercise 4. A classmate claims that since two's complement is how
negative numbers are usually represented, any 8-bit word whose leftmost
bit is 1 must represent a negative number. Using Example 1's word,
1001 0011, explain what's wrong with that claim.
Show Answer Key
1. Unsigned: 1010 1100 = 172. Sign-magnitude: sign 1, magnitude
0101100 = 44, so -44. Two's complement: invert (0101 0011), add 1
(0101 0100 = 84), so -84.
2. Unsigned reading (172) at scale 2^-4: 172 / 16 = 10.75.
Two's-complement reading (-84) at scale 2^-4: -84 / 16 = -5.25.
3. Nothing about the stored bits stops the integer instruction from
running — it has no way to know, and no way to check, that those
particular 32 bits were meant to be read as a float. It simply applies
plain two's-complement rules to every bit and produces some resulting
value, confidently and without complaint; the answer is just wrong, not
flagged as wrong, because the mismatch happened one level below where
any error-detection could occur. The mechanism that normally prevents
this is a compile-time type system: the compiler tracks that a given
value is a float and never emits anything but float instructions for
it, making the mismatched-instruction mistake impossible to write by
accident (short of a deliberate, explicit unsafe cast) — a guarantee
built on top of hardware that, on its own, enforces no such thing.
4. The claim is false, and 1001 0011 is a direct counterexample:
read under the plain unsigned convention (Example 1), that same word is
147 — a perfectly ordinary positive number, no sign or negativity
involved at all. Bit 7 being 1 only means "negative" under a signed
convention that has specifically designated it the sign bit; as Lesson
9 put it, that bit "is not stored anywhere separate from the rest of
the word... no different in kind from bit 6 or bit 3." Whether it's
being read that way at all is exactly the external decision this lesson
has been about.
Lesson 19 puts all of this into practice on an actual historic machine word — no longer an abstract 8-bit pattern, but a real word from a real machine, decoded field by field using every reading this lesson named.
Sign in to mark lessons complete and keep your progress.