One multiply the compiler removed
Worth reading first: What a float can hold · Cancellation takes the answer, not a digit · The same program, twice.
Everything in this field so far has needed a machine with more than one worker. This does not. It needs one processor, one thread, one core, and a compiler that was allowed to make a substitution every language standard permits.
a*b + c is two operations. A processor with a fused multiply-add computes it as one, forming the
product to full width and rounding the sum once; a processor without one rounds the product first
and the sum second. Both are conforming — IEEE-754 specifies what each operation returns, and says
nothing about which operations a compiler emits — and C and Fortran both explicitly permit the
contraction. No flag in the source records which one happened.
The difference is one rounding of one product: a relative 10⁻¹⁶. Here is what it decides.
From k = 27 the expression as written returns zero. Not a small number: zero, which has no sign, and the sign is the only thing anybody wants from a 2 × 2 determinant.
Where the zero comes from
The matrix is chosen so that its two products are consecutive integers. With x = 2ᵏ,
ad = (x+2)(x+2) = x² + 4x + 4,
bc = (x+1)(x+3) = x² + 4x + 3,
so the determinant is 1 exactly, at every k, and the two products differ by one part in x². Binary64 carries 53 significand bits, so once x² passes 2⁵³ — which is k = 27 — the spacing of the representable numbers near x² is larger than 1 and the two products round to the same float. Their difference is zero.
Nothing has gone wrong in any operation. Each product is correctly rounded, the subtraction of two equal numbers is exact, and the answer is zero. This is cancellation takes the answer in its purest form: the subtraction introduces no error at all and exposes error the operands were already carrying, and here the operands were carrying all of it.
What the fusion recovers
Kahan’s algorithm for the same determinant is three lines and needs the fusion:
w = b·c rounded
e = fma(b, c, −w) the exact residual of that rounding
f = fma(a, d, −w) ad − w, with one rounding
det = f − e
The second line is where the fusion earns its keep. fma(b, c, −w) computes b·c − w with a single
rounding, and since w is the rounded product, the true value of b·c − w is exactly representable —
so e is the exact error of the rounded product, recovered by an instruction. Without the fusion
that quantity needs Dekker’s splitting, six operations and a 26-bit split of each operand.
Then f is ad − w computed to one rounding, which is small and therefore exact, and the answer is f − e. The measured error is zero at every k in the sweep, not merely small.
That the sign of e is subtracted rather than added is the whole algorithm, and it is worth
recording that getting it wrong returns 7 where the answer is 1 — and does so only in the regime
where the naive route has already failed, so a test that checked the easy sizes would have passed.
Where this bites in practice
A 2 × 2 determinant is not a corner of the subject. It is:
An orientation test. Whether three points turn left or right is the sign of exactly this determinant, and computational geometry has an entire literature about it — exact predicates, adaptive precision, filters — for the reason this figure shows. Numerical linear algebra mostly does not, and has the same expression in a dozen places.
A 2 × 2 pivot. The symmetric indefinite factorisations pick between a 1 × 1 and a 2 × 2 pivot, and the choice reads a determinant of exactly this shape. When symmetry is not enough is where this site measures that decision; the number it reads is one this essay says two builds may disagree about.
A Givens rotation’s discriminant, a discriminant of a quadratic, a cross product, an area. Every one of them is ad − bc.
And a definiteness test. A symmetric 2 × 2 is positive definite exactly when a > 0 and ad − b² > 0, so a determinant computed as zero turns a definite matrix into a semi-definite one. A matrix that is definite on one machine takes that all the way, with a census rather than an example.
Which of the two is right
An awkward question, and the answer is not the one the figure suggests.
On this family the fused form is exactly right at every size and the unfused form is exactly wrong, so the temptation is to conclude that fusing is the correct implementation and the contraction is a hazard to be turned off. That conclusion is wrong, and the measurement that shows it is one field essay further on: over two hundred Gram matrices whose definiteness is settled exactly in BigInt rationals, the two forms disagree twenty-six times, and the fused form is the one that is right nine of those times. The unfused form is right seventeen.
The difference is that this essay’s determinant is computed by an algorithm designed around the fusion. Kahan’s three lines use the fma to recover an exact quantity, which is a use of the instruction rather than an accident of compilation. Take the same instruction and apply it to an ordinary expression nobody designed for it, and it moves the answer by one rounding in a direction that has no reason to be the right one.
So the two claims to keep apart:
- an algorithm written for the fusion is better than the expression it replaces, measurably and by a lot — this figure, where one is exact and the other returns zero;
- an expression the compiler happened to contract is not better or worse, it is different, and which of the two lands closer to the truth is a property of the data.
The first is a reason to write fma explicitly. The second is a reason not to imagine that a
compiler flag is a correctness setting.
Why no residual can see it
The site’s standing instrument for is this number trustworthy is a residual: compute the answer, put it back into the problem, and measure what is left. It does not work here, and the reason is worth stating because it is the reason this failure is silent.
A residual is computed from the same expression the answer was. If the compiled form contracted the multiply and the add, it contracts them in the residual too — so the residual is computed in the arithmetic whose behaviour is in question, and it reports agreement with itself. The refusal this essay publishes is that statement mechanised: an assertion that a residual computed the same way detects the contraction is fed the case and must reject.
This is a genuinely different failure from the ones the site’s other eighteen fields handle. There, a residual is small and the answer is wrong because the problem was sensitive, and the two measurements together account for it — the identity three errors and one number sets out. Here the residual is not merely uninformative; it is computed by the thing being asked about.
The instruments that do work are the ones that share no arithmetic with the computation: an exact
determinant in BigInt rationals, which is what this site’s exact.js provides and what the
definiteness census uses for its verdict; or an interval computed in directed rounding, which is
proving the answer is in the box’s machinery. Both are
second routes in the site’s usual sense, and both cost more than the computation they are checking.
How large the difference between the two forms is
Bounded, and small, which is what makes the determinant result surprising rather than obvious.
Over ten thousand random arguments, the fused and unfused forms of a*b + c differ by at most
1.36·10⁻¹⁶ relative to |ab| + |a*b+c| — 0.61 of a unit roundoff, which is one rounding of the
product and one of the sum, as it must be. There is no case in which the two forms differ by more
than that.
So the entire content of this essay is a difference of one rounding, and it decides a sign. The mechanism is the one the whole field runs on: a rounding committed at the scale of the products, followed by a subtraction that removes everything except the rounding. The products are 10¹⁶ and the answer is 1, so the summation condition number of this two-term sum is 3.6·10¹⁶ — the second highest entry in the vector that hides it’s census, in a sum with two terms in it.
The same instruction, in a longer computation
A determinant is two products, so the contraction’s effect is a single rounding and the analysis is exact. What happens when the expression is longer is worth measuring rather than extrapolating, because both the size and the character of the difference change.
Take Horner’s rule, which is s = s*x + c in a loop and is therefore the contraction’s natural
habitat — every step of it is a multiply-add. Evaluate (x − 1)⁶, expanded into
x⁶ − 6x⁵ + 15x⁴ − 20x³ + 15x² − 6x + 1, at 401 points within 10⁻³ of x = 1. The true value is a
sixth power and is never negative; it is under 10⁻¹⁸ across the whole window, which is below the
rounding of the terms that produced it.
The unfused evaluation returns a negative value at 179 of the 401 points. The fused one returns a negative value at 196. And the two disagree about the sign at 98 — a quarter of the window.
The largest difference between the two evaluations anywhere in that window is 1.44·10⁻¹⁵: six roundings rather than one, exactly as the bound says. What has changed is not the size but the consequence, because there is no longer a single answer that is right — both traces are made entirely of rounding, and neither is more nearly the sixth power than the other. A square that evaluates negative is that measurement, and it is where the field stops being able to say which build is correct.
What a caller can do
Four options, in ascending order of cost.
Use the fused form deliberately. Kahan’s three lines, with an explicit fma intrinsic rather
than a a*d - b*c the compiler may or may not contract. The error is under two ulps of the true
determinant whatever the cancellation, which is the strongest statement available about any
expression on this site. This is free and it is the answer for a 2 × 2.
Forbid the contraction. -ffp-contract=off and its equivalents make the compiled form
predictable. That buys reproducibility across builds and buys the less accurate of the two forms,
which is the trade this field keeps producing.
Filter. Compute the naive determinant along with a bound on its error; if the bound does not exclude zero, fall back to something exact. This is what computational geometry’s adaptive predicates do and it is nearly free in the common case, because the common case is a determinant that is not near zero and the bound settles it in two extra operations. The structure is the one an estimate that can be fooled describes for condition estimation, with the sign reversed: there a cheap estimate can be wrong in the flattering direction, here a cheap bound is only ever allowed to return unknown.
Compute exactly. Two products in a twoProduct expansion and an exact sum of four terms, which is what this essay’s ground truth is. About twelve operations for a 2 × 2 and it settles the question completely — and the expansion is the same object the reproducible summation policies of the sum that cannot be wrong are built from, so a code base that has one has the other.
The point of listing them is that all four exist, none is difficult, and the default — write
a*d - b*c and let the compiler decide — is the one option that gives an answer whose accuracy
depends on a flag nobody set.
What the sweep says about the format
One reading of the hero figure that is easy to miss: the failure point is not a property of the matrix, and moving to a wider float does not remove it.
The naive determinant fails at k = 27 because 2²ᵏ crosses 2⁵³. In binary32, with 24 significand bits, the same family fails at k = 12; in a hypothetical 113-bit format it fails at k = 57. The failure moves and it does not go away, because the family is parameterised by exactly the quantity the format is: how many bits separate the products from their difference.
Every real problem has a fixed k, of course, and a wider float may put it on the safe side. That is the ordinary and correct use of precision and this site has a whole knob for it — precision as the knob is the arithmetic field’s founding observation. What the figure adds is that the shape is unchanged: there is a threshold, it is set by the format, and on either side of it the naive expression is either exactly right or exactly wrong, with nothing in between. A determinant near that threshold is not approximately computable. It is computable or it is zero.
And the fused route is exact on both sides of it, at every size in the sweep, which is why the recommendation is an algorithm rather than a format.
One line
A compiler is allowed to replace two roundings with one, from source that says nothing about it, and on an expression whose subtraction removes everything except the rounding that is the whole of the answer.
At other settings
What links here
Computed from the collection, not written here: the essays that point at this one.
Reads more easily once this is understood
Essays that name this one as worth reading first.
Shares its objects with
Essays that name at least two of the same things, and that neither author linked.
- A norm that overflows before it is a norm — both name catastrophic cancellation, significand
- Eight bits, and a format that breaks the rules — both name ieee 754, significand
- The numbers below the smallest one — both name ieee 754, significand
- The other half of a format — both name ieee 754, significand
Named objects
A flat tag is an object no other essay names yet.
Bitwise reproducibilityCatastrophic cancellationDefiniteness testDeterminantError-free transformationExpression contractionFused multiply-addIEEE 754Significand