The idea of the trapezoidal rule is to approximate a general curve by trapezoids, like this. We illustrate with the problem of integrating sin(x) from 0 to pi. Of course, the true value of the integral is 2.
ezplot('sin(x)', [0, pi]), hold on approx = zeros(1,7); %initialize vector of results for j = 1:7 n = 2^j; x = pi*(0:1/n:1); plot(x, sin(x), 'r') weights = [1, 2*ones(1,n-1), 1]; approx(j) = pi/(2*n)*sin(x)*weights'; end disp('Using Trapezoidal Rule') disp(' n Approximation') for j = 1:7 disp(['n = ', num2str(2^j, '%d'), ' ', num2str(approx(j), '%1.10f')]) end
Using Trapezoidal Rule n Approximation n = 2 1.5707963268 n = 4 1.8961188979 n = 8 1.9742316019 n = 16 1.9935703438 n = 32 1.9983933610 n = 64 1.9995983886 n = 128 1.9998996002
The idea of Simpson's rule is to approximate a general curve by arcs of parabolas, like this. We illustrate with the problem of integrating sin(x) from 0 to pi. Of course, the true value of the integral is 2.
figure, ezplot('sin(x)', [0, pi]), hold on x = 0:.01:1; plot(pi*x, 1 - 4*(x-.5).^2, 'r') approx = zeros(1, 7); %initialize vector of results for j = 1:7 n = 2^j; x = pi*(0:1/n:1); weights = [1,2*ones(1,n-1)+2*mod([1:n-1],2),1] ; approx(j) = pi/(3*n)*sin(x)*weights'; end disp('Using Simpson Rule') disp(' n Approximation') for j = 1:7 disp(['n = ', num2str(2^j, '%d'), ' ', num2str(approx(j), '%1.10f')]) end
Using Simpson Rule n Approximation n = 2 2.0943951024 n = 4 2.0045597550 n = 8 2.0002691699 n = 16 2.0000165910 n = 32 2.0000010334 n = 64 2.0000000645 n = 128 2.0000000040
Note that for smooth functions, the error in Simpson's rule is roughly proportional to 1/n^4, so that it doesn't require a large value of n to get reasonable accuracy. However, for very jagged functions, the trapezoidal rule can be more accurate. Here is a program to compute the Simpson's rule approximation to an integral, along with some examples.
type Simpson
function Q = Simpson(fun, a, b, n) %SIMPSON Numerically evaluate integral, using Simpson's rule. % syntax: Q = Simpson(fun, a, b, n) % FUN should be a vectorized function defined on the interval % from a to b. n should be a positive even integer. % example: Simpson(@sin, 0, pi,4) returns the approximation % 2.0046 to the integral 2 of the sine function from 0 to pi. if mod(n,2) error('n must be even') end; weights = [1,2*ones(1,n-1)+2*mod([1:n-1],2),1] ; x = a:(b-a)/n:b; Q = (b-a)/(3*n)*fun(x)*weights'; return
Simpson(@(x) x.^3, 0, 1, 2)
ans = 0.2500
The above example shows that Simpson's rule is perfectly accurate for cubic polynomial functions. On the other hand, the square root function has a derivative that blows up at x= 0, so in this case the results won't be as good, even with a much bigger value of n:
Simpson(@sqrt, 0, 1, 2)
ans = 0.6381
Simpson(@sqrt, 0, 1, 16)
ans = 0.6654
The true value of the ingral of sqrt(x) from 0 to 1 is 2/3, so the error as a function of n looks like:
for j = 1:10 disp(['n = ', num2str(2^j, '%d'), ' ', 'error =', ... num2str(2/3 - Simpson(@sqrt, 0, 1, 2^j), '%1.10f')]) end
n = 2 error =0.0285954792 n = 4 error =0.0101404019 n = 8 error =0.0035873866 n = 16 error =0.0012684780 n = 32 error =0.0004484839 n = 64 error =0.0001585636 n = 128 error =0.0000560607 n = 256 error =0.0000198205 n = 512 error =0.0000070076 n = 1024 error =0.0000024776
One can see from this example that doubling n still decreases the error by more than a factor of 2, but by less than a factor of 16, more like a factor of 3.