The arithmetic underneath

The other half of a format

fp16 and tf32 have the same eleven significand bits and their largest numbers are 65,504 and 3.4·10³⁸. For two phases this site simulated the significand alone, so it was obliged to report them as the same format — which is a claim, and a false one.

Worth reading first: What a float can hold · Buying the accuracy back.

What a float can hold opens this site with the spacing of the representable numbers and the observation that it doubles at every power of two. Every essay since has treated “precision” as meaning the significand, and lib/float.js has simulated the significand and nothing else — each operation performed in double and rounded to a chosen number of significant bits, exactly as IEEE 754 rounds.

That was written down as a limitation on the day it was built, in the file’s own docstring: no overflow to infinity at 10³⁸, no gradual underflow, no subnormals. Everything this site claims is about precision, and precision is what is here.

The limitation had a consequence that grew rather than staying still, and the consequence is a false statement.

A 16-bit budget, split between range and precisionTwo curves against the width of the exponent field. One rises steeply and one falls in a straight line. Vertical lines mark the splits real hardware formats use.3456789101100.250.50.751bits in the exponent fieldeach curve as a fraction of its own maximumbfloat16fp16rangeprecisionto 617 decadesto 3.9 digitswhat the split buysbfloat16: largest number3.4·10³⁸fp16: largest number6.6·10⁴a bit of exponent doubles the rangea bit of significand adds a third of a digit
Fig. 1 Fifteen bits to divide between the exponent field and the significand, and the two things that buys. The vertical lines are where the hardware’s own 16-bit formats sit. Drag the width and watch tf32 appear at nineteen bits, which is a number chosen rather than inherited.

The false statement

lib/mixed.js carries a table of the hardware formats and it is indexed by mantissa bits:

bfloat16: 8 · fp16: 11 · tf32: 11 · fp32: 24 · fp64: 53

Read that table for what it is and it says fp16 and tf32 are the same format. Everything downstream agreed. Where the hardware went reports “fp16/tf32 κ·u = 0.488” as one row, because at eleven bits they compute the same thing — and that row was correct about the computation it described and wrong about the formats it named.

The two are not the same format. tf32’s largest finite number is 3.4·10³⁸ and fp16’s is 65,504, which is thirty-three decades apart, and the whole reason tf32 exists is that difference. It was introduced so that a value which fits in single precision cannot overflow when it is narrowed for a matrix multiplication, and the price paid for it is thirteen significand bits.

So the maturity phase’s job here was not to add a feature. It was to remove a claim the site was making by omission.

A format is two numbers

An IEEE-style binary format is specified by two integers: the width of the exponent field e, and the precision p — the number of significand bits including the implicit leading one. Everything else follows from those two and from the standard’s rules.

The bias is 2^(e−1) − 1. The top exponent code is reserved for infinities and NaNs, and the bottom one for zero and the subnormals. So the largest finite number is 2^emax·(2 − 2^(1−p)) with emax the bias, the smallest normal is 2^(1−bias), and the smallest subnormal is that divided by 2^(p−1).

Those formulas reproduce the numbers everybody knows, which is the check that entitles this site to say “fp16” rather than “an 11-bit simulation”:

format p e largest finite smallest normal unit roundoff
fp16 11 5 65,504 6.10·10⁻⁵ 4.88·10⁻⁴
bfloat16 8 8 3.39·10³⁸ 1.18·10⁻³⁸ 3.91·10⁻³
tf32 11 8 3.40·10³⁸ 1.18·10⁻³⁸ 4.88·10⁻⁴
binary32 24 8 3.40·10³⁸ 1.18·10⁻³⁸ 5.96·10⁻⁸
binary64 53 11 1.80·10³⁰⁸ 2.23·10⁻³⁰⁸ 1.11·10⁻¹⁶

65,504 and 3.4028…·10³⁸ are published constants that came from nowhere near this file, and a formula off by one in the bias reproduces neither. The site checks both, and checks binary32’s largest finite number against Math.fround — the hardware agreeing that the number computed from the formula is representable.

The budget, and why the trade is not symmetric

The figure is the design decision. A 16-bit format has fifteen bits to split, and every bit given to the exponent is taken from the significand.

What makes the choice interesting is that the two curves have different shapes. A bit of exponent doubles the range, because the range is exponential in the exponent width. A bit of significand adds about a third of a decimal digit, because precision is linear in it.

So the trade is wildly asymmetric, and it explains bfloat16 completely. Going from fp16’s five exponent bits to bfloat16’s eight multiplies the range by 2²⁴ — from a span of about twelve decades to one of about seventy-eight — and costs three significand bits, which is a single decimal digit. For a workload where values span many orders of magnitude and each individual value need only be roughly right, that is not a close call.

It also explains why nobody builds a 16-bit format with twelve exponent bits. The extra range is free in the sense that it costs bits, and useless in the sense that no computation needs 10⁶⁰⁰ — and the three significand bits it costs take the format below two decimal digits.

A 32-bit budget, split between range and precisionTwo curves against the width of the exponent field. One rises steeply and one falls in a straight line. Vertical lines mark the splits real hardware formats use.345678910111213141500.250.50.751bits in the exponent fieldeach curve as a fraction of its own maximumbinary32rangeprecisionto Infinity decadesto 8.7 digitswhat the split buysbinary32: largest number3.4·10³⁸a bit of exponent doubles the rangea bit of significand adds a third of a digit
Fig. 2 The same budget at thirty-two bits, where the only named format sits at eight exponent bits. The curves have the same shape; what changes is that there are enough bits for the precision curve to be worth spending on, which is why single precision keeps the exponent field it inherited from a 16-bit-sized decision.

What the extension does, and what it must not do

arith(bits) now takes an optional exponent width. With it, the arithmetic context overflows to infinity, underflows gradually, and has a largest and a smallest number. Without it, the behaviour is what it was.

That last clause is the whole engineering constraint. Two phases of figures were drawn against arith(bits) and none of them may move — a change that silently redrew 225 existing figures would be exactly the failure ../CONSOLIDATION.md records about a bad closeGaps breaking 181 figures across four sites.

So it is asserted rather than assumed. Eighteen thousand random values inside fp16’s normal range are rounded by both contexts and required to be bit-identical, and the two are required to differ in exactly the way a format does outside it: 300² is 89,984 without a range, at eleven bits, and is an infinity in fp16.

The default is expBits: null, meaning an unbounded exponent, and the site refuses to let that be described as a format — the assertion that an unbounded context has a range is fed to the build and rejected, because having no largest number is precisely what it was missing.

Where the difference shows up

Three places, and each gets an essay or a section.

Overflow, which is where a computation leaves the top of the range. This is the fp16-against-tf32 case and it is a norm that overflows before it is a norm: the naive Euclidean norm squares before it adds, which doubles the exponent, so it works over only about half of a format’s range. In fp16 a vector of sixteen entries each equal to 1,000 has a norm of 4,000 — comfortably representable — and the naive expression returns an infinity. In tf32, at the same precision, it returns 4,000.

Underflow, which is the bottom, and it is a different story with a different lesson. That is the numbers below the smallest one.

And the ranking of the formats. Where the hardware went ranks the five by mantissa bits and concludes that bfloat16 is the least accurate. It is, and it is also the only 16-bit format on which a great many computations complete at all — which is a fact about a different axis and which the ranking cannot express.

Where each norm works, for a vector of 8Four horizontal rows, one per format. Each carries a pale bar for the format's whole range, a bar above it for the scaled norm and a shorter bar below it for the naive one.-47-37-27-17-7313233301234log₁₀ of the vector's normfp1611 bitsbfloat168 bitstf3211 bitsbinary3224 bitspale: the format's range · blue: √(Σ(xᵢ/m)²)·m · red: √(Σxᵢ²)fp16 and tf32 have the same eleven significand bitsand their bars do not overlap
Fig. 3 The two axes in one picture. Each format gets a pale bar for its range, a bar for the norm that works over all of it and a shorter one for the norm that does not. fp16 and tf32 are adjacent, they have the same significand, and their bars do not overlap.

Why the two axes are not interchangeable

A reader could reasonably ask why this needs its own axis at all. Both range and precision are ways of failing to represent a number, and a computation that overflows and a computation that rounds have both lost information. The answer is that they fail differently, and the difference is the reason overflow gets a separate treatment everywhere in this subject.

Rounding is bounded and relative. Every operation returns a result within a factor of 1 + u of the exact one. That is what makes backward error analysis possible: a whole sequence of operations can be described as the exact computation on slightly perturbed data, and the perturbation is proportional to the data. Every claim in the error field rests on it.

Overflow is neither. The result is not within any factor of the exact one — it is an infinity, so the relative error is infinite. And infinity is absorbing: infinity minus infinity is a NaN, and a NaN propagates through everything it touches. So a single overflow anywhere in a long computation does not degrade the answer, it destroys it, and there is no analysis that recovers from it.

That asymmetry is why the standard treats them differently. Rounding happens silently on essentially every operation and no sane system reports it. Overflow raises a flag, because it is an event rather than a background condition.

And it is why the fix is different in kind. There is no way to compute more accurately than the format allows; the only response to rounding is a longer significand or a better-conditioned algorithm. But overflow can always be avoided by scaling, at the cost of one extra pass over the data — which is what the next essay’s scaled norm does and what every serious library routine does internally. A failure that can be engineered around and a failure that cannot are different kinds of failure, and collapsing them into “the format was not good enough” loses the only actionable half.

There is one more consequence and it is the practical one. Because rounding is relative, the natural way to think about precision is in significant digits, and the natural way to compare formats is by unit roundoff — which is what every essay on this site did before this one. Because overflow is absolute, the natural way to think about range is in decades of magnitude, and comparing formats by it means comparing 12 against 78. The two comparisons produce different orderings of the same five formats, and there is no single number that reconciles them, which is exactly why the figure above draws two curves and not one.

What is asserted here

The format constants are the hardware’s. 65,504, 2⁻¹⁴, 2⁻²⁴ for fp16; 3.4028…·10³⁸ and 2⁻¹²⁶ for binary32, with the hardware’s own fround confirming the largest finite number is representable; and binary64’s largest and smallest against the language’s own constants.

fp16 and tf32 have exactly the same unit roundoff, asserted as an equality, and ranges more than 10³³ apart — the pairing this whole extension exists for, stated as two assertions rather than as a sentence.

bfloat16 is the less precise of the two 16-bit formats and the one that cannot overflow where single precision does not. Both halves, because the first alone is the ranking that was already there and the second is what it was missing.

Bounding the exponent changes nothing inside the range, over eighteen thousand values, bit for bit.

The refusals: that fp16 and tf32 compute the same thing, fed a norm that is finite in one and infinite in the other; that overflow is a large rounding error, fed 300² in fp16; and that an unbounded context has a range.

A note on what is still missing

Three things, and naming them is cheaper than discovering them later.

The fp8 formats are not here. E5M2 follows IEEE’s rules and would fit the machinery exactly; E4M3 does not — it has no infinities and extends its exponent range to reach 448, which the formulas above do not produce. Adding it would mean either special-casing it or reporting a number that is not the one on the hardware, and reporting the wrong number quietly is the failure this site is organised against.

Rounding modes are not simulated. Everything here rounds to nearest, ties to even. Round-toward- zero and the directed modes exist, they change results, and stochastic rounding — which is genuinely used in low-precision training — changes them in a way that matters for exactly the accumulation problems the order they are added in is about.

And the block formats are not here at all. The formats current accelerators are moving to share one exponent across a block of values, which is neither a scalar format nor an array of them, and the whole notion of “the range of the format” needs restating for them. That is a subject rather than an omission.

What is here is the pair of numbers that specifies an ordinary IEEE format, the five formats that pair produces, and the two failures — off the top and off the bottom — that a significand-only simulation could not express.

The spacing of the numbers below the smallest normal, at 11 significand bitsA staircase of spacing against magnitude on logarithmic axes. It descends in steps from the right and then flattens to a horizontal line at the left. A dashed line drops away instead.10⁻⁷10⁻⁵10⁻³10⁻¹⁰10⁻⁸10⁻⁶magnitudespacing to the next numberthe smallest normalgradualflush to zerosmallest normal6.1·10⁻⁵smallest subnormal6·10⁻⁸octaves of subnormals10pairs that lie under FTZ10the spacing stops halving and stays putwhich is what makes x − y = 0 mean x = y
Fig. 4 The bottom of the range, which the next essay but one is about. The staircase descends and then flattens: below the smallest normal the spacing stops halving and stays constant, which is a behaviour with no analogue at the top.
Refinement thresholds by format, against a problem at κ = 1000A horizontal bar chart of the condition number at which iterative refinement stops working, one bar per floating-point format, with a marked line at the condition number of the problem.bfloat16 · 8 bits1/u = 256fp16 · 11 bits1/u = 2048tf32 · 11 bits1/u = 2048fp32 · 24 bits1/u = 1.7·10⁷fp64 · 53 bits1/u = 9·10¹⁵κ·u = 3.906 — past the thresholdκ·u = 0.488 — refinement recoversκ·u = 0.488 — refinement recoversκ·u = 6·10⁻⁵ — refinement recoversκ·u = 1.1·10⁻¹³ — refinement recoversthe problem is at κ = 1000; a format works when κ·u < 1thresholds are 1/u, a property of the arithmetic4 of 5 formats clear this κ
Fig. 5 The measurement this extension corrects. Three formats straddling a threshold at κ = 10³, ranked by mantissa bits — which is right about what it measures and calls two different formats by one name.
The representable numbers with a 4-bit significandA number line from 0.5 to 4 with a tick at every representable value. The ticks are evenly spaced inside each power-of-two interval and twice as far apart in the next one up.[½, 1)[1, 2)[2, 4)0.5124gap 0.0625gap 0.125 — twice as wide16 values per octavespacing doubles at each power of two
Fig. 6 Where the site started. The representable numbers at four significand bits, spaced by powers of two, with the gap doubling at every one — and with no top and no bottom, because until this phase the simulation had neither.
The spacing between consecutive numbers at 24-bit precisionA log–log staircase of the gap between neighbouring representable numbers against magnitude. The gap doubles at every power of two and reaches one whole unit partway along.110³10⁶10⁹10¹²10¹⁵10¹⁸10⁻¹⁸10⁻¹⁵10⁻¹²10⁻⁹10⁻⁶10⁻³110³magnitude of the numbergap to the next representable numberat 1: 1.2·10⁻⁷at a million: 0.063gap reaches 1: 124-bit significandthe gap follows the magnitude
Fig. 7 And the spacing as a function of magnitude in single precision. Every step is a doubling, the staircase runs forever in both directions, and the two places it stops are what the exponent field decides.

What this changes about the site’s own claims

Two of them, and both are corrections rather than additions.

The mixed-precision field’s ranking is now incomplete rather than wrong. Where the hardware went measures iterative refinement at three formats and finds the threshold at κ·u = 1, with bfloat16 failing first because its unit roundoff is largest. Every number in it is correct. What it could not say is that the same experiment run on data spanning more than twelve decades would not produce three results and one failure — it would produce two results, one failure, and one infinity, and the infinity would belong to the format with the second best precision of the three.

And the precision slider means something narrower than it appeared to. Nine figures on this site put the mantissa on a slider and watch a quantity slide with it, which is the site’s precision as the knob thread and is exactly as sound as it ever was — those figures are about the significand and they measure the significand. What they cannot show is a computation failing rather than degrading, and a reader who took the slider as a model of “using a smaller format” was being given half the model. The formats on the slider have no bottom and no top.

Nothing in the existing figures moves. The extension is opt-in, the eighteen thousand-value check above is what guarantees that, and the figures that want the other axis are the three in this essay’s field. But the claim the site was implicitly making — that narrowing a format is a matter of losing digits — was too small, and the correction is the phase’s own subject: a measurement is about the axis it was taken along, and an axis nobody measured is a claim nobody checked.

Named objects

A flat tag is an object no other essay names yet.

bfloat16Dynamic rangeExponent rangeHalf precisionIEEE 754OverflowSignificandUnit roundoff