688 lines
19 KiB
ObjectPascal
688 lines
19 KiB
ObjectPascal
{-----------------------------------------------------------------------------
|
|
The contents of this file are subject to the Mozilla Public License
|
|
Version 1.1 (the "License"); you may not use this file except in compliance
|
|
with the License. You may obtain a copy of the License at
|
|
http://www.mozilla.org/MPL/MPL-1.1.html
|
|
|
|
Software distributed under the License is distributed on an "AS IS" basis,
|
|
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
|
|
the specific language governing rights and limitations under the License.
|
|
|
|
The Original Code is: JvComplex.PAS, released on 2001-02-28.
|
|
|
|
The Initial Developer of the Original Code is Peter Thörnqvist [peter3 att users dott sourceforge dott net]
|
|
Portions created by Peter Thörnqvist are Copyright (C) 1997 Peter Thörnqvist.
|
|
All Rights Reserved.
|
|
|
|
Contributor(s):
|
|
|
|
Last Modified: 2002-06-24
|
|
|
|
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
|
|
located at http://jvcl.sourceforge.net
|
|
|
|
Known Issues:
|
|
-----------------------------------------------------------------------------}
|
|
|
|
{$I JVCL.INC}
|
|
|
|
{
|
|
@abstract(functions to handle complex numbers)
|
|
@author(Peter Thornqvist (peter3 att users dott sourceforge dott net))
|
|
@created()
|
|
@lastmod()
|
|
}
|
|
|
|
unit JvComplex;
|
|
|
|
{
|
|
@exclude
|
|
This is a unit that implements functions to handle complex numbers. It is a
|
|
translation of the complex.cpp files supplied with, among others, Symantec's C++ 7.0.
|
|
|
|
These functions might not be public domain which means I'm up for a trial RSN...
|
|
Anyway, you need at least Delphi 2.0 and the Math.pas unit (supplied with Delphi) to make
|
|
this code work. Slight changes might make it compilable under Delphi 1.0 though
|
|
I strongly doubt it. Delphi 1.0 doesn't have the Double type or a Math.pas unit,
|
|
as far as I can remember. This unit is,of course, free.
|
|
This adaption, Copyright © 1997 by Peter Thörnqvist
|
|
|
|
NOTES:
|
|
*. Z denotes a complex number, Z.Re is the real part and Z.Im is the imaginary part.
|
|
*. all functions use a common naming scheme:
|
|
a. as far as possible all functions start off with a name equal to the standard
|
|
library functions, like LogXX, ExpXX, SqrtXX...
|
|
b. the action taken (and the order) is denoted by the letters Z,R,I:
|
|
PowZR means raise Z to the power of R (I.e. Z^R),
|
|
PowRZ means raise R to the power of Z (I.e: R^Z), etc
|
|
|
|
*. There are no functions to manipulate imaginary numbers directly.
|
|
That's because you can't have imag numbers "floating around":
|
|
The computer can't differentiate between R and I variables
|
|
and would treat them both as reals, generating errors. Instead, you must
|
|
"hide" the imaginary number in a TComplex variable where Z.Re := 0
|
|
and then use the functions in this library.
|
|
*. The functions PowZR1 and PowZR2 does the same except for the fact that
|
|
PowZR1 truncates the real part to an Integer
|
|
*. All the ArcXXX functions will generate an exception if |z| > 1
|
|
*. Trig and hyperbolic functions calculations are done in radians
|
|
|
|
}
|
|
|
|
interface
|
|
|
|
uses
|
|
Math, SysUtils;
|
|
|
|
type
|
|
TComplex = record
|
|
Re: Double;
|
|
Im: Double;
|
|
end;
|
|
|
|
{ Conversions & Extractions }
|
|
|
|
{ ToComplex convert R and I to complex }
|
|
function ToComplex(R, I: Double): TComplex;
|
|
{ Real return real part of Z }
|
|
function Real(Z: TComplex): Double;
|
|
{ Imag return imag part of Z }
|
|
function Imag(Z: TComplex): Double;
|
|
|
|
{ Utility functions }
|
|
|
|
{ IsValidComplexString returns True if S is a valid complex string }
|
|
function IsValidComplexString(S: string): Boolean;
|
|
{ IsValidComplexNumber returns True if Z is a valid complex number }
|
|
function IsValidComplexNumber(Z: TComplex): Boolean;
|
|
{ BoolToString returns Boolean as string }
|
|
function BoolToString(B: Boolean): string;
|
|
{ ComplexToString convert Complex to a string }
|
|
function ComplexToString(Z: TComplex): string;
|
|
{ StringToComplex convert string to a TComplex }
|
|
function StringToComplex(S: string): TComplex;
|
|
|
|
{ Standard operators (+,-,*,/) for complex numbers }
|
|
|
|
{ AddZZ add two complex numbers }
|
|
function AddZZ(const Z, Z2: TComplex): TComplex;
|
|
{ AddZR add a complex and a real }
|
|
function AddZR(const Z: TComplex; R: Double): TComplex;
|
|
{ SubZZ subtract two complex numbers }
|
|
function SubZZ(Z, Z2: TComplex): TComplex;
|
|
{ SubZR subtract Z.Re from R (Z - R) }
|
|
function SubZR(Z: TComplex; R: Double): TComplex;
|
|
{ SubRZ subtract R from Z.Re (R - Z) }
|
|
function SubRZ(R: Double; Z: TComplex): TComplex;
|
|
{ MulZZ multiply two complex numbers }
|
|
function MulZZ(Z, Z2: TComplex): TComplex;
|
|
{ MulRZ multiply a real and a complex }
|
|
function MulRZ(R: Double; Z: TComplex): TComplex;
|
|
{ DivZR divide Z with R ( Z/R ) - let compiler handle divbyzero}
|
|
function DivZR(Z: TComplex; R: Double): TComplex;
|
|
{ DivRZ divide R with Z ( R/Z) - let compiler handle divbyzero}
|
|
function DivRZ(R: Double; Z: TComplex): TComplex;
|
|
{ DivZZ divide two complex numbers }
|
|
function DivZZ(Z, Z2: TComplex): TComplex;
|
|
|
|
{ Special functions }
|
|
|
|
{ AbsZ return absolute value of Z. ( sqrt(x*x + y*y)) }
|
|
function AbsZ(Z: TComplex): Double;
|
|
{ ModZ same as AbsZ }
|
|
function ModZ(Z: TComplex): Double;
|
|
{ ArgZ return the argument of Z in radians }
|
|
function ArgZ(Z: TComplex): Double;
|
|
{ ConjugateZ return conjugate of Z ( conjugate( x + iy ) := x - iy ) }
|
|
function ConjugateZ(Z: TComplex): TComplex;
|
|
{ NormZ return the square of the absolute value of Z }
|
|
function NormZ(Z: TComplex): Double;
|
|
{ NegZ return negated value of complex number }
|
|
function NegZ(Z: TComplex): TComplex;
|
|
{ EqualZZ test for equality }
|
|
function EqualZZ(Z, Z2: Tcomplex): Boolean;
|
|
|
|
{ Trig. and hyperbolic functions }
|
|
{ CosZ return the cosine of Z }
|
|
function CosZ(Z: TComplex): TComplex;
|
|
{ CoshZ return the hyperbolic cosine of Z }
|
|
function CoshZ(Z: TComplex): TComplex;
|
|
{ SinZ return the sine of Z }
|
|
function SinZ(Z: TComplex): TComplex;
|
|
{ ArcSinZ return the Arcsine of Z }
|
|
function ArcSinZ(Z: TComplex): TComplex;
|
|
{ SinhZ return the hyperbolic sine of Z }
|
|
function SinhZ(Z: TComplex): TComplex;
|
|
{ ArcSinhZ return the hyperbolic arcsine of Z }
|
|
function ArcSinhZ(Z: TComplex): TComplex;
|
|
{ TanZ return the tan of Z }
|
|
function TanZ(Z: TComplex): TComplex;
|
|
{ ArcTanZ return the arctan of Z }
|
|
function ArcTanZ(Z: TComplex): TComplex;
|
|
{ ArcCosZ return the arccos of Z }
|
|
function ArcCosZ(Z: TComplex): TComplex;
|
|
{ TanhZ retun the hyperbolic tan of Z }
|
|
function TanhZ(Z: TComplex): TComplex;
|
|
{ ArcTanhZ return the hyperbolic arctan of Z }
|
|
function ArcTanhZ(Z: TComplex): TComplex;
|
|
|
|
{ Math. functions }
|
|
|
|
{ ExpZ returns e raised to Z (e^Z) }
|
|
function ExpZ(Z: TComplex): TComplex;
|
|
{ LnZ returns the natural log of Z }
|
|
function LnZ(Z: TComplex): TComplex;
|
|
{ Log10Z retuns the base 10 log of Z }
|
|
function Log10Z(Z: TComplex): TComplex;
|
|
{ PolarZ return the complex number built from rect.coords. Range and Theta }
|
|
function PolarZ(Range, Angle: Double): TComplex;
|
|
{ RectangularZ return the rectangular coordinates of Z }
|
|
procedure RectangularZ(Z: TComplex; var Range, Angle: Double);
|
|
{ SqrtZ return the Square root of Z }
|
|
function SqrtZ(Z: TComplex): TComplex;
|
|
{ PowZZ return Z^Z2 }
|
|
function PowZZ(Z, Z2: TComplex): TComplex;
|
|
{ PowZR1 return Z^R (R is int) }
|
|
function PowZR1(Z: TComplex; R: Integer): TComplex;
|
|
{ PowZR2 return Z^R (R is real) }
|
|
function PowZR2(Z: TComplex; R: Double): TComplex;
|
|
{ PowRZ return R^Z }
|
|
function PowRZ(R: Double; Z: TComplex): TComplex;
|
|
|
|
implementation
|
|
|
|
{ Conversion }
|
|
|
|
{ ToComplex Convert R and I to complex }
|
|
|
|
function ToComplex(R, I: Double): TComplex;
|
|
begin
|
|
Result.Re := R;
|
|
Result.Im := I;
|
|
end;
|
|
|
|
{ IsValidComplexString True if S is a valid complex string }
|
|
|
|
function IsValidComplexString(S: string): Boolean;
|
|
begin
|
|
Result := True;
|
|
try
|
|
StringToComplex(S);
|
|
except on EConvertError do
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{ IsValidComplexNumber True if Z is a valid complex number }
|
|
|
|
function IsValidComplexNumber(Z: TComplex): Boolean;
|
|
begin
|
|
Result := True;
|
|
try
|
|
ComplexToString(Z);
|
|
except on EConvertError do
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
{ BoolToString return Boolean as string }
|
|
|
|
function BoolToString(B: Boolean): string;
|
|
const
|
|
Bools: array [Boolean] of PChar = ('False', 'True');
|
|
begin
|
|
Result := Bools[B];
|
|
end;
|
|
|
|
{ ComplexToString convert Z to a string
|
|
Will raise EConvertError on failure. Call IsValidComplexNumber
|
|
first to avoid this situation.}
|
|
|
|
function ComplexToString(Z: TComplex): string;
|
|
begin
|
|
Result := Format('(%s ,%si)', [FloatToStr(Z.Re), FloatToStr(Z.Im)]);
|
|
end;
|
|
|
|
{ convert string S to a TComplex }
|
|
{
|
|
Accepts any input that StrToFloat does, with these additions:
|
|
1. Im and Re part must be separated by any nonnumerical character
|
|
2. If the Re part has a sign, it cannot be separated from the number
|
|
(I.e - 3.4 is invalid; -3.4 is OK). The Im part sign can be separate
|
|
from the numerical body, although it isn't recommended.
|
|
|
|
Examples of valid input:
|
|
+7.8,-0.56E-12
|
|
+7.8 - 0.56E-12
|
|
(+7.8,-0.56E-12)
|
|
( +7.8 , - 0.56E-12 )
|
|
+7.8 + . 5 6 E - 1 2
|
|
etc...
|
|
|
|
Examples of invalid input:
|
|
+7.8-0.56E-12 ( numbers can't stick together)
|
|
+ 7.8,-0.56E-12 ( first '+' must be connected with the number )
|
|
+(-7.8) -0.56E-12 ( multiple signs or paranthesis in number not supported.
|
|
etc...
|
|
|
|
4. The global variable DecimalSeparator (the dot in the examples) controls
|
|
what character is actually used for separating the integral and fractional
|
|
parts of a number. This setting is controlled by the current settings in
|
|
the registry. If you are uncertain what separator your country use,
|
|
check Control Panel | Country | Numbers.
|
|
|
|
5. StringToComplex will raise an EConvertError (unhandled) if input isn't valid.
|
|
To avoid this, call IsValidComplexString first.
|
|
}
|
|
|
|
function StringToComplex(S: string): TComplex;
|
|
const
|
|
ValidNum = ['+', '-', '0'..'9', 'E', 'e'];
|
|
var
|
|
I: Integer;
|
|
T: string;
|
|
begin
|
|
T := '';
|
|
I := 1;
|
|
if S = '' then
|
|
Exit;
|
|
|
|
while I <= Length(S) do
|
|
begin
|
|
if (S[I] in ValidNum) or (S[I] = DecimalSeparator) then
|
|
T := T + S[I]
|
|
else
|
|
if Length(T) > 0 then
|
|
Break;
|
|
Inc(I);
|
|
end;
|
|
|
|
Result.Re := StrToFloat(T);
|
|
T := '';
|
|
|
|
while I <= Length(S) do
|
|
begin
|
|
if (S[I] in ValidNum) or (S[I] = DecimalSeparator) then
|
|
T := T + S[I];
|
|
Inc(I);
|
|
end;
|
|
|
|
Result.Im := StrToFloat(T);
|
|
end;
|
|
|
|
{ Real return real part of Z }
|
|
|
|
function Real(Z: TComplex): Double;
|
|
begin
|
|
Result := Z.Re;
|
|
end;
|
|
|
|
{ Imag return imag part of Z }
|
|
|
|
function Imag(Z: TComplex): Double;
|
|
begin
|
|
Result := Z.Im;
|
|
end;
|
|
|
|
{ Standard Operators }
|
|
|
|
{ AddZZ add two complex numbers: (x + yi) + (v + wi) = (x + v) + I(y + w)}
|
|
|
|
function AddZZ(const Z, Z2: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Z.Re + Z2.Re, Z.Im + Z2.Im);
|
|
end;
|
|
|
|
{ AddZR add a complex and a real: r + (x + yi) = (r + x) + yi}
|
|
|
|
function AddZR(const Z: TComplex; R: Double): TComplex;
|
|
begin
|
|
Result := AddZZ(Z, ToComplex(R, 0));
|
|
end;
|
|
|
|
{ SubZZ subtract two complex numbers: (x + yi) - (v + wi) = (x - v) + I(y - w) }
|
|
|
|
function SubZZ(Z, Z2: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Z.Re - Z2.Re, Z.Im - Z2.Im);
|
|
end;
|
|
|
|
{ SubZR subtract Z.Re from R: (x +yi) - r = (x-r) + yi }
|
|
|
|
function SubZR(Z: TComplex; R: Double): TComplex;
|
|
begin
|
|
Result := SubZZ(Z, ToComplex(R, 0));
|
|
end;
|
|
|
|
{ SubRZ subtract R from Z.Re: r - (x + yi) = (r-x) - yi }
|
|
|
|
function SubRZ(R: Double; Z: TComplex): TComplex;
|
|
begin
|
|
Result := SubZZ(ToComplex(R, 0), Z);
|
|
end;
|
|
|
|
{ MulZZ multiply two complex numbers: (x + yi) * ( v + wi) = (xv - yw) + I(xw +yv)}
|
|
|
|
function MulZZ(Z, Z2: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Z.Re * Z2.Re - Z.Im * Z2.Im, Z.Re * Z2.Im + Z.Im * Z2.Re);
|
|
end;
|
|
|
|
{ MulRZ multiply a real and a complex: r(x+yi) = rx + ryi }
|
|
|
|
function MulRZ(R: Double; Z: TComplex): TComplex;
|
|
begin
|
|
Result := MulZZ(ToComplex(R, 0), Z);
|
|
end;
|
|
|
|
{ DivZR divide Z with R ( Z/R ) - let compiler handle divbyzero: (x+yi) / r := x/r + yi/r }
|
|
|
|
function DivZR(Z: TComplex; R: Double): TComplex;
|
|
begin
|
|
Result := ToComplex(Z.Re / R, Z.Im / R);
|
|
end;
|
|
|
|
{ DivRZ divide R with Z ( R/Z) - let compiler handle divbyzero: r/(x + yi) := r/x + r/yi}
|
|
|
|
function DivRZ(R: Double; Z: TComplex): TComplex;
|
|
begin
|
|
if (Z.Re = 0) and (Z.Im <> 0) then
|
|
Result := ToComplex(0, R / Z.Im)
|
|
else
|
|
if (Z.Im = 0) and (Z.Re <> 0) then
|
|
Result := ToComplex(R / Z.Re, 0)
|
|
else
|
|
Result := ToComplex(R / Z.Re, R / Z.Im);
|
|
end;
|
|
|
|
{ DivZZ divide Z with Z2 ( Z/Z2) - let compiler handle divbyzero }
|
|
|
|
function DivZZ(Z, Z2: TComplex): TComplex;
|
|
var
|
|
Zb, Z2b: TComplex;
|
|
begin
|
|
Zb := MulZZ(Z, ConjugateZ(Z2));
|
|
Z2b := MulZZ(Z2, ConjugateZ(Z2)); { this should be Re now (Im := 0) }
|
|
Result := DivZR(Zb, Real(Z2b));
|
|
end;
|
|
|
|
{ Misc. complex specific }
|
|
|
|
{ AbsZ return absolute value of Z. ( sqrt(x*x + y*y)) }
|
|
|
|
function AbsZ(Z: TComplex): Double;
|
|
var
|
|
x, y: Double;
|
|
begin
|
|
x := Abs(Z.Re);
|
|
y := Abs(Z.Im);
|
|
if x = 0 then
|
|
Result := y
|
|
else
|
|
if y = 0 then
|
|
Result := x
|
|
else
|
|
begin
|
|
if x > y then
|
|
Result := x * Sqrt(1 + Power(y / x, 2))
|
|
else
|
|
Result := y * Sqrt(1 + Power(x / y, 2));
|
|
end;
|
|
end;
|
|
|
|
{ ModZ is the same as AbsZ }
|
|
|
|
function ModZ(Z: TComplex): Double;
|
|
begin
|
|
Result := AbsZ(Z);
|
|
end;
|
|
|
|
{ ArgZ return the argument of Z in radians: z = x + yi -> arctan(y/x) }
|
|
|
|
function ArgZ(Z: TComplex): Double;
|
|
begin
|
|
Result := ArcTan2(Z.Im, Z.Re);
|
|
end;
|
|
|
|
{ ConjugateZ return conjugate of Z ((x + iy)~ = x - iy ) }
|
|
|
|
function ConjugateZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Z.Re, -Z.Im);
|
|
end;
|
|
|
|
{ NormZ return the square of the absolute value of Z: |x + yi|^2 }
|
|
|
|
function NormZ(Z: TComplex): Double;
|
|
begin
|
|
Result := Z.Re * Z.Re + Z.Im * Z.Im;
|
|
end;
|
|
|
|
{ NegZ return negated value of complex number: x + yi = -x - yi }
|
|
|
|
function NegZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(-Z.Re, -Z.Im);
|
|
end;
|
|
|
|
{ EqualZZ test for equality }
|
|
|
|
function EqualZZ(Z, Z2: Tcomplex): Boolean;
|
|
begin
|
|
Result := ((Z.Re = Z2.Re) and (Z.Im = Z2.Im));
|
|
end;
|
|
|
|
{ Trigonometric }
|
|
|
|
{ CosZ return the cosine of Z }
|
|
|
|
function CosZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Cos(Z.Re) * Cosh(Z.Im), -(Sin(Z.Re) * Sinh(Z.Im)));
|
|
end;
|
|
|
|
{ ArcCosZ return the arccosine of Z. Input value must be between -1..1 and -I..I }
|
|
|
|
function ArcCosZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(ArcCos(Z.Re) * ArcCosh(Z.Im), ArcSin(Z.Re) * ArcSinh(Z.Im));
|
|
end;
|
|
|
|
{ CoshZ return the hyperbolic cosine of Z }
|
|
|
|
function CoshZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Cosh(Z.Re) * Cos(Z.Im), Sinh(Z.Re) * Sin(Z.Im));
|
|
end;
|
|
|
|
{ SinZ return the sine of Z }
|
|
|
|
function SinZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Sin(Z.Re) * Cosh(Z.Im), Cos(Z.Re) * Sinh(Z.Im));
|
|
end;
|
|
|
|
{ ArcSinZ return the arcsine of Z. Input value must be between -1..1 and -I..I }
|
|
|
|
function ArcSinZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(ArcSin(Z.Re) * ArcCosh(Z.Im), ArcCos(Z.Re) * ArcSinh(Z.Im));
|
|
end;
|
|
|
|
{ SinhZ return the hyperbolic sine of Z }
|
|
|
|
function SinhZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Sinh(Z.Re) * Cos(Z.Im), Cosh(Z.Re) * Sin(Z.Im));
|
|
end;
|
|
|
|
{ ArcSinhZ return the hyperbolic arcsine of Z }
|
|
|
|
function ArcSinhZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(-Z.Im, Z.Re);
|
|
Result := ArcSinZ(Result);
|
|
Result := ToComplex(Result.Im, -Result.Re);
|
|
end;
|
|
|
|
{ TanZ return the tan of Z }
|
|
|
|
function TanZ(Z: TComplex): TComplex;
|
|
var
|
|
x, y, t: Double;
|
|
begin
|
|
x := 2 * Z.Re;
|
|
y := 2 * z.Im;
|
|
t := 1.0 / (Cos(x) + Cosh(y));
|
|
Result := ToComplex(t * Sin(x), t * Sinh(y));
|
|
end;
|
|
|
|
{ ArcTanZ return the arctan of Z. }
|
|
|
|
function ArcTanZ(Z: TComplex): TComplex;
|
|
var
|
|
x, y, t: Double;
|
|
begin
|
|
x := 2 * Z.Re;
|
|
y := 2 * z.Im;
|
|
t := 1.0 / (Cos(x) + Cosh(y));
|
|
Result := ToComplex(t * ArcSin(x), t * ArcSinh(y));
|
|
end;
|
|
|
|
{ TanhZ retun the hyperbolic tan of Z }
|
|
|
|
function TanhZ(Z: TComplex): TComplex;
|
|
var
|
|
x, y, t: Double;
|
|
begin
|
|
x := 2 * Z.Re;
|
|
y := 2 * z.Im;
|
|
t := 1.0 / (Cos(x) + Cosh(y));
|
|
Result := ToComplex(t * Sinh(x), t * Sin(y));
|
|
end;
|
|
|
|
{ ArcTanhZ return the hyperbolic arctan of Z. Input value must be between -1..1 and -I..I }
|
|
|
|
function ArcTanhZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(-Z.Im, Z.Re);
|
|
Result := ArcTanZ(Result);
|
|
Result := ToComplex(Result.Im, -Result.Re);
|
|
end;
|
|
|
|
{ Math Functions }
|
|
|
|
{ ExpZ returns e raised to Z: e^(x + yi) }
|
|
|
|
function ExpZ(Z: TComplex): TComplex;
|
|
var
|
|
x: Double;
|
|
begin
|
|
x := Exp(Z.Re);
|
|
Result := ToComplex(x * Cos(Z.Im), x * Sin(Z.Im));
|
|
end;
|
|
|
|
{ LnZ returns the natural log of Z: Ln(x + iy) }
|
|
|
|
function LnZ(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(Ln(AbsZ(Z)), ArgZ(Z));
|
|
end;
|
|
|
|
{ Log10Z returns the base 10 log of Z: log(x+yi) }
|
|
|
|
function Log10Z(Z: TComplex): TComplex;
|
|
begin
|
|
Result := ToComplex(0.2171472409516259 * Ln(NormZ(Z)), ArgZ(Z));
|
|
end;
|
|
|
|
{ PolarZ returns the complex number given by the rectangular coordinates Range and Angle:
|
|
z = r(cos(angle) + I sin(angle))
|
|
Range is the length of the straight line extending from 0,0i to the point x,yi
|
|
Angle is the angle in radians between the real axis and the point x,yi
|
|
}
|
|
|
|
function PolarZ(Range, Angle: Double): TComplex;
|
|
begin
|
|
Result := ToComplex(Range * Cos(Angle), Range * Sin(Angle));
|
|
end;
|
|
|
|
{ RectangularZ returns the rectangular coordinates Range and Angle of the complex number Z
|
|
(see explanation above) }
|
|
|
|
procedure RectangularZ(Z: TComplex; var Range, Angle: Double);
|
|
begin
|
|
Angle := ArgZ(Z);
|
|
Range := AbsZ(Z);
|
|
end;
|
|
|
|
{ SqrtZ return the Square root of Z: sqrt(x+yi) }
|
|
|
|
function SqrtZ(Z: TComplex): TComplex;
|
|
var
|
|
a, b: Double;
|
|
begin
|
|
if (Z.Re = 0) and (Z.Im = 0) then
|
|
Result := ToComplex(1, 0)
|
|
else
|
|
begin
|
|
a := Sqrt((Abs(Z.Re) + AbsZ(Z)) * 0.5);
|
|
if Z.Re >= 0 then
|
|
b := Z.Im / (a + a)
|
|
else
|
|
begin
|
|
if Z.Im < 0 then
|
|
b := -a
|
|
else
|
|
b := a;
|
|
a := Z.Im / (b + b);
|
|
end;
|
|
Result := ToComplex(a, b);
|
|
end;
|
|
end;
|
|
|
|
{ PowZZ return Z^Z2: (x+yi)^(v+wi) }
|
|
|
|
function PowZZ(Z, Z2: TComplex): TComplex;
|
|
var
|
|
LogF, Phase: TComplex;
|
|
begin
|
|
if (Z2.Re = 0) and (Z2.Im = 0) then
|
|
Result := ToComplex(1, 0)
|
|
else
|
|
if Z2.Im = 0 then
|
|
Result := PowZR2(Z, Z2.Re)
|
|
else
|
|
begin
|
|
LogF.Re := Ln(AbsZ(Z));
|
|
LogF.Im := ArcTan2(Z.Im, Z.Re);
|
|
Phase.Re := Exp(LogF.Re * Z2.Re - LogF.Im * Z2.Im);
|
|
Phase.Im := LogF.Re * Z2.Im + LogF.Im * Z2.Re;
|
|
Result := ToComplex(Phase.Re * Cos(Phase.Im), Phase.Re * Sin(Phase.Im));
|
|
end;
|
|
end;
|
|
|
|
{ PowZR1 return Z^R (R is int): (x+yi)^r }
|
|
|
|
function PowZR1(Z: TComplex; R: Integer): TComplex;
|
|
begin
|
|
Result := PowZZ(Z, ToComplex(R, 0));
|
|
end;
|
|
|
|
{ PowZR2 return Z^R (R is real): (x +yi)^r }
|
|
|
|
function PowZR2(Z: TComplex; R: Double): TComplex;
|
|
begin
|
|
Result := PowZZ(Z, ToComplex(R, 0));
|
|
end;
|
|
|
|
{ PowRZ return R^Z: r^(x + yi) }
|
|
|
|
function PowRZ(R: Double; Z: TComplex): TComplex;
|
|
begin
|
|
Result := PowZZ(ToComplex(R, 0), Z);
|
|
end;
|
|
|
|
end.
|
|
|