Note
Go to the end to download the full example code.
Richardson extrapolation: cancelling error terms at a fixed step#
Richardson’s idea: if an estimate \(D(h)\) has error
\(c_1 h^2 + c_2 h^4 + \dots\), then combining \(D(h)\) and
\(D(h/2)\) as \((4D(h/2) - D(h))/3\) cancels the \(h^2\)
term. Repeating the combination on successively halved steps removes
one error order per level. This example applies
richardson_extrapolation() to a central
difference and shows it reaching near machine precision from a coarse
starting step, where no plain difference quotient can.
One extrapolation step by hand#
Two central differences, each only \(O(h^2)\), combine into an \(O(h^4)\) estimate at no extra cost.
D(h) error: 1.816e-02
D(h/2) error: 4.533e-03
(4D(h/2) - D(h))/3 error: 9.072e-06
Each level cancels one more error order#
Starting from the same coarse \(h = 0.2\), every extra level of extrapolation gains roughly two more orders of accuracy, until floating-point round-off takes over.
levels=1: error=1.816e-02
levels=2: error=9.072e-06
levels=3: error=5.397e-10
levels=4: error=4.885e-15
levels=5: error=2.709e-14
levels=6: error=6.972e-14
Extrapolation beats simply shrinking the step#
A plain central difference at step \(h\) bottoms out near \(10^{-11}\) because of cancellation; Richardson reaches that accuracy while its smallest step is still large.
hs = np.logspace(-1, -7, 25)
err_ctr = [abs(central_difference(f, x0, hh) - exact) for hh in hs]
smallest_step = [0.2 / 2 ** (k - 1) for k in levels]
fig, ax = plt.subplots(figsize=(6, 4.5))
ax.loglog(hs, err_ctr, "o-", label="central difference alone")
ax.loglog(smallest_step, np.maximum(errs, 1e-17), "s-", label="Richardson, levels 1..6")
ax.set_xlabel("smallest step used")
ax.set_ylabel("|error in f'(1)|")
ax.set_title("Richardson extrapolation from a coarse step h = 0.2")
ax.legend()
fig.tight_layout()
plt.show()

Total running time of the script: (0 minutes 0.107 seconds)