- Key idea
- Representable values, spacing that doubles with each power of two, relative vs absolute error, subnormals, infinity and NaN
- Real world
- A tape measure for a house is marked in millimetres; a map of a country is marked in kilometres. You need fine marks for small distances and coarse ones for big distances, and the relative precision is similar.
- In an LLM
- A weight of 0.001 and an activation of 300 can both be stored in bf16 with about 0.4% error. With evenly spaced integers, one of them would be either rounded to zero or clipped.
Only some numbers exist
A format with bits can store at most different numbers. Every other number has to be rounded to one of them. So the important question about a format is: which numbers can it store, and how far apart are they?
For integers, the answer is simple: evenly spaced, 1 apart. For floats, the answer is the picture on this page.
Try it
The widget uses a made-up tiny float so you can see every single value it can store. Real formats work the same way with many more ticks.
What the picture shows
Each exponent value is a band. Within one band, say between 2 and 4, the mantissa bits split the range into equal steps. With 2 mantissa bits there are 4 steps: 2, 2.5, 3, 3.5.
Each band is twice as wide as the last. The next band, 4 to 8, also gets 4 steps, so they are twice as far apart: 4, 5, 6, 7. Then 8, 10, 12, 14. The spacing doubles every time the numbers double.
So the relative error is roughly constant. Rounding 2.6 to 2.5 is a 4% error; rounding 13 to 12 or 14 is about 4–8%. Small numbers get small absolute errors and large numbers get large ones, but as a fraction of the number, the error is similar. On the log scale, every band looks the same width.
You measure a shelf to the millimetre and a road trip to the kilometre. Both measurements are about equally precise relative to what you’re measuring (a few parts in a thousand), even though one error is a million times bigger than the other. Floats are a measuring system that automatically switches from millimetres to kilometres as the number grows.
Inside an LLM, typical weights are around 0.01–0.1, while some activations reach the hundreds. In bf16, both are stored to about 3 significant figures, because each is placed in its own band. If you instead used one evenly spaced grid fine enough for 0.01, it would need far too many steps to reach 300; one coarse enough for 300 would round every weight to zero. Integer quantization has exactly this problem, which is why it needs scales and groups.
The edges of the line
Near zero: subnormals. The smallest exponent would leave a gap between zero and the first band. Instead, the all-zeros exponent is used for subnormal numbers: evenly spaced values filling that gap, without the hidden leading 1. They are less precise but stop small numbers from suddenly dropping to zero (purple ticks in the widget).
Too small: underflow. Below the smallest subnormal, a number rounds to zero. In fp16 that happens below about , which used to wipe out small gradients during training.
Too big: overflow. Above the largest value, IEEE formats give infinity, and arithmetic with infinity soon produces NaN (“not a number”, e.g. ). One NaN anywhere in a training step usually spreads to everything. fp16 overflows above 65,504, a number that large attention logits or activations can exceed.
Why not just use integers?
A trained network’s numbers span several orders of magnitude, and gradients during training span many more. Floats handle that without any bookkeeping. Integers are cheaper in hardware, but need an extra scale per block of numbers to say where the grid sits. Quantization is mostly the craft of choosing those scales well, starting with what quantization is.
Where this shows up
- The bit layout: floating point.
- How real formats choose their trade-off: fp32, fp16, bf16, fp8, fp4.
- Loss scaling to avoid underflow: training in low precision.
Spacing and error
In the band , a format with mantissa bits has spacing
(“unit in the last place”). Rounding to nearest gives an absolute error of at most half that, so a relative error of at most
where is machine epsilon: for fp32, for fp16 and for bf16. So the worst-case relative rounding error is half that: about , and .
Dynamic range
The ratio between the largest and smallest normal values, in powers of two, is roughly bands:
fp16 () covers about 30 binades, fp32 and bf16 () about 254. Adding one exponent bit roughly doubles the number of binades; adding one mantissa bit halves every gap.
Summation
Adding a small number to a large one can lose it entirely: in bf16, , because the spacing at 256 is 2. This is why reductions (sums over thousands of products in a matrix multiply, or accumulating gradients) are done in fp32 even when the inputs are bf16, fp8 or int8.