(* CAPO - Computational Analysis Platform for Oberon - by Alan Freed and Felix Friedrich. *)
(* Version 1, Update 2 *)
MODULE MathErf; (** AUTHOR "adf"; PURPOSE "The error function: erf(x) = (2/Vp) x0x exp(-t2) dt"; *)
(* To change to 64-bit reals, address the code fragments written in light red. *)
(* Ref: J.F. Hart, E.W. Cheney, C.L. Lawson, H.J. Maehly, C.K. Mesztenyi, J.R. Rice, H.G. Thacher, Jr., and C. Witzgall,
"Computer Approximations," in: The SIAM Series in Applied MathLematics, Wiley, New York, 1968. *)
IMPORT NbrInt, NbrRe, DataErrors, MathRe, MathReSeries;
VAR
maxIterations: NbrInt.Integer; twoBySqrtPi: NbrRe.Real;
(* Whenever NbrRe.Real is a 32-bit real, define the following arrays. *)
erfcP1: ARRAY 3 OF NbrRe.Real;
erfcP, erfcQ1: ARRAY 4 OF NbrRe.Real;
erfcQ: ARRAY 5 OF NbrRe.Real;
(* Or whenever NbrRe.Real is a 64-bit real, define the following arrays. *)
(* erfcP1: ARRAY 6 OF NbrRe.Real;
erfcP, erfcQ1: ARRAY 7 OF NbrRe.Real;
erfcQ: ARRAY 8 OF NbrRe.Real; *)
TYPE
ErfP = OBJECT (MathReSeries.Coefficient)
PROCEDURE Evaluate;
VAR m: NbrInt.Integer;
BEGIN
IF n = 0 THEN coef := 0
ELSIF n = 1 THEN coef := 1
ELSE
coef := 2 * (n - 1) * x; m := n + 1;
IF NbrInt.Odd( m ) THEN coef := -coef END
END;
IF n > maxIterations THEN eos := TRUE; DataErrors.ReWarning( x, "Did not converge - timed out." ) END
END Evaluate;
END ErfP;
ErfQ = OBJECT (MathReSeries.Coefficient)
PROCEDURE Evaluate;
BEGIN
IF n = 0 THEN coef := 0
ELSIF n = 1 THEN coef := 1
ELSE coef := 1 + 2 * (n - 1)
END
END Evaluate;
END ErfQ;
PROCEDURE Erfc( x: NbrRe.Real ): NbrRe.Real;
VAR max: NbrInt.Integer; erfc: NbrRe.Real;
BEGIN
max := 26; (* Asymptote reached by this value. *)
IF x > max THEN erfc := 0
ELSIF x < -max THEN erfc := 2
ELSE
IF NbrRe.Abs( x ) > 9 THEN
erfc := MathReSeries.TruncatedRationalFunction( erfcP1, erfcQ1, NbrRe.Abs( x ) )
ELSE erfc := MathReSeries.TruncatedRationalFunction( erfcP, erfcQ, NbrRe.Abs( x ) )
END;
erfc := erfc * NbrRe.Exp( -x * x );
IF x < 0 THEN erfc := 2 - erfc END
END;
RETURN erfc
END Erfc;
PROCEDURE Fn*( x: NbrRe.Real ): NbrRe.Real;
VAR erf: NbrRe.Real; p: ErfP; q: ErfQ;
BEGIN
IF NbrRe.Abs( x ) > 0.1 THEN erf := 1 - Erfc( x )
ELSE
NEW( p ); NEW( q );
erf := twoBySqrtPi * MathRe.Exp( -x * x ) * MathReSeries.ContinuedFraction( p, q, x )
END;
RETURN erf
END Fn;
(*
PROCEDURE CplxFn*( z: NbrCplx.Complex ): NbrCplx.Complex;
VAR
BEGIN
END CplxFn;
*)
BEGIN
maxIterations := 1000; twoBySqrtPi := 2 / MathRe.Sqrt( NbrRe.Pi );
(* Whenever NbrRe.Real is a 32-bit real, use the following eonstants. *)
(* Constants from Table ERFC 5663 from "Computer Approximations". *)
erfcP[0] := 1.000464117E1; erfcP[1] := 8.426552865; erfcP[2] := 3.460259332; erfcP[3] := 5.623536121E-1;
erfcQ[0] := 1.000464117E1; erfcQ[1] := 1.971558074E1; erfcQ[2] := 1.570228809E1; erfcQ[3] := 6.090748787;
erfcQ[4] := 1.0;
(* Constants from Table ERFC 5722 from "Computer Approximations". *)
erfcP1[0] := 6.141050179E-1; erfcP1[1] := 3.295899049E-1; erfcP1[2] := 5.641895902E-1;
erfcQ1[0] := 2.953483222E-1; erfcQ1[1] := 1.588352760; erfcQ1[2] := 5.841849230E-1; erfcQ1[3] := 1.0
(* Or, whenever NbrRe.Real is a 64-bit real, use the following eonstants. *)
(* (* Constants from Table ERFC 5666 from "Computer Approximations". *)
erfcP[0] := 4.4041373582475223325269D2; erfcP[1] := 6.25686535769683006135193D2;
erfcP[2] := 4.483171659914834429345063D2; erfcP[3] := 1.9184014058796685752390301D2;
erfcP[4] := 5.0991697628253203795669523D1; erfcP[5] := 7.9239298287415448527194039D0;
erfcP[6] := 0.56419994559825748305038673D0; erfcQ[0] := 4.4041373582475221430599D2;
erfcQ[1] := 1.122640220177046578853681D3; erfcQ[2] := 1.2746672667576622866580268D3;
erfcQ[3] := 8.3881036547840644197941778D2; erfcQ[4] := 3.47122928811784331429078057D2;
erfcQ[5] := 9.08727112035370362595507371D1; erfcQ[6] := 1.404533730546113829847322587D1;
erfcQ[7] := 1.0D0;
(* Constants from Table ERFC 5725 from "Computer Approximations". *)
erfcP1[0] := 2.9788656263939928862D0; erfcP1[1] := 7.409740605964741794425D0;
erfcP1[2] := 6.1602098531096305440906D0; erfcP1[3] := 5.019049726784267463450058D0;
erfcP1[4] := 1.275366644729965952479585264D0; erfcP1[5] := 0.5641895835477550741253201704D0;
erfcQ1[0] := 3.3690752069827527677D0; erfcQ1[1] := 9.608965327192787870698D0;
erfcQ1[2] := 1.708144074746600431571095D1; erfcQ1[3] := 1.20489519278551290360340491D1;
erfcQ1[4] := 9.396034016235054150430579648D0; erfcQ1[5] := 2.260528520767326969591866945D0;
erfcQ1[6] := 1.0D0 *)
END MathErf.