Why adapt an Euler step?
Forward Euler uses the slope at the beginning of a step to estimate the solution at its end. A step that is reasonable where the solution changes slowly may be too large where the slope changes rapidly. Adaptive step selection addresses this by estimating the error locally, comparing that estimate with a prescribed tolerance, and adjusting the step size.
Here the decision is based on step doubling: at a given starting point, compare one Euler step of length \(h\) with two Euler steps of length \(h/2\). The comparison is an estimate, not an exact measurement of the error. Its usefulness depends on the solution and slope behaving smoothly enough over the step.
Why the difference estimates local error
For a smooth scalar solution, Taylor expansion explains why the two computed values are close and why their difference reflects the local error. Write \(f_t\) and \(f_y\) for the partial derivatives of \(f\). Along the exact solution, \(y''=f_t+f_y f\). Denote this quantity at the starting point by \(D\). The exact value after a short step is
The full Euler step omits the quadratic term. For the two-half-step calculation, the first half-step gives \(y_n+\frac{h}{2}f(t_n,y_n)\). Expanding the slope at that intermediate point gives \(f(t_n+h/2,y_n+(h/2)f)=f(t_n,y_n)+(h/2)D+O(h^2)\). Thus the second half-step adds \((h/2)f+(h^2/4)D+O(h^3)\), and the doubled result is
Subtracting the full-step value from the doubled value leaves \(\frac{h^2}{4}D+O(h^3)\). The doubled value's error relative to the exact value is \(-\frac{h^2}{4}D+O(h^3)\). Their leading terms have the same magnitude. This is why the difference estimates the local error of the more accurate doubled value, when \(h\) is sufficiently small and the solution is smooth.
Turn the tolerance into a decision
For a scalar problem with an absolute local tolerance \(\mathrm{tol}>0\), accept the trial step when \(e_{\mathrm{est}}\leq \mathrm{tol}\). Otherwise reject it. A rejected trial does not advance the solution: retry from the same \((t_n,y_n)\) with a shorter step.
Euler's leading local error is proportional to \(h^2\). If the current estimate is \(e_{\mathrm{est}}>0\), this suggests resizing the step by a square-root factor. A practical controller also uses a safety factor \(s\), commonly chosen below one, to avoid resizing too aggressively:
The formula proposes a step for a new trial; it does not itself decide acceptance. A typical implementation also limits how much the step may shrink or grow in one adjustment. For example, it may restrict the multiplier \(h_{\mathrm{new}}/h\) to an interval such as \([0.2,2]\). The bounds are practical safeguards, not mathematical requirements. If the estimate is zero, the formula cannot be used directly; choose a bounded increase or another prescribed fallback.
For a system with components \(y_i\), an absolute tolerance alone may be inappropriate if the components have different scales. One common componentwise test uses an absolute tolerance \(\mathrm{atol}\) and relative tolerance \(\mathrm{rtol}\):
Here \(E\) is a dimensionless normalized estimate. Accept when \(E\leq 1\), and, when \(E>0\), use \(h_{\mathrm{new}}=s h/\sqrt{E}\). This test allows the permitted error to depend on the size of each component. The tolerance values must be chosen to suit the accuracy needed and the units and scales of the variables.
A practical accept-or-reject procedure
From the same \((t_n,y_n)\), compute one Euler step of length \(h\), then two Euler steps of length \(h/2\).
Compare the full-step and doubled values, using the prescribed absolute tolerance or a normalized system test.
If the estimate meets the tolerance, advance to the doubled value. If it fails, keep the starting time and value unchanged and retry with a smaller step.
Use the square-root controller, safety factor, and any chosen growth or shrink limits. Shorten the step if necessary to land exactly on the final time.
Using the doubled value on an accepted step is a common step-doubling strategy: that value is the more accurate of the two trial values under the smoothness assumptions above. The same procedure is repeated from the new accepted point.
Worked examples
Worked Example: Reject a large step and retry
Consider \(y'=t\), starting from \(t_0=0\), \(y_0=0\), with absolute tolerance \(\mathrm{tol}=0.01\). First try \(h=1\).
The full Euler step uses slope \(f(0,0)=0\), so \(Y_{\mathrm{full}}=0+1(0)=0\). For two half steps, the first reaches \(t=0.5\) with value \(0+(0.5)(0)=0\). The next slope is \(f(0.5,0)=0.5\), so the second half-step gives \(Y_{\mathrm{half}}=0+(0.5)(0.5)=0.25\). The estimate is \(|0.25-0|=0.25\), which exceeds \(0.01\). Reject the step; the state remains \((0,0)\).
With safety factor \(s=0.9\), the proposed multiplier is \(0.9\sqrt{0.01/0.25}=0.9(0.2)=0.18\). Thus retry with \(h=0.18\). The full-step value is \(0\). The half steps reach \(t=0.09\) with value \(0\), then give \(0+(0.09)(0.09)=0.0081\). The new estimate is \(0.0081\leq0.01\), so accept and advance to \((0.18,0.0081)\). As a check, for this equation the exact solution from these initial data is \(y=t^2/2\), and \(y(0.18)=0.0162\). The accepted value differs by \(0.0081\), matching the step-doubling estimate in this case.
Worked Example: Accept a step and propose a larger one
Consider \(y'=y\) from \((t_0,y_0)=(0,1)\), with absolute tolerance \(0.04\), safety factor \(s=0.9\), and trial step \(h=0.2\). The full Euler value is \(Y_{\mathrm{full}}=1+(0.2)(1)=1.2\).
For two half steps, the first gives \(1+(0.1)(1)=1.1\). The second gives \(1.1+(0.1)(1.1)=1.21\). Therefore \(e_{\mathrm{est}}=|1.21-1.2|=0.01\), which is below \(0.04\); accept \(Y_{\mathrm{half}}=1.21\) at \(t=0.2\).
The proposed next step is \(0.9(0.2)\sqrt{0.04/0.01}=0.18(2)=0.36\). This is a proposed increase, subject to any growth limit in use. As a check on the accepted endpoint, the exact solution is \(y=e^t\), so \(y(0.2)=e^{0.2}\approx1.221403\). The actual difference from the accepted value is about \(0.011403\), close to the estimate \(0.01\), but not identical.
Worked Example: Apply a normalized test to a system
Suppose a two-component system starts from \((0,0)\), and a trial step of length \(h=0.2\) gives \(Y_{\mathrm{full}}=(0,0)\) and \(Y_{\mathrm{half}}=(0.01,0.02)\). Take \(\mathrm{atol}=0.001\) and \(\mathrm{rtol}=0.05\). Since both starting components are zero, the denominators in the normalized test are \(0.001+0.05(0.01)=0.0015\) and \(0.001+0.05(0.02)=0.002\).
The first component's normalized estimate is \(0.01/0.0015=20/3\). The second is \(0.02/0.002=10\). Thus \(E=\max(20/3,10)=10\), so the trial step is rejected. With \(s=0.9\), the proposed multiplier is \(0.9/\sqrt{10}\approx0.284605\), giving \(h_{\mathrm{new}}\approx0.056921\). Retry from the original starting state; the rejected trial values are not used as the next initial condition.
Common pitfalls and limitations
Wrong: Comparing the estimate to the tolerance and then advancing with the full-step value, even though the doubled value is being used for the estimate. For example, in the accepted \(y'=y\) step above, this would advance with \(1.2\) rather than \(1.21\). Correction: Choose the value that the method specifies for accepted steps, and use it consistently. In the procedure here, that is \(Y_{\mathrm{half}}\); \(Y_{\mathrm{full}}\) is used for comparison.
Another mistake is to advance the time after a rejected step. Rejection means that neither the trial endpoint nor its value becomes the current numerical solution. Retry from the unchanged starting point. Also keep local and global accuracy distinct: many individually acceptable local steps can accumulate error, so the local test alone is not a proof of a global error bound.
Finally, a small estimated error does not guarantee that a step is safe in every respect. A step can be inaccurate if the slope changes sharply in a way the two trial calculations fail to reveal. Nor does passing an error test establish numerical stability. The estimate is a decision aid; interpret it alongside the behavior of the solution and the assumptions of the model.
Check Your Understanding
For each question, distinguish the estimated local error from the solution value used after acceptance.
- What two Euler computations are compared in step doubling?
- If an estimate exceeds the tolerance, which time and solution value should be used as the starting point for a retry?
- Why does a square root appear in the step-size adjustment formula for Euler's method?
- A normalized system test gives \(E=0.25\). Is the trial accepted, and what step multiplier does the controller \(s/\sqrt{E}\) propose when \(s=0.9\)?
- Why does passing a local tolerance not by itself prove that the accumulated error over a whole interval is below that tolerance?