← Binary Course — Part D, lesson 3 of 4 (Fractions in binary)
16. Fixed-Point: Tracking Your Own Binary Point By Hand
The concept
Lesson 14 established that the same bits mean different things depending on where you imagine the point — nothing in the bits themselves decides that, only a stated convention does. This lesson asks the next question: what does that mean for arithmetic, on a machine with no separate "fraction mode"?
Look at what Lesson 11's addition rule actually does: line up two 8-bit patterns and add them position by position, carrying as needed. That procedure never once asks what the bits represent. It doesn't know or check whether bit 0 is the ones place or a sixteenth. The same is true of Lesson 12's subtraction, Lesson 5's AND/OR/XOR/NOT, and Lesson 6's shifts — every one of them is purely positional, operating on wherever the bits sit, with no awareness of a point at all. That means if two values are scaled the same way — the point sitting in the same place in both — adding their raw bit patterns with the ordinary whole-number addition rule produces the correct sum at that same scale, automatically. No special circuit, no rewiring, no fraction-aware hardware required. This is fixed-point arithmetic: pick one scale, in advance, for every value that will interact directly, and the plain integer ALU already covered in Parts B and C does the rest.
"Pick a scale" means deciding, once, where the point sits — stated in
words: "the point sits after bit 4," or equivalently "scaled by 2^-4."
A raw fixed-point word is written exactly like any other 8-bit word from
Lessons 2-13 — an ordinary undecorated nibble-grouped pattern, no point
shown inside it — with its scale stated alongside, in words, the same way
Lessons 14-15 required a stated reading whenever a bare bit pattern could
otherwise be ambiguous. The point never appears inside the stored bits on
a real machine; it only ever exists in the program's (or programmer's)
bookkeeping.
Two operations do need extra care, and it's worth naming both up front.
Multiplication changes the scale: multiplying two values that are each
scaled by 2^-4 produces a raw product scaled by 2^-8 (the two -4s
add), so the raw product must be shifted back afterward to restore the
expected scale — an ordinary shift instruction (Lesson 6), not special
hardware, but a step that's easy to forget. Addition or subtraction of
values at different scales needs the coarser value shifted to match
the finer one first — exactly the everyday habit of lining up decimal
points before adding 3.500 + 1.25, just done with a bit shift instead of
padding zeros by eye.
This lesson keeps every value non-negative, to keep the point-tracking itself uncluttered. Negative fixed-point values need nothing new: Part C's two's complement combines directly with a stated scale, same encoding, same addition rule.
One genuine limit is worth stating plainly: what this lesson does not cover is a per-number, self-describing scale that moves automatically — that's floating point, and it needs real additional hardware (circuitry to compare two numbers' exponents and realign their bits before adding them) that fixed point, with its scale fixed and known in advance, never needs. Floating point stays out of scope here, but it marks the actual dividing line: not "can hardware read a fraction," but "does the scale itself need to be carried and adjusted automatically, per value."
Example 1 — addition at a shared scale
Add 3.5 and 2.25, both scaled by 2^-4 (point after bit 4):
3.5 x 16 = 56 = 0011 1000
2.25 x 16 = 36 = 0010 0100
0011 1000
+ 0010 0100
-----------
0101 1100
0101 1100 is 92. At scale 2^-4, that's 92 / 16 = 5.75 — matching
3.5 + 2.25 = 5.75. Notice this used Lesson 11's addition rule with
nothing added or changed. The same three bit patterns, read with no scale
at all, are just 56 + 36 = 92 — an ordinary whole-number sum. The adder
performed one mechanical operation; which of those two readings is
"correct" was decided entirely beforehand, by the scale chosen for these
particular values, not by anything the adder did differently.
Example 2 — subtraction at a shared scale
Undo Example 1: subtract 36 from 92, still scaled by 2^-4:
0101 1100
- 0010 0100
-----------
0011 1000
0011 1000 is 56, and 56 / 16 = 3.5 — matching 5.75 - 2.25 = 3.5,
Example 1's other operand recovered exactly. Lesson 12's subtraction rule
needed no changes either.
Example 3 — aligning mismatched scales before adding
Add 2.75 (scaled by 2^-4, point after bit 4) and 1.5 (scaled by
2^-1, point after bit 1 — only one fractional bit). These can't be added
raw-to-raw; their scales don't match, the same way you wouldn't add 2.750
to 1.5 in decimal without first writing the second as 1.500.
2.75 at scale 2^-4: 2.75 x 16 = 44 = 0010 1100
1.5 at scale 2^-1: 1.5 x 2 = 3 = 0000 0011
1.5's raw value needs to move from scale 2^-1 to scale 2^-4 — three
more fractional bits — which is exactly Lesson 6's left shift, shifting by
the difference between the two scales:
0000 0011 shifted left 3 = 0001 1000 (still 1.5, now at scale 2^-4)
Now both operands share scale 2^-4 and add normally:
0010 1100
+ 0001 1000
-----------
0100 0100
0100 0100 is 68. At scale 2^-4: 68 / 16 = 4.25, matching
2.75 + 1.5 = 4.25.
Example 4 — multiplication and the scale-doubling correction
Multiply 1.5 and 2.5, both scaled by 2^-4:
1.5 x 16 = 24 = 0001 1000
2.5 x 16 = 40 = 0010 1000
Unlike addition, multiplying two 8-bit values can produce a result needing
up to twice the width — the same way multiplying two 3-digit decimal
numbers can need 6 digits. 24 x 40 = 960, which needs more than 8 bits:
960 = 0000 0011 1100 0000 (16 bits)
That raw product is scaled by 2^-4 x 2^-4 = 2^-8, not the 2^-4 either
operand started at — the scales multiplied together when the values did.
Restoring scale 2^-4 takes a right shift of 4 bits, undoing the extra
factor of 2^-4:
0000 0011 1100 0000 shifted right 4 = 0000 0000 0011 1100
The bottom 8 bits, 0011 1100, are 60. At scale 2^-4: 60 / 16 = 3.75, matching 1.5 x 2.5 = 3.75. The multiply circuit itself did
nothing but an ordinary integer multiply; restoring the right scale
afterward was a separate, explicit shift.
Exercises
Exercise 1. Add 1.75 and 0.5, both scaled by 2^-4 (point after
bit 4), using Example 1's method.
Exercise 2. Add 2.25 (scaled by 2^-4) and 1.5 (scaled by 2^-2
— point after bit 2, two fractional bits), using Example 3's alignment
method.
Exercise 3. A classmate insists a computer without a floating-point
unit can only add 3.25 and 1.5 correctly if it treats them as whole
numbers — that adding them as fractions would need different circuitry.
Using Example 1, explain what's wrong with that claim. Then name the one
operation covered in this lesson where the classmate's instinct would
actually be closer to right — where an ordinary integer circuit alone
isn't quite enough without an extra step.
Exercise 4. A classmate multiplies 0.75 and 2.0, both scaled by
2^-4. Their raw values are 0.75 x 16 = 12 and 2.0 x 16 = 32, and
12 x 32 = 384. They then read 384 directly at scale 2^-4
(384 / 16) as the answer, without shifting anything. What's the correct
result, and what did they get instead?
Show Answer Key
1. 1.75 x 16 = 28 = 0001 1100. 0.5 x 16 = 8 = 0000 1000.
0001 1100 + 0000 1000 = 0010 0100, which is 36. At scale 2^-4:
36 / 16 = 2.25, matching 1.75 + 0.5 = 2.25.
2. 2.25 at scale 2^-4: 2.25 x 16 = 36 = 0010 0100. 1.5 at
scale 2^-2: 1.5 x 4 = 6 = 0000 0110. Aligning to scale 2^-4 needs 2
more fractional bits (shift left 2): 0000 0110 shifted left 2 is
0001 1000 (24, still 1.5 — 24 / 16 = 1.5, unchanged). Adding:
0010 0100 + 0001 1000 = 0011 1100, which is 60. At scale 2^-4:
60 / 16 = 3.75, matching 2.25 + 1.5 = 3.75.
3. The classmate is wrong: Example 1 added the exact same raw bit
patterns and got the correct answer whether they're read as 56 + 36 = 92 (whole numbers) or 3.5 + 2.25 = 5.75 (fixed-point at scale 2^-4)
— the adder did one mechanical, positional operation either way, and
which reading applies was decided beforehand by the chosen scale, not by
anything the circuit did differently. The operation where extra care
really is needed is multiplication (Example 4): the raw product lands at
a doubled scale and needs an explicit corrective shift before it means
what it's supposed to mean.
4. The correct result: 12 x 32 = 384, scaled by 2^-8 (the two
2^-4 scales multiplied together), so it needs a right shift of 4 before
reading it at scale 2^-4: 384 shifted right 4 is 24, and
24 / 16 = 1.5, matching 0.75 x 2.0 = 1.5. The classmate skipped that
shift and read the unshifted raw product directly at scale 2^-4
instead: 384 / 16 = 24.0 — off by a factor of 16, not a small rounding
slip, because they applied the wrong scale to a value that was never at
that scale to begin with.
Lesson 17 turns from mechanics to history: how scaled fixed-point arithmetic — exactly what this lesson just did by hand — was standard practice on real early machines (and on the slide rules that came before them) long before floating-point hardware existed.
Sign in to mark lessons complete and keep your progress.