Skip to content
The Lumenary
Early undergraduateUndergraduate (first or second year) 120 min

Numerical methods

How computers find roots, derivatives and integrals with numbers that are almost never exact — and how to prove how wrong the answer can be.

Formally verified · 19 LeanComputationally tested · 3 PythonAI-drafted · awaiting human reviewMathematically reviewed: Awaiting human review
MotivationH

Numbers that are almost right

Nearly four thousand years ago a scribe in Mesopotamia pressed a small clay tablet — now called YBC 7289 and kept at Yale — with a square, its diagonals, and the number 1;24,51,101;24,51,10 in base 6060. That is 1+2460+51602+10603≈1.41421301 + \frac{24}{60} + \frac{51}{60^2} + \frac{10}{60^3} \approx 1.4142130, the ratio of a square's diagonal to its side, correct to about six decimal places. The true value 2=1.41421356…\sqrt 2 = 1.41421356\ldots is irrational: no finite expansion in any base is exact. Every practical computation with it is an approximation.

Modern computers face the same fact on a vast scale. A weather model, a bridge design or a vaccine-trial analysis performs billions of arithmetic operations on numbers stored with about sixteen significant digits, so almost every operation rounds. Usually that is harmless. Sometimes it is not: in 1982 the Vancouver Stock Exchange started a new index at 10001000 and recomputed it thousands of times a day, truncating to three decimals each time; within two years it read about 520520 while the correctly computed value was above 10001000.

Numerical analysis is the mathematics of computing with approximations: designing methods that find roots, derivatives and integrals from finitely many arithmetic operations, and proving how large their errors can be. This lesson treats the three classical sources of error — rounding, truncation and the failure of hypotheses — through floating-point arithmetic, root finding, interpolation and differentiation, and numerical integration.

It assumes calculus of one variable (the mean value theorem and Taylor's theorem with remainder) and some programming.

IntuitionH

Three kinds of error, and how fast they shrink

Computing ∫01e−x2dx\int_0^1 e^{-x^2}dx on a laptop involves three different approximations.

  • Modelling error: the integral itself may be only a model of something physical. Numerical analysis takes the mathematical problem as given.
  • Truncation (discretisation) error: we replace the integral by a finite sum, say the trapezoidal rule with nn strips. Even with exact arithmetic the sum differs from the integral, typically by about C/n2C/n^2.
  • Rounding error: every operation in the sum is done in floating point and is rounded to about 1616 significant digits.

Truncation error shrinks as we work harder; rounding error tends to grow with the number of operations. Good methods balance the two, and good analysis predicts the balance. The key measure of a method is how fast its error shrinks: an error that is halved at each step (bisection) gains one correct binary digit per step, while an error that is squared at each step (Newton's method) doubles the number of correct digits per step:

10−1→10−2→10−4→10−8→10−16.10^{-1} \to 10^{-2} \to 10^{-4} \to 10^{-8} \to 10^{-16}.
DefinitionsH

Definitions

Definition— floating-point number

A (binary, normalised) floating-point number with precision pp is a number ±m⋅2e\pm m \cdot 2^{e} where the significand mm is an integer with 2p−1≤m<2p2^{p-1} \le m < 2^p and the exponent ee is an integer in a fixed range. The IEEE 754 binary64 format ("double precision", Python's float) has p=53p = 53 and exponents giving magnitudes from about 10−30810^{-308} to 1030810^{308}, plus zero, subnormal numbers, ±∞\pm\infty and NaN ("not a number").

Definition— machine epsilon and unit roundoff

Machine epsilon ε\varepsilon is the gap between 11 and the next larger floating-point number: ε=21−p\varepsilon = 2^{1-p}, which is 2−52≈2.2×10−162^{-52} \approx 2.2 \times 10^{-16} for binary64. The unit roundoff is u=ε/2=2−53≈1.1×10−16u = \varepsilon/2 = 2^{-53} \approx 1.1 \times 10^{-16}, the largest relative error made by rounding to nearest.

Definition— absolute and relative error

If x^\hat x approximates xx, its absolute error is ∣x^−x∣|\hat x - x| and, for x≠0x \ne 0, its relative error is ∣x^−x∣/∣x∣|\hat x - x|/|x|. A relative error of about 10−k10^{-k} means about kk correct significant digits.

Definition— order of convergence

A sequence xn→rx_n \to r with errors en=∣xn−r∣e_n = |x_n - r| converges with order p≥1p \ge 1 if en+1≤Cen pe_{n+1} \le C e_n^{\,p} for some constant CC and all large nn (with C<1C < 1 when p=1p = 1). Order 11 is linear, order 22 quadratic. In practice one estimates p≈log⁡(en+1/en)/log⁡(en/en−1)p \approx \log(e_{n+1}/e_n)/\log(e_n/e_{n-1}).

Definition— condition number

For a differentiable function ff with f(x)≠0f(x) \ne 0, the (relative) condition number κf(x)=∣xf′(x)f(x)∣\kappa_f(x) = \left|\frac{x f'(x)}{f(x)}\right| measures how much a small relative change in xx is magnified in f(x)f(x). A problem with a large condition number is ill-conditioned: no method can solve it accurately from inexact data.

ProofH

Floating point and rounding error

Theorem— Proposition 1 (rounding)

If xx is a real number in the normal range of binary64 and fl(x)\mathrm{fl}(x) is the nearest binary64 number, then fl(x)=x(1+δ)\mathrm{fl}(x) = x(1 + \delta) with ∣δ∣≤u=2−53|\delta| \le u = 2^{-53}.

Proof

Take x>0x > 0 and let 2E≤x<2E+12^{E} \le x < 2^{E+1}. In this interval the binary64 numbers are m⋅2E−52m \cdot 2^{E - 52} for 252≤m<2532^{52} \le m < 2^{53}, spaced 2E−522^{E-52} apart (and 2E+12^{E+1} is also one). So the nearest one is within half the spacing: ∣fl(x)−x∣≤2E−53≤2−53x|\mathrm{fl}(x) - x| \le 2^{E - 53} \le 2^{-53} x.

∎

IEEE 754 requires ++, −-, ×\times, ÷\div and  \sqrt{\ } to be correctly rounded: the computed result is fl\mathrm{fl} of the exact result. This gives the standard model fl(a∘b)=(a∘b)(1+δ)\mathrm{fl}(a \circ b) = (a \circ b)(1 + \delta), ∣δ∣≤u|\delta| \le u, on which error analysis is built. So floating-point arithmetic is not random or vague; it is exact arithmetic followed by one well-defined rounding. But it is not ordinary arithmetic either: 0.10.1 is stored as 3602879701896397255\frac{3602879701896397}{2^{55}}, so 0.1+0.2≠0.30.1 + 0.2 \ne 0.3 in floating point, and addition is not associative: (1+2−53)+2−53=1(1 + 2^{-53}) + 2^{-53} = 1 but 1+(2−53+2−53)=1+2−521 + (2^{-53} + 2^{-53}) = 1 + 2^{-52}.

Theorem— Theorem 2 (cancellation)

Suppose x^=x(1+δ1)\hat x = x(1 + \delta_1) and y^=y(1+δ2)\hat y = y(1 + \delta_2) with ∣δ1∣,∣δ2∣≤u|\delta_1|, |\delta_2| \le u, and x≠yx \ne y. Then

∣(x^−y^)−(x−y)∣≤u (∣x∣+∣y∣),so∣(x^−y^)−(x−y)∣∣x−y∣≤u ∣x∣+∣y∣∣x−y∣.\big|(\hat x - \hat y) - (x - y)\big| \le u\,(|x| + |y|), \qquad \text{so} \qquad \frac{|(\hat x - \hat y) - (x - y)|}{|x - y|} \le u\,\frac{|x| + |y|}{|x - y|}.

Proof

(x^−y^)−(x−y)=xδ1−yδ2(\hat x - \hat y) - (x - y) = x\delta_1 - y\delta_2, and ∣xδ1−yδ2∣≤∣x∣ u+∣y∣ u|x\delta_1 - y\delta_2| \le |x|\,u + |y|\,u.

∎

The subtraction itself is exact or nearly so; the danger is that it exposes errors already present in x^\hat x and y^\hat y. If xx and yy agree in their first kk digits, the factor (∣x∣+∣y∣)/∣x−y∣(|x| + |y|)/|x - y| is about 10k10^{k}, and kk digits are lost. This is catastrophic cancellation, and (∣x∣+∣y∣)/∣x−y∣(|x| + |y|)/|x - y| is exactly the condition number of subtraction.

Example— Two cures for cancellation

  • For small xx, cos⁡x\cos x is close to 11, and (1−cos⁡x)/x2(1 - \cos x)/x^2 computed directly loses digits: at x=10−8x = 10^{-8} the computer finds cos⁡x\cos x rounds to exactly 11 and returns 00 instead of 12\tfrac12. The identity 1−cos⁡x=2sin⁡2(x/2)1 - \cos x = 2\sin^2(x/2) removes the subtraction, and 2sin⁡2(x/2)/x22\sin^2(x/2)/x^2 is accurate to full precision.
  • The roots of x2−108x+1=0x^2 - 10^8 x + 1 = 0 are about 10810^8 and 10−810^{-8}. The formula 108−1016−42\frac{10^8 - \sqrt{10^{16} - 4}}{2} for the small root subtracts two nearly equal numbers and is wrong by 25%25\%. Computing the large root first and using the product of the roots, x1x2=1x_1 x_2 = 1, gives the small root to full precision.

A computed answer is backward stable if it is the exact answer to a slightly perturbed problem (perturbations of relative size about uu). Then its accuracy is limited only by the problem's condition number: error ≲\lesssim condition number ×\times backward error. This way of thinking, due largely to James Wilkinson, separates what is the method's fault from what is the problem's.

ProofH

Finding roots: bisection and Newton's method

Bisection. Given a continuous ff on [a,b][a, b] with f(a)≤0≤f(b)f(a) \le 0 \le f(b), look at the midpoint m=(a+b)/2m = (a + b)/2. If f(m)≤0f(m) \le 0, replace aa by mm; otherwise replace bb by mm. Repeat.

Theorem— Theorem 3 (bisection)

After nn steps the interval [an,bn][a_n, b_n] has length (b−a)/2n(b - a)/2^n, still satisfies f(an)≤0≤f(bn)f(a_n) \le 0 \le f(b_n), and contains a root cc of ff. The midpoint mnm_n satisfies ∣mn−c∣≤(b−a)/2n+1|m_n - c| \le (b - a)/2^{n+1}. So bisection always converges, linearly with rate 12\tfrac12.

Proof

The length is halved at each step, and the sign condition is preserved by construction: we keep [m,bn][m, b_n] only when f(m)≤0f(m) \le 0, and [an,m][a_n, m] only when f(m)>0f(m) > 0. By the intermediate value theorem ff has a root c∈[an,bn]c \in [a_n, b_n], and the midpoint of an interval is within half its length of every point in it.

∎

Bisection is slow — about 3.33.3 steps per decimal digit — but it needs only continuity and a sign change, and it cannot fail. Its proof rests on the completeness of R\R: the nested intervals shrink to a point, which is a root.

Newton's method. Replace ff near the current guess xnx_n by its tangent line, and take the tangent's zero as the next guess:

xn+1=xn−f(xn)f′(xn).x_{n+1} = x_n - \frac{f(x_n)}{f'(x_n)}.

For f(x)=x2−af(x) = x^2 - a this is xn+1=12(xn+axn)x_{n+1} = \frac12\left(x_n + \frac{a}{x_n}\right) — the method Heron of Alexandria described in the first century CE. (It is one plausible way the Babylonian value could have been found, but how the scribes actually computed it is not recorded.)

Theorem— Theorem 4 (local quadratic convergence of Newton's method)

Let ff be twice continuously differentiable on an open interval containing rr, with f(r)=0f(r) = 0 and f′(r)≠0f'(r) \ne 0. Then there is δ>0\delta > 0 such that for every starting value with ∣x0−r∣≤δ|x_0 - r| \le \delta, the Newton iterates are defined, stay within δ\delta of rr, converge to rr, and satisfy

∣xn+1−r∣≤M ∣xn−r∣2,M=max⁡∣x−r∣≤δ∣f′′(x)∣2min⁡∣x−r∣≤δ∣f′(x)∣.|x_{n+1} - r| \le M\,|x_n - r|^2, \qquad M = \frac{\max_{|x - r| \le \delta}|f''(x)|}{2\min_{|x - r| \le \delta}|f'(x)|}.

Moreover xn+1−r(xn−r)2→f′′(r)2f′(r)\frac{x_{n+1} - r}{(x_n - r)^2} \to \frac{f''(r)}{2f'(r)}.

Proof

Since f′f' is continuous and f′(r)≠0f'(r) \ne 0, there is δ0>0\delta_0 > 0 with f′≠0f' \ne 0 on I0=[r−δ0,r+δ0]I_0 = [r - \delta_0, r + \delta_0]. Let M0M_0 be the quotient MM computed on I0I_0 (finite, since f′′f'' and 1/f′1/f' are continuous on the closed interval), and put δ=min⁡(δ0,1/(2M0))\delta = \min(\delta_0, 1/(2M_0)) (or δ=δ0\delta = \delta_0 if M0=0M_0 = 0). Then M≤M0M \le M_0 on the smaller interval.

Suppose ∣xn−r∣≤δ|x_n - r| \le \delta. Taylor's theorem with the Lagrange remainder at xnx_n gives a ξn\xi_n between xnx_n and rr with

0=f(r)=f(xn)+f′(xn)(r−xn)+12f′′(ξn)(r−xn)2.0 = f(r) = f(x_n) + f'(x_n)(r - x_n) + \tfrac12 f''(\xi_n)(r - x_n)^2.

Dividing by f′(xn)≠0f'(x_n) \ne 0 and rearranging,

xn+1−r=xn−r−f(xn)f′(xn)=f′′(ξn)2f′(xn) (xn−r)2.x_{n+1} - r = x_n - r - \frac{f(x_n)}{f'(x_n)} = \frac{f''(\xi_n)}{2f'(x_n)}\,(x_n - r)^2 .

Hence ∣xn+1−r∣≤M∣xn−r∣2≤Mδ ∣xn−r∣≤12∣xn−r∣|x_{n+1} - r| \le M|x_n - r|^2 \le M\delta\,|x_n - r| \le \tfrac12|x_n - r|. By induction every iterate stays within δ\delta of rr, ∣xn−r∣≤δ/2n→0|x_n - r| \le \delta/2^n \to 0, and the quadratic bound holds at every step. Finally ξn→r\xi_n \to r and xn→rx_n \to r, so by continuity the ratio tends to f′′(r)/(2f′(r))f''(r)/(2f'(r)).

∎

The hypotheses are all needed, and Newton's method can fail badly when they are not met or when the start is too far away.

Example— When Newton's method fails or slows down

  • No convergence from a bad start. For f(x)=x3−2x+2f(x) = x^3 - 2x + 2 and x0=0x_0 = 0: x1=0−2−2=1x_1 = 0 - \frac{2}{-2} = 1 and x2=1−11=0x_2 = 1 - \frac{1}{1} = 0. The iterates cycle 0,1,0,1,…0, 1, 0, 1, \dots forever, although ff has a real root near −1.77-1.77. For f(x)=arctan⁡xf(x) = \arctan x, starts with ∣x0∣>1.39|x_0| > 1.39 (roughly) make the iterates oscillate with growing size.
  • Not differentiable at the root. For f(x)=x3f(x) = \sqrt[3]{x} (real cube root), f′(0)f'(0) does not exist and xn+1=xn−xn1/313xn−2/3=−2xnx_{n+1} = x_n - \frac{x_n^{1/3}}{\frac13 x_n^{-2/3}} = -2x_n: every start except 00 diverges.
  • A double root. For f(x)=(x−1)2f(x) = (x - 1)^2, f′(1)=0f'(1) = 0 and xn+1−1=12(xn−1)x_{n+1} - 1 = \frac12(x_n - 1): convergence, but only linear. (For a root of multiplicity mm, the modified step x−mf(x)/f′(x)x - m f(x)/f'(x) restores quadratic convergence.)

The secant method replaces f′(xn)f'(x_n) by the slope f(xn)−f(xn−1)xn−xn−1\frac{f(x_n) - f(x_{n-1})}{x_n - x_{n-1}} through the last two points. It needs no derivative, and under the hypotheses of Theorem 4 it converges with order φ=(1+5)/2≈1.618\varphi = (1 + \sqrt5)/2 \approx 1.618: its errors satisfy en+1≈Cenen−1e_{n+1} \approx C e_n e_{n-1}, and the exponents of ene_n follow the Fibonacci recurrence (see recurrences). Practical root finders, such as Brent's method, combine bisection's safety with the speed of secant-type steps.

ProofH

Interpolation and numerical differentiation

Given n+1n + 1 distinct nodes x0,…,xnx_0, \dots, x_n and values f(xi)f(x_i), there is exactly one polynomial pp of degree at most nn with p(xi)=f(xi)p(x_i) = f(x_i) for all ii: the Lagrange form is p(x)=∑if(xi)∏j≠ix−xjxi−xjp(x) = \sum_i f(x_i)\prod_{j \ne i}\frac{x - x_j}{x_i - x_j}, and uniqueness holds because the difference of two such polynomials has n+1n + 1 roots and degree at most nn.

Theorem— Theorem 5 (interpolation error)

If ff has n+1n + 1 continuous derivatives on [a,b][a, b], which contains the nodes, then for every x∈[a,b]x \in [a, b] there is ξ∈(a,b)\xi \in (a, b) with

f(x)−p(x)=f(n+1)(ξ)(n+1)!∏i=0n(x−xi).f(x) - p(x) = \frac{f^{(n+1)}(\xi)}{(n+1)!}\prod_{i=0}^{n}(x - x_i).

Proof

If xx is a node, both sides are 00. Otherwise let w(t)=∏i(t−xi)w(t) = \prod_i (t - x_i) and choose the constant KK so that g(t)=f(t)−p(t)−Kw(t)g(t) = f(t) - p(t) - K w(t) vanishes at t=xt = x. Then gg has at least n+2n + 2 zeros in [a,b][a, b] (the nodes and xx). By Rolle's theorem g′g' has at least n+1n + 1 zeros between them, g′′g'' at least nn, …, and g(n+1)g^{(n+1)} at least one, ξ\xi. Since p(n+1)=0p^{(n+1)} = 0 and w(n+1)=(n+1)!w^{(n+1)} = (n+1)!, we get 0=f(n+1)(ξ)−K(n+1)!0 = f^{(n+1)}(\xi) - K(n+1)!, and g(x)=0g(x) = 0 is the claimed formula.

∎

More nodes need not help. For Runge's function 1/(1+25x2)1/(1 + 25x^2) on [−1,1][-1, 1], interpolants at equally spaced nodes oscillate wildly near the ends and diverge as n→∞n \to \infty (Runge, 1901), because ∏(x−xi)\prod(x - x_i) is huge there and the derivatives of ff grow fast. Choosing Chebyshev nodes xi=cos⁡(2i+1)π2n+2x_i = \cos\frac{(2i + 1)\pi}{2n + 2} makes max⁡∣∏(x−xi)∣\max|\prod(x - x_i)| as small as possible, namely 2−n2^{-n}, and for functions as smooth as this one the interpolants converge.

Numerical differentiation. Taylor's theorem gives

f(x+h)−f(x)h=f′(x)+h2f′′(ξ),f(x+h)−f(x−h)2h=f′(x)+h26f′′′(η)\frac{f(x + h) - f(x)}{h} = f'(x) + \frac{h}{2}f''(\xi), \qquad \frac{f(x + h) - f(x - h)}{2h} = f'(x) + \frac{h^2}{6}f'''(\eta)

(for the central difference, use the intermediate value theorem to combine the two third-derivative terms). So the truncation error of the forward difference is O(h)O(h) and of the central difference O(h2)O(h^2). But if each value of ff carries an error up to ϵ≈u∣f(x)∣\epsilon \approx u|f(x)|, the forward difference also carries a rounding error up to 2ϵ/h2\epsilon/h, so its total error is at most about

E(h)=h2M2+2ϵh,minimised at h∗=2ϵ/M2, where E(h∗)=2ϵM2.E(h) = \frac{h}{2}M_2 + \frac{2\epsilon}{h}, \qquad \text{minimised at } h^* = 2\sqrt{\epsilon/M_2}, \text{ where } E(h^*) = 2\sqrt{\epsilon M_2}.

With ϵ≈10−16\epsilon \approx 10^{-16} the best step is h≈10−8h \approx 10^{-8}, giving only about 88 correct digits; smaller hh is worse. For the central difference the optimum is h≈ϵ1/3≈10−5h \approx \epsilon^{1/3} \approx 10^{-5}, with about 1111 digits. The third experiment shows both V-shaped error curves.

ProofH

Numerical integration

Divide [a,b][a, b] into nn strips of width h=(b−a)/nh = (b - a)/n with points xk=a+khx_k = a + kh. The composite trapezoidal rule and, for even nn, the composite Simpson rule are

Th=h(12f(x0)+f(x1)+⋯+f(xn−1)+12f(xn)),Sh=h3(f(x0)+4f(x1)+2f(x2)+4f(x3)+⋯+4f(xn−1)+f(xn)).T_h = h\Big(\tfrac12 f(x_0) + f(x_1) + \cdots + f(x_{n-1}) + \tfrac12 f(x_n)\Big), \qquad S_h = \frac{h}{3}\Big(f(x_0) + 4f(x_1) + 2f(x_2) + 4f(x_3) + \cdots + 4f(x_{n-1}) + f(x_n)\Big).

The trapezoidal rule integrates the piecewise-linear interpolant of ff; Simpson's rule integrates a quadratic interpolant on each pair of strips.

Theorem— Theorem 6 (trapezoidal rule)

If ff is twice differentiable on [a,b][a, b] with ∣f′′∣≤M2|f''| \le M_2, then ∣Th−∫abf∣≤(b−a)h212M2|T_h - \int_a^b f| \le \frac{(b - a)h^2}{12}M_2.

Proof

Consider one strip, shifted to [0,h][0, h], and define E(t)=t2(f(0)+f(t))−∫0tf(s) dsE(t) = \frac{t}{2}\big(f(0) + f(t)\big) - \int_0^t f(s)\,ds for 0≤t≤h0 \le t \le h: the error of a single trapezoid of width tt. Then E(0)=0E(0) = 0 and, by the fundamental theorem of calculus,

E′(t)=12(f(0)+f(t))+t2f′(t)−f(t)=12(f(0)−f(t))+t2f′(t),E′(0)=0,E'(t) = \tfrac12\big(f(0) + f(t)\big) + \tfrac{t}{2}f'(t) - f(t) = \tfrac12\big(f(0) - f(t)\big) + \tfrac{t}{2}f'(t), \qquad E'(0) = 0,E′′(t)=−12f′(t)+12f′(t)+t2f′′(t)=t2f′′(t).E''(t) = -\tfrac12 f'(t) + \tfrac12 f'(t) + \tfrac{t}{2}f''(t) = \tfrac{t}{2}f''(t).

So ∣E′′(t)∣≤M22t|E''(t)| \le \frac{M_2}{2}t. Integrating from 00 (using E′(0)=0E'(0) = 0, then E(0)=0E(0) = 0): ∣E′(t)∣≤M24t2|E'(t)| \le \frac{M_2}{4}t^2 and ∣E(t)∣≤M212t3|E(t)| \le \frac{M_2}{12}t^3. Each of the nn strips therefore contributes at most M212h3\frac{M_2}{12}h^3, and nh3=(b−a)h2n h^3 = (b - a)h^2.

∎

Theorem— Theorem 7 (Simpson's rule)

If ff is four times differentiable on [a,b][a, b] with ∣f(4)∣≤M4|f^{(4)}| \le M_4 and nn is even, then ∣Sh−∫abf∣≤(b−a)h4180M4|S_h - \int_a^b f| \le \frac{(b - a)h^4}{180}M_4.

Proof

Consider one pair of strips, shifted to [−h,h][-h, h], and for 0≤t≤h0 \le t \le h let E(t)=t3(f(−t)+4f(0)+f(t))−∫−ttf(s) dsE(t) = \frac{t}{3}\big(f(-t) + 4f(0) + f(t)\big) - \int_{-t}^{t} f(s)\,ds. Differentiating three times (each time some terms cancel):

E′(t)=−23(f(t)+f(−t))+43f(0)+t3(f′(t)−f′(−t)),E'(t) = -\tfrac23\big(f(t) + f(-t)\big) + \tfrac43 f(0) + \tfrac{t}{3}\big(f'(t) - f'(-t)\big),E′′(t)=−13(f′(t)−f′(−t))+t3(f′′(t)+f′′(−t)),E′′′(t)=t3(f′′′(t)−f′′′(−t)),E''(t) = -\tfrac13\big(f'(t) - f'(-t)\big) + \tfrac{t}{3}\big(f''(t) + f''(-t)\big), \qquad E'''(t) = \tfrac{t}{3}\big(f'''(t) - f'''(-t)\big),

with E(0)=E′(0)=E′′(0)=0E(0) = E'(0) = E''(0) = 0. By the mean value theorem f′′′(t)−f′′′(−t)=2tf(4)(ζ)f'''(t) - f'''(-t) = 2t f^{(4)}(\zeta) for some ζ\zeta, so ∣E′′′(t)∣≤23M4t2|E'''(t)| \le \frac23 M_4 t^2. Integrating three times from 00: ∣E′′(t)∣≤29M4t3|E''(t)| \le \frac29 M_4 t^3, ∣E′(t)∣≤118M4t4|E'(t)| \le \frac{1}{18}M_4 t^4, ∣E(t)∣≤190M4t5|E(t)| \le \frac{1}{90}M_4 t^5. There are n/2n/2 pairs, each contributing at most M490h5\frac{M_4}{90}h^5, and n2⋅h5=(b−a)h42\frac{n}{2}\cdot h^5 = \frac{(b - a)h^4}{2}.

∎

So for smooth integrands, halving hh divides the trapezoidal error by about 44 and Simpson's by about 1616. The bounds also explain degrees of exactness: the trapezoidal rule is exact for polynomials of degree ≤1\le 1 (f′′=0f'' = 0), Simpson's rule for degree ≤3\le 3 (f(4)=0f^{(4)} = 0) — one degree more than its quadratic interpolants would suggest, by symmetry — but not for x4x^4. Two warnings, both visible in the third experiment:

  • Hypotheses matter. For x\sqrt x on [0,1][0, 1], f′′f'' is unbounded near 00; both rules then converge only like h1.5h^{1.5}.
  • Bounds are not estimates. For a smooth periodic function integrated over a full period, the trapezoidal rule converges faster than any power of hh (the error terms cancel; this follows from the Euler–Maclaurin formula), so it beats Simpson's rule there.

Combining ThT_h and Th/2T_{h/2} as 4Th/2−Th3\frac{4T_{h/2} - T_h}{3} cancels the h2h^2 term of the error and gives exactly Simpson's rule; repeating the idea (Richardson extrapolation) gives Romberg integration.

Formal mathematicsF

Numerical analysis in Lean

Lean has a hardware type Float, but its operations are opaque to proofs: Lean can run 0.1 + 0.2 but cannot reason about it. So we formalise a model: binary64 numbers as real numbers of the form m⋅2em \cdot 2^e, and rounding as "a relative error of at most uu". First, machine epsilon — no binary64 number lies strictly between 11 and 1+2−521 + 2^{-52}:

IsBinary64Lean 4Formally verified
/-- A positive **binary64 number** (an IEEE 754 "double"), ignoring the limits on the exponent:
`m · 2ᵉ` with an integer *significand* `m` of exactly 53 bits, `2⁵² ≤ m < 2⁵³`, and an integer
exponent `e`. -/
def IsBinary64 (x : ℝ) : Prop :=
  ∃ m e : ℤ, 2 ^ 52 ≤ m ∧ m < 2 ^ 53 ∧ x = m * (2 : ℝ) ^ e
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
one_add_eps_is_binary64Lean 4Proved here from basic factsFormally verified
/-- `1` and `1 + 2⁻⁵²` are both binary64 numbers: `1 = 2⁵² · 2⁻⁵²` and
`1 + 2⁻⁵² = (2⁵² + 1) · 2⁻⁵²`. -/
theorem one_add_eps_is_binary64 : IsBinary64 1 ∧ IsBinary64 (1 + 2 ^ (-52 : ℤ)) := by
  refine ⟨⟨2 ^ 52, -52, le_refl _, by norm_num, ?_⟩, ⟨2 ^ 52 + 1, -52, by norm_num, by norm_num, ?_⟩⟩
  · norm_num
  · norm_num
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
machine_epsilonLean 4Proved here from basic factsFormally verified
/-- **Machine epsilon.** No binary64 number lies strictly between `1` and `1 + 2⁻⁵²`, so the gap
between `1` and the next larger double is `ε = 2⁻⁵² ≈ 2.2 × 10⁻¹⁶`.
Proof: if `1 < m 2ᵉ < 1 + 2⁻⁵² < 2` with `2⁵² ≤ m < 2⁵³`, then `2⁵³⁺ᵉ > 1` and `2⁵²⁺ᵉ < 2`, which
forces `e = −52`; but then `2⁵² < m < 2⁵² + 1`, impossible for an integer `m`. -/
theorem machine_epsilon (x : ℝ) (hx : IsBinary64 x) : ¬ (1 < x ∧ x < 1 + 2 ^ (-52 : ℤ)) := by
  rintro ⟨h1, h2⟩
  obtain ⟨m, e, hm1, hm2, rfl⟩ := hx
  have two_pos : (0 : ℝ) < 2 := by norm_num
  have hm1' : (2 : ℝ) ^ (52 : ℤ) ≤ m := by exact_mod_cast hm1
  have hm2' : (m : ℝ) < 2 ^ (53 : ℤ) := by exact_mod_cast hm2
  have hpow : (0 : ℝ) < 2 ^ e := zpow_pos two_pos e
  have heps : (2 : ℝ) ^ (-52 : ℤ) < 1 := zpow_lt_one_of_neg₀ (by norm_num) (by norm_num)
  -- Lower bound on `e`: `1 < m 2ᵉ < 2⁵³ · 2ᵉ = 2^(53 + e)`.
  have hlo : (1 : ℝ) < 2 ^ (53 + e) := by
    rw [zpow_add₀ two_pos.ne']
    calc (1 : ℝ) < m * 2 ^ e := h1
      _ ≤ 2 ^ (53 : ℤ) * 2 ^ e := by gcongr
  have he1 : 0 < 53 + e := by
    by_contra hc
    rw [not_lt] at hc
    have : (2 : ℝ) ^ (53 + e) ≤ 1 := zpow_le_one_of_nonpos₀ (by norm_num) hc
    linarith
  -- Upper bound on `e`: `2^(52 + e) = 2⁵² · 2ᵉ ≤ m 2ᵉ < 1 + 2⁻⁵² < 2 = 2¹`.
  have hhi : (2 : ℝ) ^ (52 + e) < 2 ^ (1 : ℤ) := by
    rw [zpow_add₀ two_pos.ne', zpow_one]
    calc (2 : ℝ) ^ (52 : ℤ) * 2 ^ e ≤ m * 2 ^ e := by gcongr
      _ < 1 + 2 ^ (-52 : ℤ) := h2
      _ < 2 := by linarith
  have he2 : 52 + e < 1 := (zpow_lt_zpow_iff_right₀ (by norm_num : (1 : ℝ) < 2)).mp hhi
  have he : e = -52 := by omega
  subst he
  -- Now `2⁵² < m < 2⁵² + 1` after multiplying through by `2⁵²`.
  have key : (2 : ℝ) ^ (52 : ℤ) * 2 ^ (-52 : ℤ) = 1 := by
    rw [← zpow_add₀ two_pos.ne']; norm_num
  have hmlo : (2 : ℝ) ^ (52 : ℤ) < m := by
    by_contra hc
    rw [not_lt] at hc
    have : (m : ℝ) * 2 ^ (-52 : ℤ) ≤ 2 ^ (52 : ℤ) * 2 ^ (-52 : ℤ) := by gcongr
    linarith
  have hmhi : (m : ℝ) < 2 ^ (52 : ℤ) + 1 := by
    by_contra hc
    rw [not_lt] at hc
    have : (2 ^ (52 : ℤ) + 1) * (2 : ℝ) ^ (-52 : ℤ) ≤ m * 2 ^ (-52 : ℤ) := by gcongr
    rw [add_mul, key, one_mul] at this
    linarith
  have hz1 : (2 : ℤ) ^ 52 < m := by exact_mod_cast hmlo
  have hz2 : m < (2 : ℤ) ^ 52 + 1 := by exact_mod_cast hmhi
  omega
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor

The cancellation bound (Theorem 2), with the standard model as a definition:

RoundsToLean 4Formally verified
/-- The **standard model of floating-point arithmetic**: `x̂` is `x` with a relative error of at
most `u`, i.e. `x̂ = x (1 + δ)` for some `|δ| ≤ u`. For binary64 with rounding to nearest,
`u = 2⁻⁵³`, half of machine epsilon. -/
def RoundsTo (u x xhat : ℝ) : Prop :=
  ∃ δ : ℝ, |δ| ≤ u ∧ xhat = x * (1 + δ)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
cancellation_boundLean 4Proved here from basic factsFormally verified
/-- **Cancellation amplifies relative error.** If `x̂` and `ŷ` approximate `x` and `y` with
relative errors at most `u`, then the exact difference `x̂ − ŷ` is within `u (|x| + |y|)` of
`x − y`: `(x̂ − ŷ) − (x − y) = x δ₁ − y δ₂`. Dividing by `|x − y|`, the relative error of the
difference can be as large as `u (|x| + |y|)/|x − y|`, which is huge when `x ≈ y`. -/
theorem cancellation_bound {u x y xhat yhat : ℝ} (hx : RoundsTo u x xhat)
    (hy : RoundsTo u y yhat) : |(xhat - yhat) - (x - y)| ≤ u * (|x| + |y|) := by
  obtain ⟨d₁, hd₁, rfl⟩ := hx
  obtain ⟨d₂, hd₂, rfl⟩ := hy
  calc |(x * (1 + d₁) - y * (1 + d₂)) - (x - y)| = |x * d₁ + -(y * d₂)| := by ring_nf
    _ ≤ |x * d₁| + |-(y * d₂)| := abs_add_le _ _
    _ = |x| * |d₁| + |y| * |d₂| := by rw [abs_neg, abs_mul, abs_mul]
    _ ≤ |x| * u + |y| * u := by gcongr
    _ = u * (|x| + |y|) := by ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor

Bisection (Theorem 3). The method is a definition; its loop invariant and its halving property are proved by induction, and Mathlib's intermediate value theorem supplies the root:

bisectStepLean 4Formally verified
/-- One step of **bisection** on an interval `[a, b]` (stored as a pair): look at the midpoint
`m`; keep `[m, b]` if `f m ≤ 0` and `[a, m]` otherwise, so a sign change is kept. -/
noncomputable def bisectStep (f : ℝ → ℝ) (p : ℝ × ℝ) : ℝ × ℝ :=
  if f ((p.1 + p.2) / 2) ≤ 0 then ((p.1 + p.2) / 2, p.2) else (p.1, (p.1 + p.2) / 2)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
bisectLean 4Formally verified
/-- The interval after `n` steps of bisection, starting from `[a, b]`. -/
noncomputable def bisect (f : ℝ → ℝ) (a b : ℝ) : ℕ → ℝ × ℝ
  | 0 => (a, b)
  | n + 1 => bisectStep f (bisect f a b n)
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
bisect_widthLean 4Proved here from basic factsFormally verified
/-- **Bisection halves the interval**: after `n` steps its width is `(b − a)/2ⁿ`. -/
theorem bisect_width (f : ℝ → ℝ) (a b : ℝ) (n : ℕ) :
    (bisect f a b n).2 - (bisect f a b n).1 = (b - a) / 2 ^ n := by
  induction n with
  | zero => simp [bisect]
  | succ k ih =>
    simp only [bisect, bisectStep]
    split_ifs <;> simp only [pow_succ] <;> linear_combination ih / 2
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
bisect_signLean 4Proved here from basic factsFormally verified
/-- **The loop invariant of bisection**: if `f a ≤ 0 ≤ f b`, then after every step the left end
still has `f ≤ 0` and the right end `f ≥ 0`. -/
theorem bisect_sign (f : ℝ → ℝ) (a b : ℝ) (ha : f a ≤ 0) (hb : 0 ≤ f b) (n : ℕ) :
    f (bisect f a b n).1 ≤ 0 ∧ 0 ≤ f (bisect f a b n).2 := by
  induction n with
  | zero => exact ⟨ha, hb⟩
  | succ k ih =>
    simp only [bisect, bisectStep]
    split_ifs with h
    · exact ⟨h, ih.2⟩
    · exact ⟨ih.1, (lt_of_not_ge h).le⟩
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
bisection_convergesLean 4Proved here from basic factsFormally verified
/-- **Bisection always works for a continuous function with a sign change.** If `f` is
continuous, `a ≤ b` and `f a ≤ 0 ≤ f b`, then for every `n` there is a root `c` of `f` within
`(b − a)/2ⁿ⁺¹` of the `n`-th midpoint. The root comes from the intermediate value theorem
(Mathlib's `intermediate_value_Icc`) applied to the current interval. -/
theorem bisection_converges (f : ℝ → ℝ) (hf : Continuous f) (a b : ℝ) (hab : a ≤ b)
    (ha : f a ≤ 0) (hb : 0 ≤ f b) (n : ℕ) :
    ∃ c, f c = 0 ∧
      |((bisect f a b n).1 + (bisect f a b n).2) / 2 - c| ≤ (b - a) / 2 ^ (n + 1) := by
  set p := bisect f a b n with hp
  have hw : p.2 - p.1 = (b - a) / 2 ^ n := bisect_width f a b n
  have hs := bisect_sign f a b ha hb n
  have hle : p.1 ≤ p.2 := by
    have : 0 ≤ (b - a) / 2 ^ n := div_nonneg (by linarith) (by positivity)
    linarith
  obtain ⟨c, ⟨hc1, hc2⟩, hfc⟩ :=
    intermediate_value_Icc hle hf.continuousOn ⟨hs.1, hs.2⟩
  refine ⟨c, hfc, ?_⟩
  rw [abs_le, pow_succ]
  constructor <;>
  · rw [div_mul_eq_div_div] at *
    linarith
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor

Newton's method. For square roots the error identity is exact algebra, which gives quadratic convergence directly. For a general ff we formalise the algebraic step of Theorem 4's proof, and cite Mathlib's Taylor theorem, which supplies the remainder term; we have not assembled the full local convergence theorem (choosing δ\delta and running the induction) in Lean.

heron_errorLean 4Proved here from basic factsFormally verified
/-- **Heron's method is Newton's method for `x² = a`**: `x' = (x + a/x)/2`. Its error satisfies
`x' − √a = (x − √a)² / (2x)` exactly: the new error is proportional to the *square* of the old
one. -/
theorem heron_error {a x : ℝ} (ha : 0 ≤ a) (hx : 0 < x) :
    (x + a / x) / 2 - √a = (x - √a) ^ 2 / (2 * x) := by
  have hs : √a ^ 2 = a := sq_sqrt ha
  field_simp
  linear_combination (-1 : ℝ) * hs
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
heron_ge_sqrtLean 4Proved here from basic factsFormally verified
/-- From any positive start, every Heron iterate is at least `√a` (an instance of the AM–GM
inequality, read off from `heron_error`: the right-hand side is a square over a positive
number). -/
theorem heron_ge_sqrt {a x : ℝ} (ha : 0 ≤ a) (hx : 0 < x) : √a ≤ (x + a / x) / 2 := by
  have h := heron_error ha hx
  have : 0 ≤ (x - √a) ^ 2 / (2 * x) := by positivity
  linarith
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
heron_quadraticLean 4Proved here from basic factsFormally verified
/-- **Quadratic convergence of Heron's method.** If `x ≥ √a > 0`, the new error is at most the
old error squared, divided by `2√a`. So once the error is below `√a`, the number of correct
digits roughly doubles at every step. -/
theorem heron_quadratic {a x : ℝ} (ha : 0 < a) (hx : √a ≤ x) :
    |(x + a / x) / 2 - √a| ≤ (x - √a) ^ 2 / (2 * √a) := by
  have hs : 0 < √a := sqrt_pos.mpr ha
  have hx0 : 0 < x := lt_of_lt_of_le hs hx
  rw [heron_error ha.le hx0, abs_of_nonneg (by positivity)]
  apply div_le_div_of_nonneg_left (by positivity) (by positivity)
  linarith
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
newton_error_stepLean 4Proved here from basic factsFormally verified
/-- **The algebraic heart of Newton's convergence proof.** Suppose `f(r) = 0` and Taylor's
theorem at `x` gives `0 = f(r) = f(x) + f'(x)(r − x) + c (r − x)²` (with `c = f''(ξ)/2`). If
`f'(x) ≠ 0`, the Newton step `x' = x − f(x)/f'(x)` satisfies `x' − r = (c / f'(x)) (x − r)²`. -/
theorem newton_error_step {x r fx dfx c : ℝ} (hd : dfx ≠ 0)
    (htaylor : fx + dfx * (r - x) + c * (r - x) ^ 2 = 0) :
    (x - fx / dfx) - r = c / dfx * (x - r) ^ 2 := by
  have hfx : fx = -(dfx * (r - x) + c * (r - x) ^ 2) := by linarith
  rw [hfx]
  field_simp
  ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
taylor_lagrangeLean 4Applies a library theoremFormally verified
/-- **Taylor's theorem with the Lagrange remainder**, as Mathlib states it
(`taylor_mean_remainder_lagrange`): if `f` is `n` times continuously differentiable on the
interval between `x₀` and `x`, and its `n`-th derivative is differentiable inside, then
`f(x) − Tₙ(x) = f⁽ⁿ⁺¹⁾(ξ)(x − x₀)ⁿ⁺¹/(n + 1)!` for some `ξ` strictly between. With `n = 1` this
supplies the constant `c = f''(ξ)/2` in `newton_error_step`. -/
theorem taylor_lagrange {f : ℝ → ℝ} {x x₀ : ℝ} {n : ℕ} (hx : x₀ ≠ x)
    (hf : ContDiffOn ℝ n f (uIcc x₀ x))
    (hf' : DifferentiableOn ℝ (iteratedDerivWithin n f (uIcc x₀ x)) (uIoo x₀ x)) :
    ∃ x' ∈ uIoo x₀ x, f x - taylorWithinEval f n (uIcc x₀ x) x₀ x =
      iteratedDerivWithin (n + 1) f (uIcc x₀ x) x' * (x - x₀) ^ (n + 1) / (n + 1).factorial :=
  taylor_mean_remainder_lagrange hx hf hf'
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor

Mathlib also has Newton's method for polynomials over any commutative ring, with an algebraic form of quadratic convergence (see the algebraist's viewpoint below):

newton_algebraicLean 4Applies a library theoremFormally verified
/-- **Quadratic convergence, algebraically.** For a polynomial `P` over a commutative ring, if
`P(x)` is nilpotent and `P'(x)` is invertible, then after `n` Newton steps `P(x)^(2ⁿ)` divides
the new value of `P`: the "error" is raised to the power `2ⁿ`. This is Mathlib's
`Polynomial.aeval_pow_two_pow_dvd_aeval_iterate_newtonMap`, the engine of Hensel's lemma. -/
theorem newton_algebraic {R S : Type*} [CommRing R] [CommRing S] [Algebra R S] {P : R[X]}
    {x : S} (h : IsNilpotent (aeval x P)) (h' : IsUnit (aeval x (derivative P))) (n : ℕ) :
    (aeval x P) ^ (2 ^ n) ∣ aeval (P.newtonMap^[n] x) P :=
  aeval_pow_two_pow_dvd_aeval_iterate_newtonMap h h' n
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor

Integration. Simpson's rule is exact for cubics but not for x4x^4, proved with the fundamental theorem of calculus; and Mathlib contains the composite trapezoidal rule with the error bound of Theorem 6 — proved, as it happens, by the same "differentiate the error twice" argument as the lesson. Simpson's error bound (Theorem 7) is not formalised here.

simpson_exact_cubicLean 4Proved here from basic factsFormally verified
/-- **Simpson's rule integrates cubics exactly**:
`∫ₐᵇ p = (b − a)/6 · (p(a) + 4 p((a + b)/2) + p(b))` for `p(x) = c₃x³ + c₂x² + c₁x + c₀`.
Proof: an antiderivative `P` gives `∫ₐᵇ p = P(b) − P(a)` (the fundamental theorem of calculus,
Mathlib's `integral_eq_sub_of_hasDerivAt`), and the two sides agree as polynomials in `a, b`. -/
theorem simpson_exact_cubic (c₃ c₂ c₁ c₀ a b : ℝ) :
    ∫ x in a..b, (c₃ * x ^ 3 + c₂ * x ^ 2 + c₁ * x + c₀) =
      (b - a) / 6 * ((c₃ * a ^ 3 + c₂ * a ^ 2 + c₁ * a + c₀) +
        4 * (c₃ * ((a + b) / 2) ^ 3 + c₂ * ((a + b) / 2) ^ 2 + c₁ * ((a + b) / 2) + c₀) +
        (c₃ * b ^ 3 + c₂ * b ^ 2 + c₁ * b + c₀)) := by
  have hderiv : ∀ x ∈ uIcc a b, HasDerivAt
      (fun x => c₃ * x ^ 4 / 4 + c₂ * x ^ 3 / 3 + c₁ * x ^ 2 / 2 + c₀ * x)
      (c₃ * x ^ 3 + c₂ * x ^ 2 + c₁ * x + c₀) x := by
    intro x _
    have h := ((((hasDerivAt_pow 4 x).const_mul c₃).div_const 4).add
      (((hasDerivAt_pow 3 x).const_mul c₂).div_const 3)).add
      (((hasDerivAt_pow 2 x).const_mul c₁).div_const 2) |>.add ((hasDerivAt_id x).const_mul c₀)
    convert h using 1
    · ext y; simp
    · push_cast; ring
  rw [intervalIntegral.integral_eq_sub_of_hasDerivAt hderiv
    (by apply Continuous.intervalIntegrable; fun_prop)]
  ring
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
simpson_not_exact_quarticLean 4Proved here from basic factsFormally verified
/-- …but not quartics: on `[0, 1]`, `∫ x⁴ = 1/5`, while Simpson's rule gives
`(1/6)(0 + 4 · (1/2)⁴ + 1) = 5/24`. So the degree of exactness of Simpson's rule is exactly `3`,
which is why its error involves the fourth derivative. -/
theorem simpson_not_exact_quartic :
    ∫ x in (0 : ℝ)..1, x ^ 4 = 1 / 5 ∧
      (1 - 0) / 6 * ((0 : ℝ) ^ 4 + 4 * ((0 + 1) / 2) ^ 4 + 1 ^ 4) = 5 / 24 := by
  constructor
  · rw [integral_pow]; norm_num
  · norm_num
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
trapezoid_errorLean 4Applies a library theoremFormally verified
/-- **The error of the composite trapezoidal rule** with `N` strips is at most
`|b − a|³ ζ / (12 N²)` when `|f''| ≤ ζ` on the interval — that is, `(b − a) h² ζ / 12` with
`h = (b − a)/N`: the `O(h²)` of the lesson. This applies Mathlib's
`trapezoidal_error_le_of_c2`, whose proof is the lesson's proof (differentiate the error of one
strip twice). -/
theorem trapezoid_error {f : ℝ → ℝ} {a b : ℝ} (hf : ContDiffOn ℝ 2 f (uIcc a b)) {ζ : ℝ}
    (hζ : ∀ x, |iteratedDerivWithin 2 f (uIcc a b) x| ≤ ζ) {N : ℕ} (hN : 0 < N) :
    |trapezoidal_error f N a b| ≤ |b - a| ^ 3 * ζ / (12 * N ^ 2) :=
  trapezoidal_error_le_of_c2 hf hζ hN
Axioms used: propext, Classical.choice, Quot.soundformal/Lumenary/NumericalMethods.leanTry it in the Lean web editor
ComputationC

Experiments: rounding, convergence and balance

The first experiment finds machine epsilon, shows the exact value Python stores for 0.10.1, and watches cancellation destroy (1−cos⁡x)/x2(1 - \cos x)/x^2 and the quadratic formula — and the rearranged formulas repair them. Note how the naive value at x=10−6x = 10^{-6} is printed with twelve digits but has only four correct.

Machine epsilon and catastrophic cancellationPythonNumerical approximationExact computationComputationally tested
"""Floating point: machine epsilon, and cancellation that destroys accuracy.

Python floats are IEEE 754 binary64 numbers. We find machine epsilon by
halving until 1 + eps is no longer bigger than 1, check that 0.1 + 0.2 is not
the float nearest to 0.3, and then watch catastrophic cancellation: computing
(1 - cos x)/x^2 for small x loses all its digits, although every operation is
correctly rounded, while the algebraically equal 2 sin^2(x/2)/x^2 stays
accurate. The same happens to the small root of x^2 - 10^8 x + 1 in the
schoolbook quadratic formula, and a rearranged formula fixes it.
"""

import math
from fractions import Fraction

def machine_epsilon():
    """Smallest power of two eps with 1 + eps > 1 in floating point."""
    eps = 1.0
    while 1.0 + eps / 2 > 1.0:
        eps /= 2
    return eps

def naive_one_minus_cos(x):
    """(1 - cos x) / x^2, computed directly (suffers cancellation)."""
    return (1 - math.cos(x)) / x ** 2

def stable_one_minus_cos(x):
    """The same quantity as 2 sin^2(x/2) / x^2: no subtraction of close numbers."""
    s = math.sin(x / 2)
    return 2 * s * s / x ** 2

def one_minus_cos_series(x, terms=8):
    """(1 - cos x)/x^2 from its Taylor series sum (-1)^k x^(2k) / (2k + 2)!."""
    return sum((-1) ** k * x ** (2 * k) / math.factorial(2 * k + 2)
               for k in range(terms))

def relative_error(approx, exact):
    """|approx - exact| / |exact|."""
    return abs(approx - exact) / abs(exact)

def quadratic_roots_naive(b, c):
    """Roots of x^2 + b x + c by the schoolbook formula (b < 0 assumed)."""
    d = math.sqrt(b * b - 4 * c)
    return (-b + d) / 2, (-b - d) / 2

def quadratic_roots_stable(b, c):
    """Large root by the formula without cancellation, small root as c / large."""
    d = math.sqrt(b * b - 4 * c)
    big = (-b + d) / 2 if b < 0 else (-b - d) / 2
    return big, c / big

def main():
    eps = machine_epsilon()
    print(f"machine epsilon = {eps!r} = 2^{round(math.log2(eps))}")
    print(f"1 + eps/2 == 1: {1 + eps / 2 == 1}")
    print(f"0.1 is stored as {Fraction(0.1)}")
    print(f"0.1 + 0.2 = {0.1 + 0.2!r}; equal to 0.3: {0.1 + 0.2 == 0.3}")
    print()
    print("(1 - cos x)/x^2 (true value from its Taylor series, about 1/2):")
    print("       x      naive           rel. error   stable rel. error")
    for k in range(1, 9):
        x = 10.0 ** (-k)
        exact = one_minus_cos_series(x)
        naive = naive_one_minus_cos(x)
        print(f"  1e-{k:d}  {naive:.12f}  {relative_error(naive, exact):10.1e}"
              f"  {relative_error(stable_one_minus_cos(x), exact):10.1e}")
    print()
    b, c = -1e8, 1.0
    small_true = 1e-8 + 1e-24  # small root of x^2 - 1e8 x + 1, to 32 digits
    naive_small = quadratic_roots_naive(b, c)[1]
    stable_small = quadratic_roots_stable(b, c)[1]
    print("Small root of x^2 - 10^8 x + 1 (true value 1.0000...e-08):")
    print(f"  schoolbook formula: {naive_small:.10e}  rel. error "
          f"{relative_error(naive_small, small_true):.1e}")
    print(f"  c / (large root):   {stable_small:.10e}  rel. error "
          f"{relative_error(stable_small, small_true):.1e}")
    print()
    print("Epistemic status: exact facts about IEEE binary64 arithmetic as")
    print("implemented by this Python (all mainstream platforms agree). The")
    print("errors are measured against series and exact expansions; they")
    print("illustrate, not prove, the cancellation bound of the lesson.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

The second solves x2=2x^2 = 2 with 5050-digit decimal arithmetic, so rounding does not mask the convergence, and estimates the orders of bisection, Newton and the secant method; then it shows Newton's method at a double root and in a 22-cycle.

Bisection, Newton and secant: orders of convergencePythonNumerical approximationCounterexampleComputationally tested
"""Bisection, Newton and secant: measuring orders of convergence.

We solve x^2 = 2 with 50-digit decimal arithmetic, so that rounding does not
hide the behaviour, and print the errors e_n = |x_n - sqrt 2|. Bisection
halves its error bound each step (order 1, rate 1/2); Newton's method roughly
doubles the number of correct digits (order 2); the secant method is in
between (order (1 + sqrt 5)/2 = 1.618...). The estimated order is
log(e_{n+1}/e_n) / log(e_n/e_{n-1}). Then two warnings: at the double root of
(x - 1)^2 Newton converges only linearly, and for x^3 - 2x + 2 started at 0
it never converges, cycling 0, 1, 0, 1, ...
"""

import math
from decimal import Decimal, getcontext

getcontext().prec = 50

def bisection(f, a, b, steps):
    """Midpoints of the bisection intervals, assuming f(a) < 0 < f(b)."""
    mids = []
    for _ in range(steps):
        m = (a + b) / 2
        mids.append(m)
        if f(m) <= 0:
            a = m
        else:
            b = m
    return mids

def newton(f, df, x, steps):
    """Newton iterates x_{n+1} = x_n - f(x_n)/f'(x_n), starting value included."""
    xs = [x]
    for _ in range(steps):
        x = x - f(x) / df(x)
        xs.append(x)
    return xs

def secant(f, x0, x1, steps):
    """Secant iterates, starting values included; stops if f values coincide."""
    xs = [x0, x1]
    for _ in range(steps):
        f0, f1 = f(xs[-2]), f(xs[-1])
        if f1 == f0:
            break
        xs.append(xs[-1] - f1 * (xs[-1] - xs[-2]) / (f1 - f0))
    return xs

def orders(errors):
    """Estimated orders log(e2/e1)/log(e1/e0) for consecutive triples."""
    out = []
    for e0, e1, e2 in zip(errors, errors[1:], errors[2:]):
        if min(e0, e1, e2) > 0 and e1 != e0:
            out.append(math.log(e2 / e1) / math.log(e1 / e0))
    return out

def main():
    root = Decimal(2).sqrt()
    f = lambda x: x * x - 2
    df = lambda x: 2 * x
    mids = bisection(f, Decimal(1), Decimal(2), 8)
    errs = [float(abs(x - root)) for x in mids]
    print("bisection errors: " + " ".join(f"{e:.0e}" for e in errs))
    print("          bounds: " + " ".join(f"{0.5 ** (n + 1):.0e}"
                                         for n in range(len(mids))))
    runs = [
        ("Newton", newton(f, df, Decimal(2), 6)[1:]),
        ("secant", secant(f, Decimal(2), Decimal(1), 7)[2:]),
    ]
    for name, xs in runs:
        errs = [float(abs(x - root)) for x in xs]
        shown = " ".join(f"{e:.0e}" for e in errs)
        est = orders(errs)
        print(f"{name:9s} errors: {shown}")
        print(f"{'':9s} estimated orders: "
              + ", ".join(f"{p:.2f}" for p in est[:5]))
    print()
    g = lambda x: (x - 1) ** 2
    dg = lambda x: 2 * (x - 1)
    xs = newton(g, dg, Decimal(2), 6)
    print("Newton at the double root of (x - 1)^2, errors:")
    print("  " + " ".join(f"{float(x - 1):g}" for x in xs))
    h = lambda x: x ** 3 - 2 * x + 2
    dh = lambda x: 3 * x * x - 2
    cyc = newton(h, dh, Decimal(0), 6)
    print("Newton for x^3 - 2x + 2 from 0:", [int(x) for x in cyc])
    print()
    print("Epistemic status: numerical evidence for one equation; the orders")
    print("1, 2 and 1.618 are theorems for simple roots of smooth functions")
    print("(proved for bisection and Newton in the lesson). The last two runs")
    print("are exact counterexamples showing that the hypotheses matter.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.

The third shows the V-shaped total error of difference quotients, and how the smoothness hypotheses govern the convergence of the trapezoidal and Simpson rules.

Truncation versus rounding, and smoothness in quadraturePythonNumerical approximationComputationally tested
"""Truncation error against rounding error, and when error bounds fail.

Part 1: the forward difference (f(x + h) - f(x))/h approximates f'(x) with a
truncation error about h|f''|/2, but rounding errors in f contribute about
2u|f|/h. As h shrinks the total error first falls and then rises again, with
its minimum near h = sqrt(u) = 1e-8; the central difference does better,
with its minimum near u^(1/3) = 1e-5.

Part 2: the composite trapezoid and Simpson rules on two integrands. For the
periodic function e^(cos x) on [0, 2 pi] the trapezoid rule converges far
faster than its O(h^2) bound suggests. For sqrt(x) on [0, 1], whose
derivatives blow up at 0, both rules converge only like h^1.5: the smoothness
hypotheses of the error theorems are not met.
"""

import math

def forward_difference(f, x, h):
    """(f(x + h) - f(x)) / h."""
    return (f(x + h) - f(x)) / h

def central_difference(f, x, h):
    """(f(x + h) - f(x - h)) / (2h)."""
    return (f(x + h) - f(x - h)) / (2 * h)

def trapezoid(f, a, b, n):
    """Composite trapezoid rule with n strips."""
    h = (b - a) / n
    return h * (0.5 * f(a) + sum(f(a + i * h) for i in range(1, n)) + 0.5 * f(b))

def simpson(f, a, b, n):
    """Composite Simpson rule with n strips (n even)."""
    if n <= 0 or n % 2:
        raise ValueError("Simpson's rule needs a positive even number of strips")
    h = (b - a) / n
    odd = sum(f(a + i * h) for i in range(1, n, 2))
    even = sum(f(a + i * h) for i in range(2, n, 2))
    return h / 3 * (f(a) + 4 * odd + 2 * even + f(b))

def bessel_i0(x, terms=30):
    """Modified Bessel function I0(x) = sum (x/2)^(2k) / (k!)^2."""
    return sum((x / 2) ** (2 * k) / math.factorial(k) ** 2 for k in range(terms))

def main():
    exact = math.cos(1.0)
    print("Derivative of sin at 1: errors of difference quotients")
    print("      h     forward    central")
    for k in range(1, 14, 2):
        h = 10.0 ** (-k)
        fe = abs(forward_difference(math.sin, 1.0, h) - exact)
        ce = abs(central_difference(math.sin, 1.0, h) - exact)
        print(f"  1e-{k:02d}  {fe:9.1e}  {ce:9.1e}")
    print()
    per_exact = 2 * math.pi * bessel_i0(1.0)
    print("Trapezoid errors for e^cos(x) on [0, 2 pi] (periodic):")
    for n in (2, 4, 8, 16):
        err = abs(trapezoid(lambda t: math.exp(math.cos(t)), 0, 2 * math.pi, n)
                  - per_exact)
        print(f"  n = {n:2d}: {err:.1e}")
    print("sqrt(x) on [0, 1] (exact 2/3): errors and observed orders")
    print("    n   trapezoid   Simpson")
    prev = None
    for n in (16, 64, 256, 1024):
        te = abs(trapezoid(math.sqrt, 0, 1, n) - 2 / 3)
        se = abs(simpson(math.sqrt, 0, 1, n) - 2 / 3)
        rate = "" if prev is None else (
            f"   orders {math.log(prev[0] / te, 4):.2f},"
            f" {math.log(prev[1] / se, 4):.2f}")
        print(f"  {n:4d}  {te:9.2e}  {se:9.2e}{rate}")
        prev = (te, se)
    print()
    print("Epistemic status: floating-point measurements for a few functions.")
    print("They agree with the error analysis (truncation ~ h or h^2, rounding")
    print("~ u/h) and show that the O(h^2) and O(h^4) quadrature bounds need")
    print("bounded derivatives; they do not prove any rate.")

if __name__ == "__main__":
    main()
Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Explore

Explore: Newton's method, Runge's phenomenon, the trapezoidal rule

Newton's method is the iteration of the map N(x)=x−f(x)/f′(x)N(x) = x - f(x)/f'(x), and a root of ff is a fixed point of NN with N′(r)=0N'(r) = 0 — which is why the cobweb hits the fixed point so fast. For 2\sqrt 2, start at x0=3x_0 = 3 and count the steps until the cobweb is indistinguishable from the fixed point.

Newton's method for x² = 2

The map x ↦ (x + 2/x)/2 has a superattracting fixed point at √2.

f(x) =
x₀

Iterates xₖ against k

  • y = f(x)
  • y = x
  • cobweb path

Last iterates: x6 = 1.41421, x7 = 1.41421, x8 = 1.41421

The orbit appears to settle at a fixed point x* ≈ 1.41421.

Fixed points in view (numerical): x* = 1.4142 (attracting: |f′(x*)| < 1)

Based on 3,000 iterations in floating-point arithmetic: numerical evidence, not proof.

Now the cubic x3−2x+2x^3 - 2x + 2, started at 00. The cobweb settles into a square: a cycle of period 22. Try other starting values — those below about −1-1 find the root near −1.77-1.77.

Newton's method can cycle

For x³ − 2x + 2 the iterates from 0 alternate 0, 1, 0, 1, …

f(x) =
x₀

Iterates xₖ against k

  • y = f(x)
  • y = x
  • cobweb path

Last iterates: x18 = 0, x19 = 1, x20 = 0

The orbit appears to settle into a cycle of period 2: 0, 1.

Fixed points in view (numerical): x* = −1.7693 (attracting: |f′(x*)| < 1)

Based on 3,000 iterations in floating-point arithmetic: numerical evidence, not proof.

Runge's phenomenon: Runge's function, its degree-1010 interpolant at eleven equally spaced nodes (marked), and its degree-1010 interpolant at Chebyshev nodes (coefficients rounded). The first overshoots to almost 22 near x=±0.95x = \pm 0.95; the second stays within about 0.110.11 everywhere.

Runge's phenomenon

Move the sliders and trace along the curves to read off values.

  • 1/(1 + 25x²)
  • equally spaced nodes
  • Chebyshev nodes
  • 1/(1 + 25x²): y = 0.0385
  • equally spaced nodes: y = 0.0385
  • Chebyshev nodes: y = −0.0054

Finally, the trapezoidal rule on the periodic function ecos⁡xe^{\cos x} over [0,2π][0, 2\pi]: increase the number of strips from 22 to 88 and watch the error collapse far faster than h2h^2. Then switch to the midpoint or left rule — for periodic functions over a full period they are just as good.

The trapezoidal rule on a periodic function

Approximate the area under a curve with thin strips, and watch the error shrink as the strips get thinner.

  • f(x) = exp(cos(x))

Trapezoid sum with 4 strips

T4 = 7.989323

Exact value of the integral

∫02π f(x) dx = 7.954927

Error (sum − integral)

0.034397

All four rules with n = 4

RuleSumError
Left (L4)7.9893230.034397
Right (R4)7.9893230.034397
Midpoint (M4)7.920532−0.034394
Trapezoid (T4)7.9893230.034397

Double n and watch the error: left and right sums roughly halve it, midpoint and trapezoid sums cut it to about a quarter.

Exercises

Exercises

1. Numerical methods

Warm-upHuman

Bisection is started on [1,2][1, 2] to find 2\sqrt 2 as a root of x2−2x^2 - 2. After nn halvings we report the midpoint of the current interval. What is the smallest nn for which Theorem 3 guarantees an error of at most 10−610^{-6}?

2. Numerical methods

Warm-upHuman

Newton's method for x2−2x^2 - 2 is xn+1=12(xn+2xn)x_{n+1} = \frac12\left(x_n + \frac{2}{x_n}\right). Starting from x0=1x_0 = 1, compute exactly x1=32x_1 = \frac32, x2=1712x_2 = \frac{17}{12} and x3=pqx_3 = \frac{p}{q} in lowest terms. Enter the numerator pp.

3. Numerical methods

CoreHuman

For large xx (say x=1012x = 10^{12}), which formula computes x+1−x\sqrt{x + 1} - \sqrt{x} most accurately in floating point?

Choose one

4. Numerical methods

CoreHuman

Newton's method for f(x)=x3f(x) = \sqrt[3]{x} (the real cube root) gives xn+1=−2xnx_{n+1} = -2x_n and diverges from every x0≠0x_0 \ne 0, although f(0)=0f(0) = 0. Which hypothesis of Theorem 4 fails?

Choose one

5. Numerical methods

CoreHuman

Apply Simpson's rule with n=2n = 2 strips (h=2h = 2) to ∫04x3 dx\int_0^4 x^3\,dx. What value does it give?

6. Numerical methods

CoreHuman

Which statements are true? (Choose all that apply.)

Choose all that apply

7. Numerical methods

CoreHuman

In binary64 arithmetic, approximately which step hh minimises the total error of the forward difference f(x+h)−f(x)h\frac{f(x + h) - f(x)}{h} for a typical smooth function with ff, f′′f'' of moderate size?

Choose one

8. Numerical methods

CoreFormal

With IsBinary64 x meaning "xx is a positive binary64 number", which Lean statement says that 2−522^{-52} is the gap between 11 and the next larger binary64 number?

Choose one

9. Numerical methods

StretchComputational

Write newton(f, df, x0, tol=1e-12, max_iter=50) that runs Newton's method and returns (x, n): the first iterate with abs(f(x)) <= tol and the number of steps taken. If a derivative is exactly 0, or max_iter steps pass without success, return (None, n).

Runs entirely in your browser, in an isolated worker. Nothing is sent to a server.
Common misconceptionsH

Common misconceptions

Misconception

"Printing more digits means more accuracy." The number of digits printed is a formatting choice; the number of correct digits is decided by the error analysis. Python prints the naive value of (1−cos⁡x)/x2(1 - \cos x)/x^2 at x=10−6x = 10^{-6} as 0.5000444502910.500044450291, of which only four digits are right; and 0.10.1 printed to twenty digits is 0.100000000000000005550.10000000000000000555, which says something about binary storage, not about your problem.

Misconception

"Newton's method converges from any starting point." Theorem 4 is local: it guarantees convergence only from starts close enough to a simple root. From x0=0x_0 = 0, Newton's method for x3−2x+2x^3 - 2x + 2 cycles forever; for x3\sqrt[3]{x} it diverges from every start except 00; at a double root it converges only linearly. Robust software safeguards Newton steps with bisection.

Misconception

"A smaller step size is always more accurate." For difference quotients, rounding error grows like ϵ/h\epsilon/h; below h≈10−8h \approx 10^{-8} the forward difference gets worse, and at h=10−16h = 10^{-16} it is typically useless.

Misconception

"Floating-point arithmetic is random or unreliable." It is deterministic and precisely specified: each basic operation returns the correctly rounded exact result. What fails are expectations borrowed from real arithmetic — associativity, exact decimals, and tests like 0.1 + 0.2 == 0.3. Compare floats with a tolerance chosen by error analysis.

Misconception

"A higher-order rule is always better." The O(h4)O(h^4) bound for Simpson's rule needs a bounded fourth derivative. For x\sqrt x on [0,1][0, 1] both rules converge like h1.5h^{1.5}, and for periodic functions over a period the trapezoidal rule beats Simpson's rule by far.

ViewpointsH

Many ways of seeing

Analysis— Iteration, contraction and completeness

Newton's method is a fixed-point iteration xn+1=N(xn)x_{n+1} = N(x_n). If a map gg sends a closed interval II into itself and ∣g′∣≤L<1|g'| \le L < 1 on II, the mean value theorem gives ∣g(x)−g(y)∣≤L∣x−y∣|g(x) - g(y)| \le L|x - y|: gg is a contraction, and the Banach fixed-point theorem says it has exactly one fixed point in II, reached from every start, with linear rate LL. The order of convergence is governed by derivatives at the fixed point: if g′(r)≠0g'(r) \ne 0 the convergence is linear; if g′(r)=0≠g′′(r)g'(r) = 0 \ne g''(r) it is quadratic. For Newton, N′(x)=f(x)f′′(x)/f′(x)2N'(x) = f(x)f''(x)/f'(x)^2 vanishes at a simple root, which is the analytic reason for quadratic convergence. The Newton–Kantorovich theorem (1948) extends Theorem 4 to systems of equations and to Banach spaces, with a computable test on the starting point. See real analysis and numerical analysis.

Algebra— Newton's method without limits: Hensel lifting

The identity behind quadratic convergence is algebraic. Over any commutative ring, if f(x)≡0(modq)f(x) \equiv 0 \pmod{q} and f′(x)f'(x) is invertible modulo qq, then x′=x−f(x)/f′(x)x' = x - f(x)/f'(x) satisfies f(x′)≡0(modq2)f(x') \equiv 0 \pmod{q^2}, by Taylor expansion of the polynomial ff. For example, x2≡2(mod7)x^2 \equiv 2 \pmod 7 has the solution 33; one Newton step lifts it to x′≡3−76≡10(mod49)x' \equiv 3 - \frac{7}{6} \equiv 10 \pmod{49}, and indeed 102=100=2+2⋅4910^2 = 100 = 2 + 2 \cdot 49. Repeating gives solutions modulo 74,78,…7^4, 7^8, \dots — Hensel's lemma, the pp-adic Newton method that builds 2\sqrt 2 in the 77-adic numbers. Mathlib's newton_algebraic above is a version with "error" meaning a nilpotent element: after nn steps f(x)2nf(x)^{2^n} divides ff at the new point. The same idea, with power series in place of numbers, computes reciprocals and square roots of power series in computer algebra. See algebraic number theory and congruences.

Geometry— Tangent lines and basins in the complex plane

Geometrically, each Newton step follows the tangent line of the graph down to the axis; convexity explains much of its behaviour (if ff is increasing and convex on [r,∞)[r, \infty), every start to the right of rr converges monotonically). In the complex plane the same formula z↦z−f(z)/f′(z)z \mapsto z - f(z)/f'(z) solves polynomial equations, and Arthur Cayley (1879) asked which starting points converge to which root. For z2−1z^2 - 1 the answer is clean: the half-planes Re z>0\mathrm{Re}\,z > 0 and Re z<0\mathrm{Re}\,z < 0. For z3−1z^3 - 1 the three basins of attraction have a common, fractal boundary — the Julia set of the Newton map — and every point of that boundary is a boundary point of all three basins. See complex analysis and dynamical systems.

Topology— Why bisection cannot fail

Bisection is the intermediate value theorem made into an algorithm, and the intermediate value theorem is a topological statement: a continuous image of the connected interval [a,b][a, b] is connected, so it contains every value between f(a)f(a) and f(b)f(b). The proof that the nested intervals close in on a root uses the completeness of R\R; over Q\Q, the function x2−2x^2 - 2 changes sign on [1,2][1, 2] but has no root. In higher dimensions the analogue of a sign change is a non-zero degree (winding number) on a boundary: if a map F:R2→R2F : \R^2 \to \R^2 winds non-trivially around 00 on a loop, it has a zero inside (Brouwer), and bisection-like subdivision methods can locate it. See point-set topology.

Probability— Monte Carlo: an error that ignores dimension

To integrate over the unit cube [0,1]d[0, 1]^d, average ff at NN independent uniformly random points. By the central limit theorem the error is about σ/N\sigma/\sqrt N, where σ2\sigma^2 is the variance of ff — whatever the dimension. A tensor-product trapezoidal rule with NN points has only N1/dN^{1/d} points per axis, so its error behaves like N−2/dN^{-2/d}, which beats Monte Carlo only when d<4d < 4. This is why high-dimensional integrals in statistics, finance and physics are computed by random sampling, and the error statement is probabilistic: a confidence interval, not a bound. (Rounding errors themselves are sometimes modelled as random, which explains why accumulated error often grows like n u\sqrt n\,u rather than the worst case nun u — a heuristic, not a theorem.) See probability theory.

Computation— Cost, stability and standards

Speed of convergence is not the whole story: one Newton step costs an evaluation of ff and of f′f', one secant step only of ff, so per function evaluation the secant method (order 1.6181.618) is often faster than Newton (order 22 per two evaluations, about 1.4141.414 per evaluation). For linear systems, Gaussian elimination with partial pivoting is backward stable in practice, while computing the inverse matrix explicitly is slower and less accurate; for least squares, the QR factorisation is preferred to the normal equations because squaring the matrix squares its condition number. Behind all of this stands the IEEE 754 standard (1985, revised 2008 and 2019), which made floating-point results reproducible across machines. See algorithm design.

History & global context

History and global context

  • Ancient approximation. The Old Babylonian tablet YBC 7289 (c. 1800–1600 BCE) gives 2\sqrt 2 to about six decimal places. Heron of Alexandria (1st century CE) described the iterative square-root method now seen as Newton's method for x2=ax^2 = a. The Chinese Nine Chapters on the Mathematical Art solved problems by the "excess and deficit" method, a form of linear interpolation (double false position). Liu Hui (263 CE) approximated π\pi with polygons of up to 3072 sides, and Zu Chongzhi (5th century) showed 3.1415926<π<3.14159273.1415926 < \pi < 3.1415927. In Samarkand, Jamshīd al-Kāshī computed 2π2\pi to the equivalent of sixteen decimal places (1424) and found sin⁡1∘\sin 1^\circ by a fixed-point iteration on a cubic equation.
  • Newton, Raphson and Simpson. Isaac Newton described his method for polynomial equations in De analysi (written 1669, published 1711), with the famous example x3−2x−5=0x^3 - 2x - 5 = 0; Joseph Raphson published a streamlined version (1690), and Thomas Simpson (1740) gave the general form for non-polynomial equations using derivatives. Johannes Kepler's barrel rule (1615) is Simpson's rule for one panel, which Bonaventura Cavalieri and James Gregory also knew; Thomas Simpson popularised it (1743).
  • Interpolation. Newton developed divided-difference interpolation; the "Lagrange" form was published by Edward Waring (1779) and Leonhard Euler (1783) before Joseph-Louis Lagrange (1795). Carl Runge exhibited the divergence of equally spaced interpolation in 1901, and Pafnuty Chebyshev's polynomials (1850s) underlie the cure.
  • The computer age. John von Neumann and Herman Goldstine analysed rounding errors in matrix inversion (1947); James H. Wilkinson developed backward error analysis (Rounding Errors in Algebraic Processes, 1963). William Kahan led the design of the IEEE 754 floating-point standard (1985), for which he received the Turing Award (1989).
Further reading

Further reading

  • Richard L. Burden and J. Douglas Faires, Numerical Analysis (1978; many later editions, now with Annette Burden) — a standard first course with many worked examples.
  • Endre Süli and David F. Mayers, An Introduction to Numerical Analysis (2003) — rigorous and concise, with complete proofs of the error bounds.
  • Nicholas J. Higham, Accuracy and Stability of Numerical Algorithms (1996; 2nd edition 2002) — the reference on floating-point error analysis.
  • David Goldberg, "What every computer scientist should know about floating-point arithmetic", ACM Computing Surveys 23 (1991) — a classic tutorial on IEEE arithmetic.
  • Lloyd N. Trefethen, Approximation Theory and Approximation Practice (2013) — interpolation, Chebyshev points and Runge's phenomenon done right.
  • Lloyd N. Trefethen and David Bau III, Numerical Linear Algebra (1997) — conditioning and stability in the setting where they matter most.

Next in the Lumenary: numerical analysis (linear systems, eigenvalues and differential equations), ordinary differential equations (Euler and Runge–Kutta methods) and optimisation (Newton's method for minimisation).