GENERIC MODULEComplexTrans (R, RT, C);
Arithmetic for Modula-3, see doc for detailsAbstract: Transcendental functions of complex numbers.
IMPORT Arithmetic AS Arith; IMPORT FloatMode; <* UNUSED *> CONST Module = "ComplexTrans."; PROCEDUREThis function would definitely benefit of an implementation of SinCosArg (READONLY x: T; ): R.T = BEGIN RETURN RT.ArcTan2(x.im, x.re); END Arg; PROCEDUREPowR (READONLY x: T; y: R.T; ): T = VAR arg := Arg(x); abs := Abs(x); BEGIN RETURN C.Scale(Exp(T{R.Zero, R.Mul(arg, y)}), RT.Pow(abs, y)); END PowR; PROCEDUREPow (x, y: T; ): T = VAR z := Ln(x); BEGIN z := C.Mul(y, z); z := Exp(z); RETURN z; END Pow;
PROCEDUREThis function would definitely benefit of an implementation of SinCosExp (READONLY x: T; ): T = BEGIN RETURN C.Scale(T{RT.Cos(x.im), RT.Sin(x.im)}, RT.Exp(x.re)); END Exp;
PROCEDURELemming's stuffExpI (x: R.T; ): T = BEGIN RETURN T{RT.Cos(x), RT.Sin(x)}; END ExpI; PROCEDURELn (READONLY x: T; ): T = VAR z: T; BEGIN (*z.re:= R.Div(RT.Ln(AbsSqr(x)),R.Two);*) z.re := RT.Ln(AbsSqr(x)) / R.Two; z.im := Arg(x); RETURN z; END Ln; PROCEDURECos (READONLY x: T; ): T RAISES {Arith.Error} = VAR z: T; BEGIN IF ABS(x.re) > FLOAT(18.0D0, R.T) OR ABS(x.im) > FLOAT(18.0D0, R.T) THEN RAISE Arith.Error(NEW(Arith.ErrorOutOfRange).init()); END; z.re := +RT.Cos(x.re) * RT.CosH(x.im); z.im := -RT.Sin(x.re) * RT.SinH(x.im); RETURN z; END Cos; PROCEDURESin (READONLY x: T; ): T RAISES {Arith.Error} = VAR z: T; BEGIN IF ABS(x.re) > FLOAT(18.0D0, R.T) OR ABS(x.im) > FLOAT(18.0D0, R.T) THEN RAISE Arith.Error(NEW(Arith.ErrorOutOfRange).init()); END; z.re := +RT.Sin(x.re) * RT.CosH(x.im); z.im := +RT.Cos(x.re) * RT.SinH(x.im); RETURN z; END Sin; PROCEDURETan (READONLY x: T; ): T RAISES {Arith.Error} = BEGIN RETURN C.Div(Sin(x), Cos(x)); END Tan; PROCEDURECosH (READONLY x: T; ): T RAISES {Arith.Error} = BEGIN RETURN Cos(T{re := -x.im, im := +x.re}); END CosH; PROCEDURESinH (READONLY x: T; ): T RAISES {Arith.Error} = VAR (*z.re = -i*i*z.im = z.im*) (*z.im = -i*z.re* = -z.re*) z := Sin(T{-x.im, x.re}); BEGIN RETURN T{z.im, -z.re}; END SinH; PROCEDURETanH (READONLY x: T; ): T RAISES {Arith.Error} = BEGIN RETURN C.Div(SinH(x), CosH(x)); END TanH; PROCEDURENorm1 (READONLY x: T; ): R.T = BEGIN RETURN ABS(x.re) + ABS(x.im); END Norm1; PROCEDURENormInf (READONLY x: T; ): R.T = BEGIN RETURN MAX(ABS(x.re), ABS(x.im)); END NormInf;
PROCEDUREArcSin (READONLY x: T; ): T = VAR ix := T{R.Neg(x.im), x.re}; y := SqRt(C.Add(C.Square(ix), C.One)); BEGIN (* arcsin x = -i ln (ix ± sqrt (1-x²)) *) (*ix := C.Mul(x,C.I);*) RETURN C.Neg(C.Mul(C.I, Ln(C.Add(ix, y)))); END ArcSin; PROCEDUREArcCos (READONLY x: T; ): T = VAR y := SqRt(C.Sub(C.Square(x), C.One)); BEGIN (* arccos x = -i ln (x ± sqrt (x²-1)) *) RETURN C.Neg(C.Mul(C.I, Ln(C.Add(x, y)))); END ArcCos; PROCEDUREArcTan (READONLY x: T; ): T RAISES {Arith.Error} = VAR y := C.Div(C.Sub(C.I, x), C.Add(C.I, x)); BEGIN (* arctan x := 1/2i ln ((i-x)/(i+x)) *) RETURN C.Mul(Ln(y), T{R.Zero, RT.Half}); END ArcTan; PROCEDUREAbs (READONLY x0: T; ): R.T = VAR x := C.Normalize(x0); y := RT.SqRt(AbsSqr(x.val)); <* FATAL FloatMode.Trap *> BEGIN (* a workaround to prevent NaNs and Zeros *) RETURN R.Scalb(y, x.exp); END Abs;
PROCEDURE Abs (READONLY x:T;) : R.T = BEGIN RETURN RT.SqRt(AbsSqr(x)); END Abs;
PROCEDUREAbsSqr (READONLY x: T; ): R.T = BEGIN (* RETURN C.Mul(x,C.Conj(x)); it's a real number, but the type is still T *) RETURN x.re * x.re + x.im * x.im; END AbsSqr; PROCEDURESqRt (READONLY x: T; ): T = VAR r := Abs(x); z: T; BEGIN z.re := R.Add(r, x.re); IF R.Compare(z.re, R.Zero) < 0 THEN (* mathematically impossible, can be caused by rounding *) z.re := R.Zero; ELSE z.re := RT.SqRt(R.Mul(z.re, RT.Half)); END; z.im := R.Sub(r, x.re); IF R.Compare(z.im, R.Zero) < 0 THEN (* mathematically impossible, can be caused by rounding *) z.im := R.Zero; ELSE z.im := RT.SqRt(R.Mul(z.im, RT.Half)); IF R.Compare(x.im, R.Zero) < 0 THEN (* instead of using the Sgn function *) z.im := R.Neg(z.im); END; END; (* Root is on the same side as the radicand with respect to the real axis. *) RETURN z; END SqRt; BEGIN END ComplexTrans.