home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------------------------- *)
- (* NUMINT.PAS *)
- (* Unterprogramme zur numerischen Integration *)
- (* *)
- (* Copyright (c) 1989 TOOLBOX & Karsten Gieselmann *)
- (* ------------------------------------------------------------------------- *)
-
- UNIT NumInt;
-
- INTERFACE
-
- CONST
- MaxDim = 3; (* Maximale Dimension eines Mehrfachintegrals *)
-
- TYPE
- {$IFDEF CPU87}
- FLOAT = DOUBLE; (* Fließkommatyp *)
- {$ELSE}
- FLOAT = REAL;
- {$ENDIF}
- VECTOR = ARRAY[1..MaxDim] OF FLOAT;
- POINTS = ARRAY[1..MaxDim] OF WORD; (* Stützstellen *)
- PROC = POINTER;{ TO FUNCTION(FLOAT ) : FLOAT } (* Prozedurparameter *)
- VPROC = POINTER;{ TO FUNCTION(VECTOR) : FLOAT }
-
-
- (* ------------- Grundlegende Integrationsverfahren (Regeln) ------------- *)
-
- FUNCTION Trapezoid(Integrand : PROC; a,b : FLOAT; N : WORD) : FLOAT;
- (* Integration mit der Trapez-Regel *)
-
- FUNCTION Simpson(Integrand : PROC; a,b : FLOAT; N : WORD) : FLOAT;
- (* Integration mit der Simpson-Regel *)
-
- FUNCTION Gauss(Integrand : PROC; a,b : FLOAT; N : WORD) : FLOAT;
- (* Integration durch Gauss-Quadratur *)
-
-
- (* --- Aufbauende Methoden zur automatischen Berechnung eines Integrals -- *)
-
- FUNCTION Successive( Rule : PROC; (* Integrationsregel *)
- f : PROC; (* Integrandenfunktion *)
- a,b : FLOAT; (* Integrationsgrenzen *)
- Accuracy : FLOAT; (* relative Genauigkeit *)
- MaxPoints : WORD; (* Maximale Stützstellenzahl *)
- VAR Result : FLOAT; (* Wert des Integrals *)
- VAR Error : FLOAT) (* absoluter Fehler *)
- : BOOLEAN; (* Genauigkeit erreicht? *)
-
- FUNCTION Adaptive ( Rule : PROC; (* Integrationsregel *)
- f : PROC; (* Integrandenfunktion *)
- a,b : FLOAT; (* Integrationsgrenzen *)
- Accuracy : FLOAT; (* relative Genauigkeit *)
- Points : WORD; (* Stützstellenzahl *)
- MaxIntervals : WORD; (* maximale Intervallzahl *)
- VAR Result : FLOAT; (* Wert des Integrals *)
- VAR Error : FLOAT) (* absoluter Fehler *)
- : BOOLEAN; (* Genauigkeit erreicht? *)
-
-
- (* ---------------- Berechnung von Mehrfach-Integralen ------------------- *)
-
- FUNCTION Romberg( Integrand : PROC; (* Integrandenfunktion *)
- Dim : WORD; (* Dimension des Integranden *)
- a,b : VECTOR; (* Integrationsgrenzen *)
- Accuracy : FLOAT; (* relative Genauigkeit *)
- N : POINTS; (* Gewichtsfaktoren *)
- MaxStep : WORD; (* Maximale Schrittzahl *)
- VAR Result : FLOAT; (* Wert des Integrals *)
- VAR Error : FLOAT) (* absoluter Fehler *)
- : BOOLEAN; (* Genauigkeit erreicht? *)
-
-
-
- IMPLEMENTATION
-
-
- FUNCTION Trapezoid;
- (* Integration mit der Trapez-Regel *)
- VAR
- h,T : FLOAT;
- i : WORD;
-
- FUNCTION f(x : FLOAT) : FLOAT;
- INLINE($FF/$9E/Integrand); (* CALL FAR Integrand[BP] *)
-
- BEGIN
- h := (b-a)/N;
- T := (f(a)+f(b)) * 0.5;
- FOR i:=1 TO N-1 DO
- T := T + f(a+i*h);
- Trapezoid := T*h
- END;
-
-
- FUNCTION Simpson;
- (* Integration mit der Simpson-Regel *)
- VAR
- h,S : FLOAT;
- i : WORD;
-
- FUNCTION f(x : FLOAT) : FLOAT;
- INLINE($FF/$9E/Integrand); (* CALL FAR Integrand[BP] *)
-
- BEGIN
- h := (b-a)/(2*N);
- S := f(a) + f(b);
- FOR i:=0 TO N-1 DO
- S := S + 4.0*f(a+(2*i+1)*h);
- FOR i:=1 TO N-1 DO
- S := S + 2.0*f(a+(2*i)*h);
- Simpson := S * h/3.0;
- END;
-
-
- FUNCTION Gauss;
- (* Integration durch Gauss-Quadratur *)
- CONST
- z : ARRAY[1..16] OF FLOAT = ( (* Stützstellen *)
- 0.095012509837637440185, -0.095012509837637440185,
- 0.281603550779258913230, -0.281603550779258913230,
- 0.458016777657227386342, -0.458016777657227386342,
- 0.617876244402643748447, -0.617876244402643748447,
- 0.755404408355003033895, -0.755404408355003033895,
- 0.865631202387831743880, -0.865631202387831743880,
- 0.944575023073232576078, -0.944575023073232576078,
- 0.989400934991649932596, -0.989400934991649932596);
-
- w : ARRAY[1..16] OF FLOAT = ( (* Gewichte *)
- 0.189450610455068496285, 0.189450610455068496285,
- 0.182603415044923588867, 0.182603415044923588867,
- 0.169156519395002538189, 0.169156519395002538189,
- 0.149595988816576732081, 0.149595988816576732081,
- 0.124628971255533872052, 0.124628971255533872052,
- 0.095158511682492784810, 0.095158511682492784810,
- 0.062253523938647892863, 0.062253523938647892863,
- 0.027152459411754094852, 0.027152459411754094852);
- VAR
- i,j : WORD;
- x,g,h : FLOAT;
-
- FUNCTION f(x : FLOAT) : FLOAT;
- INLINE($FF/$9E/Integrand); (* CALL FAR Integrand[BP] *)
-
- BEGIN
- h := (b-a)/(2*N);
- g := 0;
- FOR i:=1 TO N DO
- FOR j:=1 TO 16 DO
- BEGIN
- x := a + h*(2*i-1+z[j]);
- g := g + f(x)*w[j];
- END;
- Gauss := g * h
- END;
-
-
- FUNCTION Successive;
- (* Integration durch sukzessive Stützstellenverdopplung *)
- VAR
- LastResult : FLOAT;
- N : WORD;
- Success : BOOLEAN;
-
- FUNCTION Integrate(f : PROC; a,b : FLOAT; N : WORD) : FLOAT;
- INLINE($FF/$9E/Rule); (* CALL FAR Rule[BP] *)
-
- BEGIN
- N := 2;
- Success := FALSE;
- Result := Integrate(f, a, b, N); (* erste Näherung bestimmen *)
- REPEAT
- LastResult := Result;
- N := N * 2; (* Stützstellen verdoppeln! *)
- Result := Integrate(f, a, b, N);
- Error := ABS(Result-LastResult);
- Success := (Error < ABS(Accuracy*Result)); (* bis Genauigkeit erreicht *)
- UNTIL (N > MaxPoints) OR Success;
- Successive := Success;
- END;
-
-
- FUNCTION Adaptive;
- (* Adaptive Integration durch rekursive Intervallhalbierung *)
- CONST
- Rule_ : PROC = NIL;
- VAR
- r,e,EstimateError : FLOAT;
- Intervals : WORD;
-
- FUNCTION Integrate(f : PROC; a,b : FLOAT; N : WORD) : FLOAT;
- INLINE($FF/$1E/Rule_); (* CALL FAR Rule_[DS] *)
-
- FUNCTION SubInterval(a, b : FLOAT) : BOOLEAN;
- (* rekusive Integration, liefert TRUE bei erfolgreicher Bearbeitung *)
- BEGIN
- SubInterval := FALSE;
- IF Intervals <= MaxIntervals THEN BEGIN
- r := Integrate(f, a, b, Points*2);
- e := ABS(r - Integrate(f, a, b, Points));
- IF e <= EstimateError THEN BEGIN (* Genauigkeit erreicht? *)
- Result := Result + r; (* Teilergebnisse aufaddieren *)
- Error := Error + e;
- END ELSE BEGIN
- INC(Intervals);
- IF NOT SubInterval(a, (a+b)/2) THEN EXIT;
- IF NOT SubInterval((a+b)/2, b) THEN EXIT;
- END;
- SubInterval := TRUE;
- END;
- END;
-
- BEGIN
- Rule_ := Rule; (* Zugriff über DS, da BP sich verändert (Rekursion!) *)
- Intervals := 0;
- Result := 0;
- Error := 0;
- EstimateError := ABS(Accuracy * Integrate(f, a, b, Points));
- Adaptive := SubInterval(a, b);
- END;
-
-
- FUNCTION Romberg;
- (* Berechnung eines Mehrfachintegrals nach dem Romberg-Verfahren *)
- CONST
- Integrand_ : PROC = NIL;
- VAR
- p,x : VECTOR;
- T : ARRAY[1..100] OF FLOAT;
- i,j,k : WORD;
- LastResult,w : FLOAT;
-
- FUNCTION f(x : VECTOR) : FLOAT;
- INLINE($FF/$1E/Integrand_); (* CALL FAR Integrand_[DS] *)
-
- FUNCTION Sum(k : WORD) : FLOAT;
- (* Rekursives Aufsummieren *)
- VAR
- i : WORD;
- s : FLOAT;
- BEGIN
- s := 0;
- FOR i:=1 TO N[k] DO BEGIN
- x[k] := a[k] + p[k]*(i-0.5);
- IF k > 1 THEN (* schon auf unterster Ebene? *)
- s := s + Sum(k-1)
- ELSE
- s := s + f(x);
- END;
- Sum := s;
- END;
-
- BEGIN
- Romberg := FALSE;
- IF NOT(Dim IN [1..MaxDim]) THEN EXIT; (* unerlaubte Dimension *)
- Integrand_ := Integrand;
- LastResult := 0.0;
- k := 1;
- REPEAT
- FOR i:=1 TO Dim DO BEGIN
- p[i] := (b[i]-a[i]) / N[i]; (* Bestimmung der Gewichte *)
- END;
- T[k] := Sum(Dim); (* Aufsummieren der Funktionswerte *)
- FOR i:=1 TO Dim DO
- T[k] := T[k] * p[i]; (* Multiplikation mit den Gewichten *)
- FOR j:=2 TO k DO BEGIN
- i := Succ(k) - j;
- w := 2 shl (j-2);
- T[i] := T[i+1] + (T[i+1]-T[i])/(Sqr(w)-1.0);
- END;
- Result := T[1];
- Error := ABS(Result - LastResult); (* erreichte Genauigkeit *)
- INC(k);
- FOR i:=1 TO Dim DO (* Zahl der Stützstellen pro Dimension verdoppeln *)
- N[i] := 2*N[i];
- LastResult := Result;
- UNTIL (k > MaxStep) OR ((k > 2) AND (Error < ABS(Result*Accuracy)));
- Romberg := Error < ABS(Result*Accuracy);
- END;
-
- END.