(* *********************************************** Модуль работы с комплексными числами. Вадим Исаев, 2020 Module for complex numbers. Vadim Isaev, 2020 *************************************************** *) MODULE CMath; IMPORT Math, Out; TYPE complex* = POINTER TO RECORD re*: REAL; im*: REAL END; VAR result: complex; i* : complex; _0*: complex; (* Инициализация комплексного числа. Init complex number. *) PROCEDURE CInit* (re : REAL; im: REAL): complex; VAR temp: complex; BEGIN NEW(temp); temp.re:=re; temp.im:=im; RETURN temp END CInit; (* Четыре основных арифметических операций. Four base operations +, -, * , / *) (* Сложение addition : z := z1 + z2 *) PROCEDURE CAdd* (z1, z2: complex): complex; BEGIN result.re := z1.re + z2.re; result.im := z1.im + z2.im; RETURN result END CAdd; (* Сложение с REAL. addition : z := z1 + r1 *) PROCEDURE CAdd_r* (z1: complex; r1: REAL): complex; BEGIN result.re := z1.re + r1; result.im := z1.im; RETURN result END CAdd_r; (* Сложение с INTEGER. addition : z := z1 + i1 *) PROCEDURE CAdd_i* (z1: complex; i1: INTEGER): complex; BEGIN result.re := z1.re + FLT(i1); result.im := z1.im; RETURN result END CAdd_i; (* Смена знака. substraction : z := - z1 *) PROCEDURE CNeg (z1 : complex): complex; BEGIN result.re := -z1.re; result.im := -z1.im; RETURN result END CNeg; (* Вычитание. substraction : z := z1 - z2 *) PROCEDURE CSub* (z1, z2 : complex): complex; BEGIN result.re := z1.re - z2.re; result.im := z1.im - z2.im; RETURN result END CSub; (* Вычитание REAL. substraction : z := z1 - r1 *) PROCEDURE CSub_r1* (z1 : complex; r1 : REAL): complex; BEGIN result.re := z1.re - r1; result.im := z1.im; RETURN result END CSub_r1; (* Вычитание из REAL. substraction : z := r1 - z1 *) PROCEDURE CSub_r2* (r1 : REAL; z1 : complex): complex; BEGIN result.re := r1 - z1.re; result.im := - z1.im; RETURN result END CSub_r2; (* Вычитание INTEGER. substraction : z := z1 - i1 *) PROCEDURE CSub_i* (z1 : complex; i1 : INTEGER): complex; BEGIN result.re := z1.re - FLT(i1); result.im := z1.im; RETURN result END CSub_i; (* Умножение. multiplication : z := z1 * z2 *) PROCEDURE CMul (z1, z2 : complex): complex; BEGIN result.re := (z1.re * z2.re) - (z1.im * z2.im); result.im := (z1.re * z2.im) + (z1.im * z2.re); RETURN result END CMul; (* Умножение с REAL. multiplication : z := z1 * r1 *) PROCEDURE CMul_r (z1 : complex; r1 : REAL): complex; BEGIN result.re := z1.re * r1; result.im := z1.im * r1; RETURN result END CMul_r; (* Умножение с INTEGER. multiplication : z := z1 * i1 *) PROCEDURE CMul_i (z1 : complex; i1 : INTEGER): complex; BEGIN result.re := z1.re * FLT(i1); result.im := z1.im * FLT(i1); RETURN result END CMul_i; (* Деление. division : z := znum / zden *) PROCEDURE CDiv (z1, z2 : complex): complex; (* The following algorithm is used to properly handle denominator overflow: | a + b(d/c) c - a(d/c) | ---------- + ---------- I if |d| < |c| a + b I | c + d(d/c) a + d(d/c) ------- = | c + d I | b + a(c/d) -a+ b(c/d) | ---------- + ---------- I if |d| >= |c| | d + c(c/d) d + c(c/d) *) VAR tmp, denom : REAL; BEGIN IF ( ABS(z2.re) > ABS(z2.im) ) THEN tmp := z2.im / z2.re; denom := z2.re + z2.im * tmp; result.re := (z1.re + z1.im * tmp) / denom; result.im := (z1.im - z1.re * tmp) / denom; ELSE tmp := z2.re / z2.im; denom := z2.im + z2.re * tmp; result.re := (z1.im + z1.re * tmp) / denom; result.im := (-z1.re + z1.im * tmp) / denom; END; RETURN result END CDiv; (* Деление на REAL. division : z := znum / r1 *) PROCEDURE CDiv_r* (z1 : complex; r1 : REAL): complex; BEGIN result.re := z1.re / r1; result.im := z1.im / r1; RETURN result END CDiv_r; (* Деление на INTEGER. division : z := znum / i1 *) PROCEDURE CDiv_i* (z1 : complex; i1 : INTEGER): complex; BEGIN result.re := z1.re / FLT(i1); result.im := z1.im / FLT(i1); RETURN result END CDiv_i; (* fonctions elementaires *) (* Вывод на экран. out complex number *) PROCEDURE CPrint* (z: complex; width: INTEGER); BEGIN Out.Real(z.re, width); IF z.im>=0.0 THEN Out.String("+"); END; Out.Real(z.im, width); Out.String("i"); END CPrint; PROCEDURE CPrintLn* (z: complex; width: INTEGER); BEGIN CPrint(z, width); Out.Ln; END CPrintLn; (* Вывод на экран с фиксированным кол-вом знаков после запятой (p) *) PROCEDURE CPrintFix* (z: complex; width, p: INTEGER); BEGIN Out.FixReal(z.re, width, p); IF z.im>=0.0 THEN Out.String("+"); END; Out.FixReal(z.im, width, p); Out.String("i"); END CPrintFix; PROCEDURE CPrintFixLn* (z: complex; width, p: INTEGER); BEGIN CPrintFix(z, width, p); Out.Ln; END CPrintFixLn; (* Модуль числа. module : r = |z| *) PROCEDURE CMod* (z1 : complex): REAL; BEGIN RETURN Math.sqrt((z1.re * z1.re) + (z1.im * z1.im)) END CMod; (* Квадрат числа. square : r := z*z *) PROCEDURE CSqr* (z1: complex): complex; BEGIN result.re := z1.re * z1.re - z1.im * z1.im; result.im := 2.0 * z1.re * z1.im; RETURN result END CSqr; (* Квадратный корень числа. square root : r := sqrt(z) *) PROCEDURE CSqrt* (z1: complex): complex; VAR root, q: REAL; BEGIN IF (z1.re#0.0) OR (z1.im#0.0) THEN root := Math.sqrt(0.5 * (ABS(z1.re) + CMod(z1))); q := z1.im / (2.0 * root); IF z1.re >= 0.0 THEN result.re := root; result.im := q; ELSE IF z1.im < 0.0 THEN result.re := - q; result.im := - root ELSE result.re := q; result.im := root END END ELSE result := z1; END; RETURN result END CSqrt; (* Экспонента. exponantial : r := exp(z) *) (* exp(x + iy) = exp(x).exp(iy) = exp(x).[cos(y) + i sin(y)] *) PROCEDURE CExp* (z: complex): complex; VAR expz : REAL; BEGIN expz := Math.exp(z.re); result.re := expz * Math.cos(z.im); result.im := expz * Math.sin(z.im); RETURN result END CExp; (* Натуральный логарифм. natural logarithm : r := ln(z) *) (* ln( p exp(i0)) = ln(p) + i0 + 2kpi *) PROCEDURE CLn* (z: complex): complex; BEGIN result.re := Math.ln(CMod(z)); result.im := Math.arctan2(z.im, z.re); RETURN result END CLn; (* Число в степени. exp : z := z1^z2 *) PROCEDURE CPower* (z1, z2 : complex): complex; VAR a: complex; BEGIN a:=CLn(z1); a:=CMul(z2, a); result:=CExp(a); RETURN result END CPower; (* Число в степени REAL. multiplication : z := z1^r *) PROCEDURE CPower_r* (z1: complex; r: REAL): complex; VAR a: complex; BEGIN a:=CLn(z1); a:=CMul_r(a, r); result:=CExp(a); RETURN result END CPower_r; (* Обратное число. inverse : r := 1 / z *) PROCEDURE CInv* (z: complex): complex; VAR denom : REAL; BEGIN denom := (z.re * z.re) + (z.im * z.im); (* generates a fpu exception if denom=0 as for reals *) result.re:=z.re/denom; result.im:=-z.im/denom; RETURN result END CInv; (* direct trigonometric functions *) (* Косинус. complex cosinus *) (* cos(x+iy) = cos(x).cos(iy) - sin(x).sin(iy) *) (* cos(ix) = cosh(x) et sin(ix) = i.sinh(x) *) PROCEDURE CCos* (z: complex): complex; BEGIN result.re := Math.cos(z.re) * Math.cosh(z.im); result.im := - Math.sin(z.re) * Math.sinh(z.im); RETURN result END CCos; (* Синус. sinus complex *) (* sin(x+iy) = sin(x).cos(iy) + cos(x).sin(iy) *) (* cos(ix) = cosh(x) et sin(ix) = i.sinh(x) *) PROCEDURE CSin (z: complex): complex; BEGIN result.re := Math.sin(z.re) * Math.cosh(z.im); result.im := Math.cos(z.re) * Math.sinh(z.im); RETURN result END CSin; (* Тангенс. tangente *) PROCEDURE CTg* (z: complex): complex; VAR temp1, temp2: complex; BEGIN temp1:=CSin(z); temp2:=CCos(z); result:=CDiv(temp1, temp2); RETURN result END CTg; (* inverse complex hyperbolic functions *) (* Гиперболический арккосинус. hyberbolic arg cosinus *) (* _________ *) (* argch(z) = -/+ ln(z + i.V 1 - z.z) *) PROCEDURE CArcCosh* (z : complex): complex; BEGIN result:=CNeg(CLn(CAdd(z, CMul(i, CSqrt(CSub_r2(1.0, CMul(z, z))))))); RETURN result END CArcCosh; (* Гиперболический арксинус. hyperbolic arc sinus *) (* ________ *) (* argsh(z) = ln(z + V 1 + z.z) *) PROCEDURE CArcSinh* (z : complex): complex; BEGIN result:=CLn(CAdd(z, CSqrt(CAdd_r(CMul(z, z), 1.0)))); RETURN result END CArcSinh; (* Гиперболический арктангенс. hyperbolic arc tangent *) (* argth(z) = 1/2 ln((z + 1) / (1 - z)) *) PROCEDURE CArcTgh (z : complex): complex; BEGIN result:=CDiv_r(CLn(CDiv(CAdd_r(z, 1.0), CSub_r2(1.0, z))), 2.0); RETURN result END CArcTgh; (* trigonometriques inverses *) (* Арккосинус. arc cosinus complex *) (* arccos(z) = -i.argch(z) *) PROCEDURE CArcCos* (z: complex): complex; BEGIN result := CNeg(CMul(i, CArcCosh(z))); RETURN result END CArcCos; (* Арксинус. arc sinus complex *) (* arcsin(z) = -i.argsh(i.z) *) PROCEDURE CArcSin* (z : complex): complex; BEGIN result := CNeg(CMul(i, CArcSinh(z))); RETURN result END CArcSin; (* Арктангенс. arc tangente complex *) (* arctg(z) = -i.argth(i.z) *) PROCEDURE CArcTg* (z : complex): complex; BEGIN result := CNeg(CMul(i, CArcTgh(CMul(i, z)))); RETURN result END CArcTg; BEGIN result:=CInit(0.0, 0.0); i :=CInit(0.0, 1.0); _0:=CInit(0.0, 0.0); END CMath.