MODULE CalcD4;
IMPORT NbrInt, NbrRe, NbrCplx, MathRe, CalcFn;
CONST
Forward* = 9; Central* = 10; Backward* = 11;
VAR
epsilon, zero: NbrRe.Real;
PROCEDURE DoNothing( x: NbrRe.Real );
END DoNothing;
PROCEDURE DoCplxNothing( z: NbrCplx.Complex );
END DoCplxNothing;
PROCEDURE Solve*( f: CalcFn.ReArg; atX: NbrRe.Real; differencing: NbrInt.Integer ): NbrRe.Real;
VAR h, h2, h4, hOpt, hMin, power, result, temp: NbrRe.Real;
BEGIN
power := 4 / 5; hMin := MathRe.Power( NbrRe.Epsilon, power ); power := 1 / 6;
hOpt := ABS( atX ) * MathRe.Power( epsilon, power ); h := NbrRe.Max( hOpt, hMin );
temp := atX + h; DoNothing( temp ); h := temp - atX; h2 := h * h; h4 := h2 * h2;
IF differencing = Forward THEN
result := f( atX + 4 * h );
result := result - 4 * f( atX + 3 * h );
result := result + 6 * f( atX + 2 * h );
result := result - 4 * f( atX + h );
result := (result + f( atX )) / h4
ELSIF differencing = Backward THEN
result := f( atX );
result := result - 4 * f( atX - h );
result := result + 6 * f( atX - 2 * h );
result := result - 4 * f( atX - 3 * h );
result := (result + f( atX - 4 * h )) / h4
ELSE
result := f( atX + 2 * h );
result := result - 4 * f( atX + h );
result := result + 6 * f( atX );
result := result - 4 * f( atX - h );
result := (result + f( atX - 2 * h )) / h4
END;
RETURN result
END Solve;
PROCEDURE SolveCplx*( f: CalcFn.CplxArg; atZ: NbrCplx.Complex; differencing: NbrInt.Integer ): NbrCplx.Complex;
VAR h, hOpt, hMin, power: NbrRe.Real; ch, ch2, ch4, result, temp: NbrCplx.Complex;
BEGIN
power := 4 / 5; hMin := MathRe.Power( NbrRe.Epsilon, power ); power := 1 / 6;
hOpt := NbrCplx.Abs( atZ ) * MathRe.Power( epsilon, power ); h := NbrRe.Max( hOpt, hMin );
NbrCplx.Set( h, h, ch );
temp := atZ + ch; DoCplxNothing( temp ); ch := temp - atZ; ch2 := ch * ch; ch4 := ch2 * ch2;
IF differencing = Forward THEN
result := f( atZ + 4 * ch );
result := result - 4 * f( atZ + 3 * ch );
result := result + 6 * f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := (result + f( atZ )) / ch4
ELSIF differencing = Backward THEN
result := f( atZ );
result := result - 4 * f( atZ - ch );
result := result + 6 * f( atZ - 2 * ch );
result := result - 4 * f( atZ - 3 * ch );
result := (result + f( atZ - 4 * ch )) / ch4
ELSE
result := f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := result + 6 * f( atZ );
result := result - 4 * f( atZ - ch );
result := (result + f( atZ - 2 * ch )) / ch4
END;
RETURN result
END SolveCplx;
PROCEDURE SolveCplxRe*( f: CalcFn.CplxArg; atZ: NbrCplx.Complex; differencing: NbrInt.Integer ): NbrCplx.Complex;
VAR h, hOpt, hMin, power: NbrRe.Real; ch, ch2, ch4, result, temp: NbrCplx.Complex;
BEGIN
power := 4 / 5; hMin := MathRe.Power( NbrRe.Epsilon, power ); power := 1 / 6;
hOpt := NbrCplx.Abs( atZ ) * MathRe.Power( epsilon, power ); h := NbrRe.Max( hOpt, hMin );
NbrCplx.Set( h, zero, ch );
temp := atZ + ch; DoCplxNothing( temp ); ch := temp - atZ; ch2 := ch * ch; ch4 := ch2 * ch2;
IF differencing = Forward THEN
result := f( atZ + 4 * ch );
result := result - 4 * f( atZ + 3 * ch );
result := result + 6 * f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := (result + f( atZ )) / ch4
ELSIF differencing = Backward THEN
result := f( atZ );
result := result - 4 * f( atZ - ch );
result := result + 6 * f( atZ - 2 * ch );
result := result - 4 * f( atZ - 3 * ch );
result := (result + f( atZ - 4 * ch )) / ch4
ELSE
result := f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := result + 6 * f( atZ );
result := result - 4 * f( atZ - ch );
result := (result + f( atZ - 2 * ch )) / ch4
END;
RETURN result
END SolveCplxRe;
PROCEDURE SolveCplxIm*( f: CalcFn.CplxArg; atZ: NbrCplx.Complex; differencing: NbrInt.Integer ): NbrCplx.Complex;
VAR h, hOpt, hMin, power: NbrRe.Real; ch, ch2, ch4, result, temp: NbrCplx.Complex;
BEGIN
power := 4 / 5; hMin := MathRe.Power( NbrRe.Epsilon, power ); power := 1 / 6;
hOpt := NbrCplx.Abs( atZ ) * MathRe.Power( epsilon, power ); h := NbrRe.Max( hOpt, hMin );
NbrCplx.Set( zero, h, ch );
temp := atZ + ch; DoCplxNothing( temp ); ch := temp - atZ; ch2 := ch * ch; ch4 := ch2 * ch2;
IF differencing = Forward THEN
result := f( atZ + 4 * ch );
result := result - 4 * f( atZ + 3 * ch );
result := result + 6 * f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := (result + f( atZ )) / ch4
ELSIF differencing = Backward THEN
result := f( atZ );
result := result - 4 * f( atZ - ch );
result := result + 6 * f( atZ - 2 * ch );
result := result - 4 * f( atZ - 3 * ch );
result := (result + f( atZ - 4 * ch )) / ch4
ELSE
result := f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := result + 6 * f( atZ );
result := result - 4 * f( atZ - ch );
result := (result + f( atZ - 2 * ch )) / ch4
END;
RETURN result
END SolveCplxIm;
PROCEDURE SolveCplxAbs*( f: CalcFn.CplxArg; atZ: NbrCplx.Complex; differencing: NbrInt.Integer ): NbrCplx.Complex;
VAR h, hOpt, hMin, power: NbrRe.Real; ch, ch2, ch4, result, temp: NbrCplx.Complex;
BEGIN
power := 4 / 5; hMin := MathRe.Power( NbrRe.Epsilon, power ); power := 1 / 6;
hOpt := NbrCplx.Abs( atZ ) * MathRe.Power( epsilon, power ); h := NbrRe.Max( hOpt, hMin );
NbrCplx.SetPolar( h, zero, ch );
temp := atZ + ch; DoCplxNothing( temp ); ch := temp - atZ; ch2 := ch * ch; ch4 := ch2 * ch2;
IF differencing = Forward THEN
result := f( atZ + 4 * ch );
result := result - 4 * f( atZ + 3 * ch );
result := result + 6 * f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := (result + f( atZ )) / ch4
ELSIF differencing = Backward THEN
result := f( atZ );
result := result - 4 * f( atZ - ch );
result := result + 6 * f( atZ - 2 * ch );
result := result - 4 * f( atZ - 3 * ch );
result := (result + f( atZ - 4 * ch )) / ch4
ELSE
result := f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := result + 6 * f( atZ );
result := result - 4 * f( atZ - ch );
result := (result + f( atZ - 2 * ch )) / ch4
END;
RETURN result
END SolveCplxAbs;
PROCEDURE SolveCplxArg*( f: CalcFn.CplxArg; atZ: NbrCplx.Complex; differencing: NbrInt.Integer ): NbrCplx.Complex;
VAR h, hOpt, hMin, power: NbrRe.Real; ch, ch2, ch4, result, temp: NbrCplx.Complex;
BEGIN
power := 4 / 5; hMin := MathRe.Power( NbrRe.Epsilon, power ); power := 1 / 6;
hOpt := NbrCplx.Arg( atZ ) * MathRe.Power( epsilon, power ); h := NbrRe.Max( hOpt, hMin );
NbrCplx.SetPolar( zero, h, ch );
temp := atZ + ch; DoCplxNothing( temp ); ch := temp - atZ; ch2 := ch * ch; ch4 := ch2 * ch2;
IF differencing = Forward THEN
result := f( atZ + 4 * ch );
result := result - 4 * f( atZ + 3 * ch );
result := result + 6 * f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := (result + f( atZ )) / ch4
ELSIF differencing = Backward THEN
result := f( atZ );
result := result - 4 * f( atZ - ch );
result := result + 6 * f( atZ - 2 * ch );
result := result - 4 * f( atZ - 3 * ch );
result := (result + f( atZ - 4 * ch )) / ch4
ELSE
result := f( atZ + 2 * ch );
result := result - 4 * f( atZ + ch );
result := result + 6 * f( atZ );
result := result - 4 * f( atZ - ch );
result := (result + f( atZ - 2 * ch )) / ch4
END;
RETURN result
END SolveCplxArg;
BEGIN
epsilon := 100 * NbrRe.Epsilon; zero := 0
END CalcD4.