Unit integral;
interface
Const
max_dim = 10;
max_deg = 96;
Type
real_fun = Function (x: real): real;
real_fun2 = Function (x,y: real): real;
real_vec = array[1..max_dim+1] Of real;
index = array [1..max_dim+1] Of word;
vec_fun = Function (j: word; x: real_vec): real;
Var no_evalutions, highest_level: word;
Function simpson(F: real_fun; x0,x1: real; div_no: word): real;
{ вычисление интеграла методом Симпсона }
Function double_simpson (F: real_fun2; x0,x1,y0,y1: real; x_div, y_div: word): real;
{ вычисление двойного интеграла методом Симпсона }
Function adaptive_simpson (F: real_fun; x0,x1,eps,eta: real): real;
{ вычисление интеграла методом Симпсона с заданной точностью }
Function romberg( f: real_fun; x0,x1,eps,eta: real; min, max: word): real;
{ вычисление интеграла методом Ромберга }
Function gauss3 (f: real_fun; x0,x1: real; n: word): real;
{ вычисление интеграла по 3-х точечной ф-ле Гаусса }
Procedure compute_gauss_coeffs( deg: word);
{ вычисление коэф-тов для ф-лы Гаусса }
Function gauss(F: real_fun; x0,x1: real; deg: word): real;
{ вычисление интеграла методом Гаусса }
implementation
uses crt;
Var zero, weight: array [1..max_deg] Of real;
Function simpson (F: real_fun; x0,x1: real; div_no: word): real;
Var x,dx,sum: real;
j: word;
Begin
dx := (x1-x0)/(2.0*div_no);
sum := F(x0)+F(x1);
x := x0;
For j:=1 To 2*div_no-1 Do
Begin
x := x+dx;
If odd(j) Then sum := sum+4.0*F(x)
Else sum := sum+2.0*F(x);
End;
simpson := dx*sum/3.0;
End;
Function double_simpson (F: real_fun2; x0,x1,y0,y1: real; x_div, y_div : word): real;
Var dx,dy,x,sum: real;
i: word;
Function simple_simpson (x: real): real;
Var y,sum: real;
j,v: word;
Begin
sum := F(x,y0)+F(x,y1);
y := y0;
For j:=1 To 2*y_div-1 Do
Begin
y := y+dy;
If odd(j) Then sum := sum+4.0*F(x,y)
Else sum := sum+2.0*F(x,y);
End;
simple_simpson := sum;
End; {simple_simpson}
Begin{double_simpson}
dx := (x1-x0)/(2.0*x_div);
dy := (y1-y0)/(2.0*y_div);
x := x0;
sum := simple_simpson(x0)+simple_simpson(x1);
For i:=1 To 2*x_div-1 Do
Begin
x := x+dx;
If odd(i) Then sum := sum+4.0*simple_simpson(x)
Else sum := sum+2.0*simple_simpson(x);
End;
double_simpson := dx*dy*sum/9.0;
End;{double_simpson}
Function adaptive_simpson (F: real_fun; x0,x1,eps,eta: real): real;
Const max_level = 35;
Var k,nest_level: word;
integral_abs: real;
Function simpson3point(x0,delta_x, estimate, integral_abs, eps, eta, left, middle, right:
real): real;
Var dx3, sum, eps3, eta3, factor, left_integ, middle_integ, right_integ, F1,F2,F4,F5 :
real
;
Begin
inc(nest_level);
dx3 := delta_x/3.0;
F1 := F(x0+0.5*dx3);
F2 := F(x0+dx3);
F4 := F(x0+2.0*dx3);
F5 := F(x0+2.5*dx3);
inc(no_evalutions,4);
factor := dx3/6.0;
left_integ := factor*(left+4.0*F1+F2);
middle_integ := factor*(F2+4.0*middle+F4);
right_integ := factor*(F4+4.0*F5+right);
sum := left_integ+middle_integ+right_integ;
integral_abs := integral_abs-abs(estimate)+abs(left_integ)+abs(middle_integ)+abs(
right_integ);
If (nest_level>1) And ((nest_level = max_level) Or (abs(sum-estimate) <= eps+eta*
integral_abs)) Then
simpson3point := sum
Else
Begin
If nest_level>highest_level Then
inc(highest_level);
eps3 := 0.577*eps;
eta3 := 0.577*eta;
left_integ := simpson3point(x0,dx3,left_integ, integral_abs, eps3, eta3, left, F1,
F2);
middle_integ := simpson3point(x0+dx3, dx3, middle_integ, integral_abs, eps3, eta3,
F2, middle, F4);
right_integ := simpson3point(x0+2.0*dx3,dx3,right_integ, integral_abs, eps3, eta3,
F4, F5, right);
simpson3point := left_integ+middle_integ+right_integ;
End;
dec(nest_level);
End; {simpson3point}
Begin {adaptive_simpson}
nest_level := 1;
highest_level := 1;
no_evalutions := 3;
adaptive_simpson := simpson3point(x0,x1-x0,0.0,0.0,eps,eta,F(x0),F(x0+0.5*(x1-x0)), F(x1
));
End; {adaptive_simpson}
Function romberg(F: real_fun; x0,x1,eps,eta: real; min, max: word): real;
Const abs_max = 30;
Var p,dx,error, F_of_x0, F_of_x1, F_of_xk, roundoff_error, integral_abs, tolerance,
pervious_estimate, current_estimate,
mid_sum, temp_sum, mid_sum_abs: real;
table: array[0..abs_max] Of real;
j,n: word;
k,r: longint;
done: boolean;
denom: array[1..abs_max] Of real;
Begin
p := 1.0;
For k:=1 To abs_max Do
Begin
p := 4.0*p;
denom[k] := 1.0/(p-1.0);
End;
dx := x1-x0;
F_of_x0 := F(x0);
F_of_x1 := F(x1);
current_estimate := 0.0;
pervious_estimate := 0.0;
done := false;
table[0] := 0.5*dx*(F_of_x0+F_of_x1);
integral_abs := 0.5*abs(dx)*(abs(F_of_x0)+abs(F_of_x1));
n := 1;
r := 1;
Repeat
dx := 0.5*dx;
mid_sum := 0.0;
mid_sum_abs := 0.0;
roundoff_error := 0.0;
For k:=1 To r Do
Begin
F_of_xk := F(x0+(2*k-1)*dx);
mid_sum_abs := mid_sum_abs+abs(F_of_xk);
F_of_xk := F_of_xk+roundoff_error;
temp_sum := mid_sum+F_of_xk;
roundoff_error := (mid_sum-temp_sum)+F_of_xk;
mid_sum := temp_sum;
If keypressed Then halt;
End;
table[n] := 0.5*table[n-1]+dx*mid_sum;
integral_abs := 0.5*integral_abs+abs(dx)*mid_sum_abs;
For j:=n-1 Downto 0 Do
table[j] := table[j+1]+denom[n-j]*(table[j+1]-table[j]);
If n>=min Then
Begin
tolerance := eta*integral_abs+eps;
error := abs(table[0]-current_estimate)+abs(current_estimate-pervious_estimate);
done := (error<tolerance);
End;
inc(n);
done := done Or (n>max);
pervious_estimate := current_estimate;
current_estimate := table[0];
r := r+r;
Until done;
romberg := current_estimate;
End;
Function gauss3(F: real_fun; x0,x1: real; n: word): real;
Var t,sum,x,z,dx: real;
i,k: word;
gzero, gweight: array[1..3] Of real;
Procedure initialize_constants;
Var s,t: real;
j: word;
Begin
gzero[1] := -sqrt(0.6);
gzero[2] := 0.0;
gzero[3] := sqrt(0.6);
gweight[1] := 5.0/9.0;
gweight[2] := 8.0/9.0;
gweight[3] := 5.0/9.0;
For j:=1 To 3 Do
Begin
gzero[j] := 0.5*(1.0+gzero[j]);
gweight[j] := 0.5*gweight[j];
End;
End;{initialize_constants}
Begin{gauss3}
initialize_constants;
dx := (x1-x0)/n;
x := x0;
sum := 0.0;
For i:=0 To n-1 Do
Begin
t := 0.0;
For k:=1 To 3 Do
Begin
z := x+dx*gzero[k];
t := t+gweight[k]*F(z)
End;
sum := sum+dx*t;
x := x+dx;
End;
gauss3 := sum;
End;{gauss3}
Procedure compute_gauss_coeffs(deg: word);
Const eps = 6.0e-20;
Var i,index: word;
p0k, p0k_1, d0k, p1k, p1k_1, d1k, x0,x1,y,z,dx,x,u: real;
Procedure legendre_poly(n: word; x: real; Var Pk,Pk_1,Dk: real);
Var pk_2, dk_1, dk_2: real;
i,j,k: word;
Begin
If n=0 Then
Begin
pk := 1.0;
dk := 0.0;
End
Else
Begin
pk_1 := 1.0;
Pk := x;
Dk_1 := 0.0;
Dk := 1.0;
i := 3;
j := 1;
For k:=2 To n Do
Begin
pk_2 := pk_1;
pk_1 := pk;
dk_2 := dk_1;
dk_1 := dk;
pk := (i*x*Pk_1-j*Pk_2)/k;
Dk := (i*(Pk_1+x*Dk_1)-j*dk_2)/k;
inc(i,2);
inc(j);
End;
End
End; {legendre_poly}
Begin{compute_gauss_coeffs}
index := (deg+1) Div 2;
dx := 1.0/(10.0*deg);
x0 := 0.0;
x1 := x0+dx;
If odd(deg) Then
Begin
zero[index] := 0.0;
legendre_poly(deg,x0,P0k, P0k_1, D0k);
weight[index] := 2.0/(P0k_1*D0k*deg);
End;
For i:=0 To 10*deg-1 Do
Begin
x0 := x1;
x1 := x1+dx;
legendre_poly(deg,x0,p0k,p0k_1,d0k);
legendre_poly(deg,x1,p1k,p1k_1,d1k);
If p0k*p1k <= 0.0 Then
Begin
x := x0-p0k*dx/(p1k-p0k);
legendre_poly(deg,x,p0k,p0k_1,d0k);
u := p0k/d0k;
y := x-u;
while abs(x-y) >= eps Do
Begin
If keypressed Then
Begin
writeln('>=eps loop: ',x:10:10,' ',y:10:10, ' ',abs(x-y): 10);
readln;
End;
x := y;
legendre_poly(deg,x,p0k,p0k_1,d0k);
u := p0k/d0k;
y := x-u;
End;
inc(index);
legendre_poly(deg,y,p0k,p0k_1,d0k);
zero[index] := y;
weight[index] := 2.0/(p0k_1*d0k*deg);
If index=deg Then
break;
End;
End;
For i:=1 To deg Div 2 Do
Begin
zero[i] := -zero[deg-i+1];
weight[i] := weight[deg-i+1];
End;
End;{compute_gauss_coeffs}
Function gauss(F: real_fun; x0,x1: real; deg: word): real;
Var index: word;
a,b,sum: real;
Begin
a := 0.5*(x1-x0);
b := 0.5*(x1+x0);
sum := 0.0;
For index:=1 To deg Do
Begin
sum := sum+F(a*zero[index]+b)*weight[index];
If keypressed Then halt;
End;
gauss := a*sum;
End;
End.