stringtranslate.com

Romberg's method

In numerical analysis, Romberg's method[1] is used to estimate the definite integral

Richardson extrapolation[2]trapezium rulerectangle ruletriangular arrayNewton–Cotes formulaGaussian quadratureClenshaw–Curtis quadrature

The method is named after Werner Romberg, who published the method in 1955.

Method

Using , the method can be inductively defined by

big O notationRnm[3]

The zeroeth extrapolation, R(n, 0), is equivalent to the trapezoidal rule with 2n + 1 points; the first extrapolation, R(n, 1), is equivalent to Simpson's rule with 2n + 1 points. The second extrapolation, R(n, 2), is equivalent to Boole's rule with 2n + 1 points. The further extrapolations differ from Newton-Cotes formulas. In particular further Romberg extrapolations expand on Boole's rule in very slight ways, modifying weights into ratios similar as in Boole's rule. In contrast, further Newton-Cotes methods produce increasingly differing weights, eventually leading to large positive and negative weights. This is indicative of how large degree interpolating polynomial Newton-Cotes methods fail to converge for many integrals, while Romberg integration is more stable.

By labelling our approximations as instead of , we can perform Richardson extrapolation with the error formula defined below:

When function evaluations are expensive, it may be preferable to replace the polynomial interpolation of Richardson with the rational interpolation proposed by Bulirsch & Stoer (1967).

A geometric example

To estimate the area under a curve the trapezoid rule is applied first to one-piece, then two, then four, and so on.

One-piece approximation
One-piece. Note since it starts and ends at zero, this approximation yields zero area.
Two-piece approximation
Two-piece
Four-piece approximation
Four-piece
Eight-piece approximation
Eight-piece

After trapezoid rule estimates are obtained, Richardson extrapolation is applied.

Example

As an example, the Gaussian function is integrated from 0 to 1, i.e. the error function erf(1) ≈ 0.842700792949715. The triangular array is calculated row by row and calculation is terminated if the two last entries in the last row differ less than 10−8.

0.771743330.82526296 0.843102830.83836778 0.84273605 0.842711600.84161922 0.84270304 0.84270083 0.842700660.84243051 0.84270093 0.84270079 0.84270079 0.84270079

The result in the lower right corner of the triangular array is accurate to the digits shown. It is remarkable that this result is derived from the less accurate approximations obtained by the trapezium rule in the first column of the triangular array.

Implementation

Here is an example of a computer implementation of the Romberg method (in the C programming language):

#include <stdio.h>#include <math.h>void print_row(size_t i, double *R) { printf("R[%2zu] = ", i); for (size_t j = 0; j <= i; ++j) { printf("%f ", R[j]); } printf("\n");}/*INPUT:(*f) : pointer to the function to be integrateda  : lower limitb  : upper limitmax_steps: maximum steps of the procedureacc  : desired accuracyOUTPUT:Rp[max_steps-1]: approximate value of the integral of the function f for x in [a,b] with accuracy 'acc' and steps 'max_steps'.*/double romberg(double (*f)(double), double a, double b, size_t max_steps, double acc) { double R1[max_steps], R2[max_steps]; // buffers double *Rp = &R1[0], *Rc = &R2[0]; // Rp is previous row, Rc is current row double h = b-a; //step size Rp[0] = (f(a) + f(b))*h*0.5; // first trapezoidal step print_row(0, Rp); for (size_t i = 1; i < max_steps; ++i) { h /= 2.; double c = 0; size_t ep = 1 << (i-1); //2^(n-1) for (size_t j = 1; j <= ep; ++j) { c += f(a + (2*j-1) * h); } Rc[0] = h*c + .5*Rp[0]; // R(i,0) for (size_t j = 1; j <= i; ++j) { double n_k = pow(4, j); Rc[j] = (n_k*Rc[j-1] - Rp[j-1]) / (n_k-1); // compute R(i,j) } // Print ith row of R, R[i,i] is the best estimate so far print_row(i, Rc); if (i > 1 && fabs(Rp[i-1]-Rc[i]) < acc) { return Rc[i]; } // swap Rn and Rc as we only need the last row double *rt = Rp; Rp = Rc; Rc = rt; } return Rp[max_steps-1]; // return our best guess}

Here is an implementation of the Romberg method (in the Python programming language):

def print_row(i, R): """Prints a row of the Romberg table.""" print(f"R[{i:2d}] = ", end="") for j in range(i + 1): print(f"{R[j]:f} ", end="") print()def romberg(f, a, b, max_steps, acc): """ Calculates the integral of a function using Romberg integration. Args: f: The function to integrate. a: Lower limit of integration. b: Upper limit of integration. max_steps: Maximum number of steps. acc: Desired accuracy. Returns: The approximate value of the integral. """ R1, R2 = [0] * max_steps, [0] * max_steps # Buffers for storing rows Rp, Rc = R1, R2 # Pointers to previous and current rows h = b - a # Step size Rp[0] = 0.5 * h * (f(a) + f(b)) # First trapezoidal step print_row(0, Rp) for i in range(1, max_steps): h /= 2. c = 0 ep = 1 << (i - 1) # 2^(i-1) for j in range(1, ep + 1): c += f(a + (2 * j - 1) * h) Rc[0] = h * c + 0.5 * Rp[0] # R(i,0) for j in range(1, i + 1): n_k = 4**j Rc[j] = (n_k * Rc[j - 1] - Rp[j - 1]) / (n_k - 1) # Compute R(i,j) # Print ith row of R, R[i,i] is the best estimate so far print_row(i, Rc) if i > 1 and abs(Rp[i - 1] - Rc[i]) < acc: return Rc[i] # Swap Rn and Rc for next iteration Rp, Rc = Rc, Rp return Rp[max_steps - 1] # Return our best guess

References

Citations

  1. ^ Romberg 1955
  2. ^ Richardson 1911
  3. ^ Mysovskikh 2002

Bibliography

External links