Methods that were designed apart

The part of a solver that may be rounded

A preconditioner computed and applied with a three-bit significand still returns thirteen correct digits — it costs seventeen extra iterations and nothing else. Round the working arithmetic instead and the step count barely moves while the answer loses exactly the digits the format dropped.

Worth reading first: Buying the accuracy back · Changing the condition number on purpose.

The mixed-precision field has one rule and it is about a direct solve: factorise cheaply, correct in double, and the whole method lives or dies on the precision of the residual. The measurement behind it is unambiguous — the same refinement code with the residual computed in single ends at 8.80·10⁻⁵, having improved by a total factor of 1.51 across six steps. Inert, not slow.

An iterative solve has two low-precision opportunities rather than one, and they are not symmetric at all. A preconditioned conjugate gradient method has a preconditioner, which is an approximation to A⁻¹ that nobody claims is accurate, and a working arithmetic, which is what everything else is computed in. Both look like places to save. One of them is.

Preconditioned conjugate gradients with one part of it roundedIteration count against significand bits, on the 100-unknown model problem. Rounding the preconditioner's output takes the count from 18 to 35 and leaves the answer correct to 8.8·10⁻¹³ throughout. Rounding the working arithmetic instead leaves the count at 18–300 and takes the answer to 0.159. The horizontal line is the 39 steps the unpreconditioned method takes.21018263442500102030405060708090100110120130140150160170180190200210220230240250260270280290300310320330340significand bitsiterationspreconditioner roundedarithmetic roundedno preconditionersame bits, different casualtyerror, 3-bit preconditioner8.8·10⁻¹³error, 3-bit arithmetic0.16‖A − LLᵀ‖/‖A‖ of the factor0.083a direction may be roundeda measurement may not
Fig. 1 Preconditioned conjugate gradients on the 100-unknown model problem with one part of it rounded. The solid curve rounds the preconditioner’s output to the stated number of significand bits; the dashed one rounds the working arithmetic instead. The horizontal line is the 39 steps the unpreconditioned method takes. Drag it to three bits and watch which curve moves.

Watching one curve move is the argument, and the rate at which it moves is the part a single frame cannot give. Four more widths, from the cheapest format anybody ships down to almost nothing:

Preconditioned conjugate gradients with one part of it roundedIteration count against significand bits, on the 100-unknown model problem. Rounding the preconditioner's output takes the count from 18 to 20 and leaves the answer correct to 5.8·10⁻¹³ throughout. Rounding the working arithmetic instead leaves the count at 18–24 and takes the answer to 7.3·10⁻⁴. The horizontal line is the 39 steps the unpreconditioned method takes.101826344250010203040significand bitsiterationspreconditioner roundedarithmetic roundedno preconditionersame bits, different casualtyerror, 11-bit preconditioner5.8·10⁻¹³error, 11-bit arithmetic7.3·10⁻⁴‖A − LLᵀ‖/‖A‖ of the factor0.083a direction may be roundeda measurement may not
Fig. 2 Rounding to eleven bits — roughly binary16’s significand. The preconditioner-rounded run takes 20 steps to an error of 5.8·10⁻¹³; the working-precision-rounded run takes 24 steps to 7.3·10⁻⁴.
Preconditioned conjugate gradients with one part of it roundedIteration count against significand bits, on the 100-unknown model problem. Rounding the preconditioner's output takes the count from 18 to 21 and leaves the answer correct to 2.4·10⁻¹³ throughout. Rounding the working arithmetic instead leaves the count at 18–29 and takes the answer to 0.00597. The horizontal line is the 39 steps the unpreconditioned method takes.71523313947010203040significand bitsiterationspreconditioner roundedarithmetic roundedno preconditionersame bits, different casualtyerror, 8-bit preconditioner2.4·10⁻¹³error, 8-bit arithmetic0.006‖A − LLᵀ‖/‖A‖ of the factor0.083a direction may be roundeda measurement may not
Fig. 3 Eight bits: 21 steps and 2.42·10⁻¹³ against 29 steps and 5.97·10⁻³.

Three bits removed have cost the first route one step and no accuracy, and the second route five steps and an order of magnitude. Removing two more crosses a line for the second route and not for the first.

Preconditioned conjugate gradients with one part of it roundedIteration count against significand bits, on the 100-unknown model problem. Rounding the preconditioner's output takes the count from 18 to 22 and leaves the answer correct to 8.9·10⁻¹³ throughout. Rounding the working arithmetic instead leaves the count at 18–40 and takes the answer to 0.0179. The horizontal line is the 39 steps the unpreconditioned method takes.5132129374553010203040significand bitsiterationspreconditioner roundedarithmetic roundedno preconditionersame bits, different casualtyerror, 6-bit preconditioner8.9·10⁻¹³error, 6-bit arithmetic0.018‖A − LLᵀ‖/‖A‖ of the factor0.083a direction may be roundeda measurement may not
Fig. 4 Six bits, where the working-precision run reaches 40 steps — past the 39 the unpreconditioned method takes, so the preconditioner has stopped paying for itself — with an error of 1.79·10⁻². The preconditioner-rounded run is at 22 steps and 8.91·10⁻¹³.
Preconditioned conjugate gradients with one part of it roundedIteration count against significand bits, on the 100-unknown model problem. Rounding the preconditioner's output takes the count from 18 to 27 and leaves the answer correct to 7.6·10⁻¹³ throughout. Rounding the working arithmetic instead leaves the count at 18–300 and takes the answer to 0.132. The horizontal line is the 39 steps the unpreconditioned method takes.31119273543510102030405060708090100110120130140150160170180190200210220230240250260270280290300310320330340significand bitsiterationspreconditioner roundedarithmetic roundedno preconditionersame bits, different casualtyerror, 4-bit preconditioner7.6·10⁻¹³error, 4-bit arithmetic0.13‖A − LLᵀ‖/‖A‖ of the factor0.083a direction may be roundeda measurement may not
Fig. 5 Four bits. The working-precision run hits the 300-step cap with an error of 0.132; the preconditioner-rounded run takes 27 steps to 7.59·10⁻¹³.
significand bits preconditioner rounded working precision rounded
11 20 steps, 5.8·10⁻¹³ 24 steps, 7.3·10⁻⁴
8 21 steps, 2.42·10⁻¹³ 29 steps, 5.97·10⁻³
6 22 steps, 8.91·10⁻¹³ 40 steps, 1.79·10⁻²
4 27 steps, 7.59·10⁻¹³ 300 steps, 0.132
3 35 steps, 8.83·10⁻¹³ 300 steps, 0.159
2 35 steps, 8.83·10⁻¹³ 300 steps, 0.159

The preconditioner-rounded column holds its accuracy at every width down to two bits. The error reads 5.8·10⁻¹³, 2.42·10⁻¹³, 8.91·10⁻¹³, 7.59·10⁻¹³ and 8.83·10⁻¹³ — a factor of four of variation, with no trend, across nine bits of precision removed. What the rounding costs is steps: 20, 21, 22, 27, 35. And 35 is still fewer than the 39 the unpreconditioned method takes, so a preconditioner computed to two significand bits is still worth having.

The working-precision column loses accuracy monotonically and then stops converging. 7.3·10⁻⁴, 5.97·10⁻³, 1.79·10⁻², 0.132, 0.159 — and the step count goes 24, 29, 40, 300, 300, where 300 is the cap rather than a measurement. It crosses the unpreconditioned line at six bits, which is the width at which rounding the working arithmetic has made the whole preconditioner pointless.

At four bits the two routes differ by eleven orders of magnitude in error and by a factor of eleven in steps, on the same problem, the same method and the same number of significand bits — 7.59·10⁻¹³ against 0.132, 27 steps against 300. That is the asymmetry the essay is named for, and the slider is what turns it from a comparison into a rate.

One reading is not a measurement: the last two rows are identical. Three bits and two bits give 35 steps and 8.83·10⁻¹³ for one route and 300 and 0.159 for the other, to every digit. The sweep has saturated, so the two-bit row is not evidence about two bits — it is evidence that the construction stops distinguishing widths below three.

The experiment, and what is held fixed

The problem is the two-dimensional discrete Laplacian on a 10×10 grid, and the preconditioner is the incomplete Cholesky factor iterative.js builds by refusing to store any entry the matrix has as a zero. That factor is not accurate and never was: ‖A − LLᵀ‖/‖A‖ is 0.0825, which is a residual this site prints and asserts to be large — the one place where the badge points the other way.

Two runs, each changing exactly one thing.

Rounding the preconditioner. M⁻¹r is computed in double and then rounded to b significand bits before it is used. Not the factor — the application, because the question is what an inexact preconditioner does rather than what a different preconditioner does.

Rounding the working arithmetic. The products with A, the inner products and the vector updates all go through an arithmetic context of b bits, and the preconditioner stays exact. float.js has supplied that context since the foundation phase and nothing else about the code changes.

The first result: three significand bits

significand bits in the preconditioner steps relative error
53 18 1.4·10⁻¹³
24 18 8.1·10⁻¹³
16 20 3.8·10⁻¹⁴
11 20 5.8·10⁻¹³
8 21 2.4·10⁻¹³
6 22 8.9·10⁻¹³
4 27 7.6·10⁻¹³
3 35 8.8·10⁻¹³

The error column does not move. Three significand bits is a format with eight distinct significands; there is no hardware that has ever offered it, and it is well below the eight bits float.js treats as the bottom of its own range. The answer is still correct to thirteen digits.

What it costs is seventeen iterations, and even that is worth having: the unpreconditioned method takes 39 steps on this problem, so a three-bit preconditioner at 35 steps is still ahead. At two bits it is not — 62 steps — and that is where it stops being worth applying, which is a statement about the trade rather than about the answer.

The reason is structural rather than lucky, and it is worth stating in one line: M⁻¹ enters the method only through the search direction. A wrong direction is a slower descent. It is not a wrong answer, because the residual that decides how far to move along that direction is computed from A and b and never from M. Conjugate gradients with a preconditioner of pure noise is steepest descent — slow, and correct.

The second result: the same bits, the other casualty

working significand bits steps relative error final relative residual
53 18 1.4·10⁻¹³ 4.0·10⁻¹³
24 20 1.6·10⁻⁷ 1.1·10⁻¹³
16 20 2.2·10⁻⁵ 9.8·10⁻¹³

Both at once, which is what a code would do

The two sweeps each move one precision and hold the other at 53 bits. A real mixed-precision solver reduces both, and whether the penalties add is not answered by either sweep.

Steps and relative error over the grid:

53 working bits 24 16 11 8
precond 53 bits 18 / 1.4·10⁻¹³ 20 / 1.6·10⁻⁷ 20 / 2.2·10⁻⁵ 24 / 7.3·10⁻⁴ 29 / 6.0·10⁻³
24 18 / 8.1·10⁻¹³ 20 / 1.6·10⁻⁷ 20 / 2.3·10⁻⁵ 24 / 7.3·10⁻⁴ 29 / 6.0·10⁻³
11 20 / 5.8·10⁻¹³ 20 / 9.3·10⁻⁸ 21 / 1.9·10⁻⁵ 22 / 7.3·10⁻⁴ 25 / 6.5·10⁻³
6 22 / 8.9·10⁻¹³ 23 / 9.8·10⁻⁸ 23 / 1.9·10⁻⁵ 23 / 6.4·10⁻⁴ 25 / 5.1·10⁻³
3 35 / 8.8·10⁻¹³ 36 / 1.4·10⁻⁷ 36 / 2.7·10⁻⁵ 34 / 7.3·10⁻⁴ 35 / 4.6·10⁻³

Read down a column and the error does not move. At sixteen working bits it is 2.2, 2.3, 1.9, 1.9 and 2.7 times 10⁻⁵ while the preconditioner falls from fifty-three bits to three — a spread of 1.4 across a factor of 2⁵⁰. At eleven bits it is 7.3·10⁻⁴ five times over.

Read across a row and the steps are the preconditioner’s. At three bits they are 35, 36, 36, 34, 35 — flat, whatever the working arithmetic is doing.

And the two costs do not add

There is one row of the grid worth reading on its own, because it is the configuration a code would actually ship and it is not the corner of the table. At three preconditioner bits and eleven working bits the run takes 34 steps and returns 7.3·10⁻⁴ — which is the same step count as a three-bit preconditioner in double, and the same error as an exact preconditioner at eleven bits, to two figures. Neither number has been degraded by the presence of the other, and both are what the single-knob sweeps predicted for their own knob.

That is what “separable” means operationally: the two sweeps that this essay already contains are, between them, a complete description of the grid. Nothing had to be measured at the corners to know what the corners would do — which is exactly the claim a grid is run to test, and the reason it was worth running rather than assuming.

That is the part worth having, because it is not obvious in advance and it decides whether a code may take both reductions.

A three-bit preconditioner alone costs 35 steps. Eight-bit working arithmetic alone costs 29. Both together cost 35 — not the 46 an additive penalty would give, and not more. The worse of the two dominates and the other is free.

A badly preconditioned search direction computed in a coarse arithmetic could plausibly have been worse than either: a direction that is already wrong, rounded further, in a method whose whole mechanism is a sequence of conjugate directions. It is not. The reason is the same one the section above gives for the preconditioner alone — M⁻¹ enters only through the direction, and A and b enter through the residual — and the two error sources travel down those two channels without meeting.

So the practical rule is the strongest form of the essay’s finding. The two decisions are independent: choose the working precision from the accuracy wanted, choose the preconditioner’s precision from what the step count is worth, and neither choice constrains the other. That is a rare thing on this site, where most pairs of knobs interact — a step count and a penalty hand over to each other, a rank and a tolerance trade against each other — and it is worth stating precisely because independence is usually the thing a measurement takes away rather than grants.

| 11 | 24 | 7.3·10⁻⁴ | 3.2·10⁻¹³ | | 8 | 29 | 6.0·10⁻³ | 2.5·10⁻¹³ |

Read the columns in order. The step count goes 18, 20, 20, 24, 29 — it barely moves, and at eight bits it is still well under the unpreconditioned 39. The error goes through five orders of magnitude, and the ratio of the error to the unit roundoff is 2.7, 1.5, 1.5, 1.5 across the four reduced precisions: the accuracy is set by the arithmetic and by nothing else.

So the iteration converges just as fast to a different answer. That is the asymmetry the essay is for, and it inverts the intuition that low precision makes a method work harder. It does not make this one work harder; it makes it arrive somewhere else at the same speed.

And the residual does not notice

The fourth column above is the one that should be uncomfortable.

working bits reported residual true error ratio
24 1.1·10⁻¹³ 1.6·10⁻⁷ 1.5·10⁶
16 9.8·10⁻¹³ 2.2·10⁻⁵ 2.3·10⁷
11 3.2·10⁻¹³ 7.3·10⁻⁴ 2.3·10⁹
8 2.5·10⁻¹³ 6.0·10⁻³ 2.4·10¹⁰

Every quantity a solver can compute says it has converged to rounding. The quantity anybody wants is six to ten orders of magnitude worse. This site’s oldest sentence — a small residual is not a small error — usually arrives as a statement about the problem: a backward-stable algorithm on an ill-conditioned system returns a tiny residual and a large error, and the amplification is κ. Here the problem is the model Laplacian, whose condition number is under fifty, and the gap is ten orders of magnitude.

The mechanism is different and worth separating. In the classical case the residual is computed accurately and is genuinely small, and κ turns it into a forward error. Here the residual is computed in the same low precision as everything else, so what the method is measuring is the residual of the rounded operator applied to the computed answer — a quantity that can be driven to the tolerance without the answer being anywhere near right. The stopping test is not lying about the residual. It is answering a question about a different matrix.

The rule this produces

The received rule for mixed precision is about which parts are cheap or which parts are only approximate anyway. Both are wrong here, and both point at the same wrong answer: the preconditioner is the approximate part, so a careless reading says it is the part that needs care, and the measurement says it is the part that can be rounded to three bits.

The rule that fits both experiments is:

A quantity that steers may be rounded. A quantity that measures may not.

The preconditioner steers — it chooses a direction, and the method corrects for a bad choice by construction. The residual measures — it decides how far to move and whether to stop, and there is nothing downstream to correct it against. Iterative refinement is the same rule in the direct case: the residual’s precision is the whole method, and the factorisation, which merely proposes a correction, can be computed at half.

Where the threshold went

The mixed-precision field’s threshold is κu ≈ 1, and it is worth asking what happened to it here, because it does not appear in either table.

For iterative refinement the threshold is real and sharp: past κu = 1 the correction step stops contracting and the method is inert. For the preconditioned iteration the corresponding quantity would be about the preconditioner’s precision, and there is no threshold in that column at all — three bits works, two bits works and is not worth it, and the error never moves.

That is the same fact from the other side. Refinement’s threshold exists because the factorisation is used to solve a system whose answer is then taken as a correction; if the correction is wrong by more than the error it was meant to remove, nothing improves. A Krylov method never takes its preconditioner’s output as an answer. It takes it as a direction and then computes, in the working precision, exactly how far to go — which is why the only threshold in this essay is the one at two bits, where the direction has become so poor that the extra iterations cost more than the preconditioner saves.

What a real code would do with this

Two consequences, and the second is the one worth carrying.

The preconditioner is the obvious thing to put in low precision, and the measurement here is strong evidence for a practice that already exists — half-precision preconditioners are used, and the usual justification is that they are cheap and the loss is small. The loss measured here is not small, it is zero, at every format down to four bits, and the only cost is in the iteration count.

And a low-precision iteration needs its stopping test computed somewhere else. This is the part that is not standard practice and follows directly from the fourth column above. A method run in a reduced working precision with its convergence test computed in that same precision will stop, will report success, and will be wrong by u — and the report is not distinguishable from a correct one by anything inside the run. The fix is the one refinement uses: compute the residual, occasionally, in a higher precision than the iteration. That is one product with A per check, at a precision the iteration is not otherwise paying for.

Refinement thresholds by format, against a problem at κ = 10⁴A 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 = 39.063 — past the thresholdκ·u = 4.883 — past the thresholdκ·u = 4.883 — past the thresholdκ·u = 6·10⁻⁴ — refinement recoversκ·u = 1.1·10⁻¹² — refinement recoversthe problem is at κ = 10⁴; a format works when κ·u < 1thresholds are 1/u, a property of the arithmetic2 of 5 formats clear this κ
Fig. 6 The formats this comparison is drawn between, from the mixed-precision field. Every one of them is above the three significand bits at which a preconditioner still returns thirteen correct digits — and the same formats decide the answer entirely when they are used for the working arithmetic.

Why the preconditioner only steers, in the derivation rather than in the result

The measurement above is strong enough on its own, and it is worth seeing where in the method the asymmetry comes from, because the same reading says which other components can be rounded.

Preconditioned conjugate gradients computes, at each step, a direction p, a step length α, and an update to the residual. The preconditioner enters in exactly one place: the direction is built from M⁻¹r rather than from r. The step length is

α  =  (rᵀ M⁻¹ r) / (pᵀ A p)

and the numerator uses M⁻¹ while the denominator does not — but the numerator is also the quantity the method compares against itself from step to step, so an error in M⁻¹ scales both the direction and its own length consistently. What decides how far the iterate actually moves along p is pᵀAp, computed from A.

So a wrong M⁻¹ produces a direction that is a worse descent direction, and the method then takes exactly the right step along it. That is why the answer does not move: there is no path from M to the fixed point of the iteration. The fixed point is Ax = b.

The same reading says which other quantities are safe. A restart’s shifts, a smoother’s weight, a line search’s initial guess — anything the method treats as a proposal and then measures — can be computed carelessly. Anything that enters the convergence test, the residual, or the final update cannot.

The one place where a rounded preconditioner does damage

There is a failure mode this experiment does not show, and it is worth naming because it is the reason the practice is not simply free.

Rounding the output of M⁻¹ perturbs a direction. Rounding the construction of M is a different operation: an incomplete Cholesky factorisation computed in low precision can meet a nonpositive pivot and fail to exist, and an incomplete factorisation is far more prone to that than a complete one because it has already thrown away the entries that would have kept the pivots positive. A failure there is not a slower descent; it is no preconditioner at all.

That is the same shape as the message and the word, where a factorisation chosen for its communication cost stops having an answer to return past a computable condition number — and the two together suggest the rule for low precision inside a solver has a second clause. A quantity that steers may be rounded; a quantity whose existence depends on the arithmetic is a third category, and it fails by refusing rather than by degrading.

What the incomplete factor’s own residual says

The preconditioner here is not accurate and never claimed to be: ‖A − LLᵀ‖/‖A‖ = 0.0825, printed on every figure in this essay, and asserted by the iterative field to be large. It is the one residual on this site whose assertion points the other way — a small one would mean the incomplete factorisation had stored the entries it was built to discard.

Put that beside the three-bit result and the picture is sharper than either alone. The preconditioner is already an 8% approximation to A before any rounding; rounding its application to three significand bits perturbs a quantity that was never close. What the experiment measures is not that low precision is harmless in general — it is that this particular quantity has so much slack in it that a format below anything hardware offers still lands inside the slack.

What is left

A real half-precision run. Everything here simulates precision by rounding double results, which is float.js’s standing method and is exactly right for the significand. What it does not model is what a device actually does: fused multiply-add, accumulation in a wider register, and the exponent range — an fp16 iteration on this problem would meet overflow before it met precision.

And the preconditioner’s own construction. The factor here is computed in double and its application is rounded. Computing the incomplete Cholesky factorisation itself at low precision is a different experiment, and a more delicate one: the factorisation can fail outright, since an incomplete Cholesky meets a nonpositive pivot much more readily than a complete one, and a failure is not a slower descent. That is the shape of the finding in the message and the word, where a method that saves communication by squaring the condition number stops having an answer to return at all.

A derivative that may be rounded by six orders of magnitude

This page asks which parts of a solver tolerate a shorter format. There is a sharper version of the same question: which parts tolerate being wrong, and by how much. A Newton method’s Jacobian tolerates being wrong in the tenth digit and costs nothing for it.

Newton on the Bratu problem: analytic Jacobian, differenced Jacobian at ε = 10^-6, and matrix-freeThree residual sequences, all starting from zero. The analytic Jacobian gives 8, 0.052, 3·10⁻⁶, 5.2·10⁻¹³; a Jacobian differenced at ε = 10^-6, whose entries are correct to about 1.3·10⁻¹⁰, gives 8, 0.052, 3·10⁻⁶, 4.6·10⁻¹³. They stop at the same residual. The matrix-free run, where GMRES sees only a closure and no entry exists anywhere, lands 8.1·10⁻¹⁶ from the analytic answer in 438 products.0123456710⁻¹⁴10⁻¹²10⁻¹⁰10⁻⁸10⁻⁶10⁻⁴10⁻²1Newton step‖F(x)‖analytic Jdifferenced Jmatrix-freeone fixed point, three derivativesanalytic floor4.2·10⁻¹³differenced floor3.9·10⁻¹³matrix-free floor3.8·10⁻¹³products used, matrix-free438the derivative chooses the stepand the residual decides the answer
Fig. 7 The same residual sequence from an analytic Jacobian and from a difference quotient six orders of magnitude worse. The derivative appears only in the step; the residual is evaluated exactly.

What links here

Computed from the collection, not written here: the essays that point at this one.

Shares its objects with

Essays that name at least two of the same things, and that neither author linked.

Named objects

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

Conjugate gradientsForward errorHalf-precisionIncomplete choleskyMixed-precisionPreconditioningResidualStopping criterionUnit roundoff