Orthogonal is a number
Orthogonality is the load-bearing property of numerical linear algebra. Almost every stable algorithm in the subject works by applying orthogonal transformations, for the reason set out in the condition number is an amplifier: an orthogonal matrix has κ = 1, so it cannot amplify an error that is already present. QR factorisation, the symmetric eigenvalue problem, the SVD, every least-squares method worth using — all of them are sequences of orthogonal steps.
Which makes the word worth examining. “Q is orthogonal” means QᵀQ = I. In the algebra that is an equation. In the arithmetic it is a measurement, and the measurement has a value.
What the number means
‖QᵀQ − I‖ collects every deviation from orthogonality into one quantity. The diagonal entries measure how far each column is from having unit length; the off-diagonal entries are the cosines of the angles between pairs of columns, scaled by their lengths.
For Householder QR on any matrix, in double precision, it is around 10⁻¹⁵ — a few units of rounding times a modest factor for the size. That number does not depend on the condition number of the matrix, which is the surprising and important part, and it is the subject of a reflection cannot stop being one.
For classical Gram–Schmidt on the eight-by-eight Hilbert matrix it is 1. Not 10⁻³, not 10⁻¹. One. The largest off-diagonal entry of QᵀQ is 1.0, and two unit vectors whose inner product is 1 are the same vector.
Unit length is not perpendicularity
The upper table in the figure has an exact 1 down its whole diagonal, to twelve digits.
That is not a coincidence and it is the reason this failure goes unnoticed. Gram–Schmidt normalises each column as its last act, dividing by the computed norm, so every column comes out with length 1 to within a rounding whatever else has gone wrong. A check that verified the columns were unit vectors — which is the check somebody writes when they are being careful — would pass.
The information is entirely in the off-diagonal, and getting at it costs a matrix product: form QᵀQ, subtract the identity, take a norm. For a thin Q with n columns that is O(mn²), the same order as the factorisation itself, so it is not something to do inside a production loop. It is exactly something to do in a test.
The factorisation is still correct
Here is the part that makes this genuinely difficult rather than merely subtle.
Both factorisations satisfy ‖A − QR‖/‖A‖ ≈ 10⁻¹⁷. The classical Gram–Schmidt factors multiply back to give the original matrix to full double-precision accuracy. The factorisation is of the right matrix, it is accurate, and its Q is not orthogonal.
So the site’s rule — no decomposition drawn without its residual printed — is necessary and is not sufficient. ‖A − QR‖ certifies that the factors factorise; ‖QᵀQ − I‖ certifies that one of them is what it claims to be. They are different questions and a figure showing a QR carries both.
This is not a hypothetical concern about a quantity nobody uses. Every downstream use of Q assumes QᵀQ = I. Solving least squares by QR computes Qᵀb and then back-substitutes, which is correct only if Q is orthogonal. An orthogonal-basis method for an eigenvalue problem re-orthogonalises precisely because it does not trust the property to survive. Feed a non-orthogonal Q into any of them and the result is wrong in a way that is not attributable to the factorisation, because the factorisation was fine.
How bad it gets, as a function of the matrix
The loss is not a fixed penalty. It scales with the condition number of the matrix being factorised, and it does so at a rate that differs by method.
Reading numbers off that: at κ = 10⁵, classical Gram–Schmidt has ‖QᵀQ − I‖ ≈ 10⁻⁸ and modified has 10⁻¹². At κ = 10⁹ classical is at 0.45, which is to say the columns are no longer usefully a basis at all, and modified is at 10⁻⁸. Householder is at 1.8·10⁻¹⁵ at both, and at every other point on the axis.
The κ² and κ behaviours are classical results — Björck’s analysis of modified Gram–Schmidt is from 1967 — and what the figure adds is that they are this code’s behaviour and not a citation. The predictions were drawn before the measurements and the measurements are on them.
What the flatness of the Householder line means
Every other quantity on this site gets worse as the problem gets harder. The Householder line does not, and the reason is structural rather than a matter of degree.
A Householder reflection is I − 2vvᵀ for a unit vector v. Rounding v gives a slightly different unit vector — and I − 2v’v’ᵀ is still exactly a reflection, still exactly orthogonal, for whatever v’ the rounding produced. The rounding perturbs which reflection is in hand; it cannot make the thing in hand stop being one.
Gram–Schmidt has no such protection. Its Q is assembled from subtractions and divisions, and nothing about the assembly enforces the property. When the subtractions go wrong, the result is a matrix, and there is no structure to fall back on.
That difference — between a property enforced by construction and a property achieved by arithmetic — is one of the recurring lessons in numerical analysis and it is worth taking outside the subject. An invariant maintained by a representation survives rounding. An invariant maintained by careful computation does not.
What to do about it
Three options, and the choice is usually easy.
Use Householder. It costs about twice the arithmetic of Gram–Schmidt for a square matrix, it is what LAPACK does, and it removes the problem entirely. For a dense factorisation there is no reason to do anything else.
Use modified Gram–Schmidt. One word different from classical, no extra cost, and the loss becomes κu instead of κ²u — which for κ up to about 10⁷ is entirely acceptable in double. Two Gram–Schmidts is about what that one word is and why it works.
Re-orthogonalise. Run the Gram–Schmidt step twice against the already-computed columns. “Twice is enough” is a real theorem (Kahan and Parlett), and it restores orthogonality to rounding level for any Q that was not catastrophically bad to begin with. It costs a second pass and it is what iterative Krylov methods do, because there Q is built one column at a time and Householder does not fit the access pattern.
What is not an option is more precision. Classical Gram–Schmidt at 53 bits is worse than modified at 24 on a mildly ill-conditioned matrix, which the slider on the figure above shows directly: drag it down and the curves move together, and the classical line at full precision remains above the modified line at any precision on the scale.
Measuring in the right precision
One implementation point that keeps the figures on this site honest, because it is easy to get backwards.
The factorisations in the sliding figure are performed at whatever significand width the reader has selected. The measurement of ‖QᵀQ − I‖ is always performed in double.
Measuring a 24-bit factorisation’s orthogonality error in 24-bit arithmetic would report it as very nearly zero, because the error is exactly the size of what 24-bit arithmetic cannot see. The matrix product QᵀQ would round to the identity and the figure would show a flat line at machine zero for every method — a beautiful, entirely false result, and one that nothing else in the pipeline would flag.
That single decision — the measurement is always in double — is one line in lib/matrix.js and it
is the most consequential line in the file.
What is asserted here
Four claims, checked as the figures are generated.
Every classical column is a unit vector, to 10⁻¹², which is what makes the failure quiet.
Some pair of them is not perpendicular: the largest off-diagonal entry of QᵀQ must exceed 0.1. If a change ever made classical Gram–Schmidt behave on the Hilbert matrix, this essay’s central figure would stop being true and the build would say so.
Householder’s off-diagonals are below 10⁻¹³, with that tolerance bracketed between the measured noise — around 10⁻¹⁶ — and 10⁻⁶, which would be a genuine failure.
Both factorisations reconstruct A to 10⁻¹⁴, which is the claim that makes the whole essay interesting rather than merely a report of a bug.
And the orthogonality measurement is fed a counterexample: a shear, which has unit columns and is not orthogonal, and which the check must reject. Without that, a scaling error in the routine would make every method on this site look excellent. Assertions that reject is the thread, and this is the instance that guards the most figures.
Where this goes
Two Gram–Schmidts takes the pair apart line by line, and is the clearest instance on the site of two algorithms that a derivation cannot distinguish. A reflection cannot stop being one is the structural argument for why Householder does not degrade. And the projection and the right angle is what orthogonality is for: the least-squares solution is defined by a perpendicularity condition, and the accuracy with which that condition can be enforced is exactly the accuracy of the Q used to enforce it.
The Gram matrix as a diagnostic
QᵀQ has a name outside this context: it is the Gram matrix of the columns, the table of all pairwise inner products. It is worth recognising, because the same object answers several questions that are usually treated separately.
Its diagonal entries are the squared lengths. Its off-diagonal entries, divided by the lengths, are the cosines of the angles between columns. Its determinant is the squared volume of the parallelepiped the columns span, so a Gram determinant near zero means the columns are nearly dependent. Its eigenvalues are the squares of the singular values of Q.
That last identity is why forming a Gram matrix squares a condition number, and it connects this essay directly to the road that squares the problem: the normal equations are the Gram matrix of A, and the reason they lose accuracy is the reason QᵀQ is a sensitive thing to compute.
For a Q that is supposed to be orthonormal, the Gram matrix should be the identity, and the extent to which it is not is the single number this whole field is about. Printing it, as the figure at the top of this essay does, is more informative than printing the norm — the norm says how bad, the table says which pair.
What a bad Q does to a Krylov method
The most common place loss of orthogonality causes real damage is not in a dense factorisation, where Householder is available, but in iterative methods, where it is not.
Arnoldi and Lanczos build an orthonormal basis for a Krylov subspace one vector at a time, each new vector obtained by applying A to the previous one and orthogonalising against everything so far. The access pattern is inherently Gram–Schmidt-shaped: the vectors do not exist in advance, so there is no matrix to reflect.
When orthogonality is lost, two things happen and both are famous. In Lanczos, eigenvalues appear multiple times in the computed spectrum — “ghost” eigenvalues, which are not eigenvalues of anything, and which arise because the basis has silently started to repeat directions. In GMRES, the computed residual stops tracking the true residual, so the method reports convergence it has not achieved.
The standard defences are re-orthogonalisation, which is expensive but reliable, and selective re-orthogonalisation, which is a genuinely subtle piece of engineering. Both exist because the property this essay measures does not survive on its own.
Orthogonality in more than one norm
A brief technical point that the figures here elide, since it occasionally matters.
‖QᵀQ − I‖ can be measured in the Frobenius norm, which is the root sum of squares of all entries, or in the 2-norm, which is the largest singular value. This site uses Frobenius throughout, because it is cheap and because it aggregates every deviation rather than only the worst direction.
The two differ by at most a factor of √n, so for the matrix sizes here they tell the same story. The 2-norm is the right choice when the question is about a specific direction — “how badly does this basis fail for one particular vector” — and Frobenius is the right choice for the question this site asks, which is “how far is this from being an orthonormal basis at all”.
Stating which norm is being used is not pedantry. A great many quoted error figures in this subject are incomparable because their norms differ, and the difference can be a factor of the matrix dimension.
The habit worth keeping
Any time code produces a matrix that is supposed to be orthogonal — a QR factor, an eigenvector matrix, a rotation, a basis — compute ‖QᵀQ − I‖ once and look at it.
It costs a matrix product, it is a single number, and it distinguishes the working case from every common way of getting it wrong. Most of the time the answer is 10⁻¹⁵ and the check was unnecessary. The cases where it is not are the cases where every downstream result is wrong, and nothing else would have said so, because the columns will still be unit vectors and the factorisation will still reconstruct.
That habit, generalised, is the site’s rule. No decomposition without its residual is the same instinct applied to a different property, and between them the two numbers cover most of what can go wrong with a factorisation before anything downstream sees it.