home *** CD-ROM | disk | FTP | other *** search
- { Complex Function Library for use with TURBO PASCAL include statement
- based on D.D. Clark article in Dr. Dobb's Journal, Oct. 1984, with
- modifications to make Polar actually work properly, etc.
- J.M.Weiss, 1572 Peacock Ave., Sunnyvale, CA 94087
- 3/6/84 }
-
- TYPE Complex = RECORD
- re : Real;
- im : Real
- END; {of RECORD}
-
- {Following is for Turbo-87 Version with 8087 support }
- CONST Precision: Real=1.5e-16;
- max_real:Real=1.67e308;
- big_sqrt:Real=1.29e154;
- closest:Real=4.19e-307;
-
- {Following is for Turbo Version without 8087 support
- CONST Precision: Real=1.e-11;
- max_real:Real=1.e38;
- big_sqrt:Real=1.e19;
- closest:Real=1.e-39; }
-
- PROCEDURE Cadd( Arg1, Arg2: Complex; VAR Result: Complex);
- {adds Arg1 and Arg2 and returns sum in Result}
-
- BEGIN {Cadd}
- Result.re := Arg1.re + Arg2.re;
- Result.im := Arg1.im + Arg2.im;
- END;{ of Cadd}
-
- PROCEDURE Csub( Arg1, Arg2: Complex; VAR Result: Complex);
- {subtracts Arg2 and Arg1 and returns difference in Result}
-
- BEGIN {Csub}
- Result.re := Arg1.re - Arg2.re;
- Result.im := Arg1.im - Arg2.im;
- END;{ of Csub}
-
- PROCEDURE Cmult( Arg1, Arg2: Complex; VAR Result: Complex );
- {multiplies Arg1 by Arg2 and returns quotient in Result}
-
- BEGIN {Cmult}
- Result.re := Arg1.re*Arg2.re - Arg1.im*Arg2.im;
- Result.im := Arg1.im*Arg2.re + Arg1.re*Arg2.im
- END; {of Cmult}
-
- PROCEDURE Cdiv( Arg1, Arg2: Complex; VAR Result: Complex );
- {divides Arg1 by Arg2 and returns quotient in Result}
-
- VAR Denom: Real;
-
- BEGIN {Cdiv}
- Denom := Sqr(Arg2.re) + Sqr(Arg2.im);
- Result.re := (Arg1.re*Arg2.re + Arg1.im*Arg2.im)/Denom;
- Result.im := (Arg1.im*Arg2.re - Arg1.re*Arg2.im)/Denom
- END; {of Cdiv}
-
-
-
-
-
- PROCEDURE Cexp( Arg: Complex; VAR Result: Complex );
- {raises e to the arg and returns as result}
-
- VAR Expo: Real;
-
- BEGIN {Cexp }
- Expo := Exp(Arg.re);
- Result.re := Expo*Cos(Arg.im);
- Result.im := Expo*Sin(Arg.im)
- END; {of Cexp}
-
-
-
-
-
- PROCEDURE Csin( Arg: Complex; VAR Result: Complex );
- {takes the sine of arg and returns as result}
- {Warning 15 digits precision ==> sin(pi)=1.e-16}
-
- VAR One,Exp1,Part1,Part2,Sum,Divisor: Complex;
-
- BEGIN {Csin}
- One.re := 1.0;
- One.im := 0.0;
- Exp1.re := - Arg.im; { z*i }
- Exp1.im := Arg.re;
- Cexp(Exp1, Part1); { exp(zi) }
- Cdiv(One,Part1,Part2);
- Csub(Part1, Part2, Sum);
- Divisor.re := 0.0;
- Divisor.im := 2.0;
- Cdiv(Sum, Divisor, Result); { exp(zi) - exp(-zi))/(2i) }
- IF Abs(Result.re) < Precision THEN Result.re := 0.0;
- IF Abs(Result.im) < Precision THEN Result.im :=0.0;
- END; { of Csin }
-
- PROCEDURE Ccos( Arg: Complex; VAR Result: Complex );
- {takes the cosine of arg and returns as result}
- {Precision warning: 15 digits: cos(pi/2)=6.e-17}
-
- VAR One,Exp1,Part1,Part2,Sum,Divisor: Complex;
-
- BEGIN {Ccos}
- One.re := 1.0;
- One.im := 0.0;
- Exp1.re := - Arg.im; { z*i }
- Exp1.im := Arg.re;
- Cexp(Exp1, Part1); { exp(zi) }
- Cdiv(One,Part1,Part2);
- Cadd(Part1, Part2, Sum);
- Divisor.re := 2.0;
- Divisor.im := 0.0;
- Cdiv(Sum, Divisor, Result); { exp(zi) + exp(-zi))/2 }
- IF Abs(Result.re) < Precision THEN Result.re := 0.0;
- IF Abs(Result.im) < Precision THEN Result.im :=0.0;
- END; {of Ccos }
-
- PROCEDURE Ctan (Arg: Complex; VAR Result: Complex);
-
- VAR Arg1,Arg2: Complex;
-
- BEGIN {Ctan}
- Csin(Arg,Arg1);
- Ccos(Arg,Arg2);
- Cdiv( Arg1,Arg2, Result)
- END; {of Ctan}
-
- PROCEDURE Cmplx (Arg1, Arg2: real; VAR Result: Complex);
-
- BEGIN {Cmplx}
- Result.re := Arg1;
- Result.im := Arg2
- END; {of Cmplx}
-
- PROCEDURE Conj(VAR Arg: Complex);
- {take complex conjugate of complex variable Arg}
-
- BEGIN {Conj}
- Arg.im := -Arg.im
- END; {of Conj}
-
- PROCEDURE Rect(Modulus,Phase: Real; VAR Result: Complex);
- {convert modulus and phase to rectangular coordinate}
-
- BEGIN {Rect}
- Result.re := Modulus*Cos(Phase);
- Result.im := Modulus*Sin(Phase)
- END; {of Rect}
-
-
-
- PROCEDURE Csqr(Arg: Complex; VAR Result:Complex);
- {take complex square of Arg and return Result}
-
- BEGIN {Csqr}
- Cmult(Arg,Arg,Result)
- END; {of Csqr}
-
- PROCEDURE Cscale(Scale: Real; Arg: Complex; VAR Result:Complex);
-
- BEGIN {Cscale}
- Result.re := Scale*Arg.re;
- Result.im := Scale*Arg.im
- END; {of Cscale}
-
- FUNCTION SafeDivide(x,y:Real) : Real;
- { divide x by y and intercept incipient underflow or overflow}
-
- LABEL 1;
-
- BEGIN {SafeDivide}
- if Abs(y) < 1.0 then {check overflow}
- if Abs(x) > Abs(y)*max_real then
- SafeDivide := max_real
- else
- goto 1
- else if abs(x) < 1.0 then {check underflow}
- if Abs(y) > Abs(x)*max_real then
- SafeDivide := 0.0
- else
- goto 1
- else
- 1: SafeDivide := x/y {normal calculation}
- END; {of SafeDivide}
-
- FUNCTION ATan2(x,y:Real) : Real;
- {take arctangent of x/y and account for right angles and proper quadrant}
- VAR
- a: Real;
- BEGIN {ATan2}
- if y = 0.0 then {check for exceptional cases with y=0.0}
- if(x = 0.0) then {if both arguments are zero, return zero}
- a := 0.0
- else
- a := 0.5*pi {otherwise its a right angle}
- else begin
- a := SafeDivide(x,y); { try the divide, preventing unseemly errors}
- if a>= 1.e308 then
- a:= 0.5*pi
- else begin
- if a<> 0.0 then
- begin
- a:=Abs(a);
- if a>big_sqrt then
- a:=0.5*pi
- else if a< closest then
- a:=0.0
- else
- a:=ArcTan(a);
- end;
- if y < 0.0 then {choose upper or lower half of plane}
- a:= pi - a;
- end;
- end;
- if x < 0.0 then {choose left or right half of plane}
- a := -a;
- ATan2 := a
- end; {of ATan2}
-
- PROCEDURE Polar(Arg: Complex; VAR Modulus, Phase: Real);
- {converts a complex number arg in rectangular form to polar form}
-
- BEGIN {Polar}
- if Abs(Arg.re) < closest then
- Arg.re := 0.0;
- if Abs(Arg.im) < closest then
- Arg.im := 0.0;
- Modulus := Sqrt(Sqr(Arg.re) + Sqr(Arg.im));
- Phase := ATan2(Arg.im,Arg.re)
- END; { of Polar}
-
- PROCEDURE Ctopower( Arg: Complex; Power: Integer; VAR Result: Complex );
- {raises Arg to integral Power and returns the answer in Result}
-
- VAR i: Integer;
- Modulus, Phase, NewMod, PowAmp: Real;
-
- BEGIN {Ctopower}
- IF Power = 0 THEN BEGIN
- Result.re := 1.0;
- Result.im := 0.0
- END
- ELSE BEGIN
- Polar(Arg, Modulus, Phase);
- NewMod := 1;
- IF Power >0 THEN
- FOR i := 1 TO Power DO NewMod := NewMod*Modulus
- ELSE
- FOR i := 1 TO Abs(Power) DO NewMod := NewMod/Modulus;
- PowAmp := Power*Phase;
- Result.re := NewMod*Cos(PowAmp);
- Result.im := NewMod*Sin(PowAmp)
- END
- END; { of Ctopower}
-
- PROCEDURE Cln( Arg: Complex; VAR Result: Complex );
- {takes natural log of arg as result}
-
- VAR Modulus,Phase: Real;
-
- BEGIN {Cln}
- Polar(Arg, Modulus, Phase);
- Result.re := Ln(Modulus);
- Result.im := Phase
- END; { of Cln }
-
- PROCEDURE CtoC( Arg1,Arg2: Complex; VAR Result: Complex );
- {takes complex number arg1 to complex power arg2}
-
- VAR LogPart, Expo: Complex;
-
- BEGIN { CtoC }
- Cln(Arg1, LogPart);
- Cmult(Arg2,LogPart, Expo);
- Cexp(Expo, Result )
- END; {of CtoC}
-
- PROCEDURE Csqrt(Arg: Complex; VAR Result:Complex);
- {take complex square root of Arg and return Result}
-
- VAR
- Argmag,Argphs: Real;
-
- BEGIN {Csqrt}
- Polar(Arg,Argmag,Argphs);
- Argmag:=Sqrt(Argmag);
- Argphs:=0.5*Argphs;
- Rect(Argmag,Argphs,Result)
- END; {of Csqrt}