Rev 8859 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
9893 | akron1 | 1 | (* *********************************************** |
2 | Модуль работы с комплексными числами. |
||
3 | Вадим Исаев, 2020 |
||
4 | Module for complex numbers. |
||
5 | Vadim Isaev, 2020 |
||
6 | *************************************************** *) |
||
7 | |||
8 | MODULE CMath; |
||
9 | |||
10 | IMPORT Math, Out; |
||
11 | |||
12 | TYPE |
||
13 | complex* = POINTER TO RECORD |
||
14 | re*: REAL; |
||
15 | im*: REAL |
||
16 | END; |
||
17 | |||
18 | VAR |
||
19 | result: complex; |
||
20 | |||
21 | i* : complex; |
||
22 | _0*: complex; |
||
23 | |||
24 | (* Инициализация комплексного числа. |
||
25 | Init complex number. *) |
||
26 | PROCEDURE CInit* (re : REAL; im: REAL): complex; |
||
27 | VAR |
||
28 | temp: complex; |
||
29 | BEGIN |
||
30 | NEW(temp); |
||
31 | temp.re:=re; |
||
32 | temp.im:=im; |
||
33 | |||
34 | RETURN temp |
||
35 | END CInit; |
||
36 | |||
37 | |||
38 | (* Четыре основных арифметических операций. |
||
39 | Four base operations +, -, * , / *) |
||
40 | |||
41 | (* Сложение |
||
42 | addition : z := z1 + z2 *) |
||
43 | PROCEDURE CAdd* (z1, z2: complex): complex; |
||
44 | BEGIN |
||
45 | result.re := z1.re + z2.re; |
||
46 | result.im := z1.im + z2.im; |
||
47 | |||
48 | RETURN result |
||
49 | END CAdd; |
||
50 | |||
51 | (* Сложение с REAL. |
||
52 | addition : z := z1 + r1 *) |
||
53 | PROCEDURE CAdd_r* (z1: complex; r1: REAL): complex; |
||
54 | BEGIN |
||
55 | result.re := z1.re + r1; |
||
56 | result.im := z1.im; |
||
57 | |||
58 | RETURN result |
||
59 | END CAdd_r; |
||
60 | |||
61 | (* Сложение с INTEGER. |
||
62 | addition : z := z1 + i1 *) |
||
63 | PROCEDURE CAdd_i* (z1: complex; i1: INTEGER): complex; |
||
64 | BEGIN |
||
65 | result.re := z1.re + FLT(i1); |
||
66 | result.im := z1.im; |
||
67 | |||
68 | RETURN result |
||
69 | END CAdd_i; |
||
70 | |||
71 | (* Смена знака. |
||
72 | substraction : z := - z1 *) |
||
73 | PROCEDURE CNeg (z1 : complex): complex; |
||
74 | BEGIN |
||
75 | result.re := -z1.re; |
||
76 | result.im := -z1.im; |
||
77 | |||
78 | RETURN result |
||
79 | END CNeg; |
||
80 | |||
81 | (* Вычитание. |
||
82 | substraction : z := z1 - z2 *) |
||
83 | PROCEDURE CSub* (z1, z2 : complex): complex; |
||
84 | BEGIN |
||
85 | result.re := z1.re - z2.re; |
||
86 | result.im := z1.im - z2.im; |
||
87 | |||
88 | RETURN result |
||
89 | END CSub; |
||
90 | |||
91 | (* Вычитание REAL. |
||
92 | substraction : z := z1 - r1 *) |
||
93 | PROCEDURE CSub_r1* (z1 : complex; r1 : REAL): complex; |
||
94 | BEGIN |
||
95 | result.re := z1.re - r1; |
||
96 | result.im := z1.im; |
||
97 | |||
98 | RETURN result |
||
99 | END CSub_r1; |
||
100 | |||
101 | (* Вычитание из REAL. |
||
102 | substraction : z := r1 - z1 *) |
||
103 | PROCEDURE CSub_r2* (r1 : REAL; z1 : complex): complex; |
||
104 | BEGIN |
||
105 | result.re := r1 - z1.re; |
||
106 | result.im := - z1.im; |
||
107 | |||
108 | RETURN result |
||
109 | END CSub_r2; |
||
110 | |||
111 | (* Вычитание INTEGER. |
||
112 | substraction : z := z1 - i1 *) |
||
113 | PROCEDURE CSub_i* (z1 : complex; i1 : INTEGER): complex; |
||
114 | BEGIN |
||
115 | result.re := z1.re - FLT(i1); |
||
116 | result.im := z1.im; |
||
117 | |||
118 | RETURN result |
||
119 | END CSub_i; |
||
120 | |||
121 | (* Умножение. |
||
122 | multiplication : z := z1 * z2 *) |
||
123 | PROCEDURE CMul (z1, z2 : complex): complex; |
||
124 | BEGIN |
||
125 | result.re := (z1.re * z2.re) - (z1.im * z2.im); |
||
126 | result.im := (z1.re * z2.im) + (z1.im * z2.re); |
||
127 | |||
128 | RETURN result |
||
129 | END CMul; |
||
130 | |||
131 | (* Умножение с REAL. |
||
132 | multiplication : z := z1 * r1 *) |
||
133 | PROCEDURE CMul_r (z1 : complex; r1 : REAL): complex; |
||
134 | BEGIN |
||
135 | result.re := z1.re * r1; |
||
136 | result.im := z1.im * r1; |
||
137 | |||
138 | RETURN result |
||
139 | END CMul_r; |
||
140 | |||
141 | (* Умножение с INTEGER. |
||
142 | multiplication : z := z1 * i1 *) |
||
143 | PROCEDURE CMul_i (z1 : complex; i1 : INTEGER): complex; |
||
144 | BEGIN |
||
145 | result.re := z1.re * FLT(i1); |
||
146 | result.im := z1.im * FLT(i1); |
||
147 | |||
148 | RETURN result |
||
149 | END CMul_i; |
||
150 | |||
151 | (* Деление. |
||
152 | division : z := znum / zden *) |
||
153 | PROCEDURE CDiv (z1, z2 : complex): complex; |
||
154 | (* The following algorithm is used to properly handle |
||
155 | denominator overflow: |
||
156 | |||
157 | | a + b(d/c) c - a(d/c) |
||
158 | | ---------- + ---------- I if |d| < |c| |
||
159 | a + b I | c + d(d/c) a + d(d/c) |
||
160 | ------- = | |
||
161 | c + d I | b + a(c/d) -a+ b(c/d) |
||
162 | | ---------- + ---------- I if |d| >= |c| |
||
163 | | d + c(c/d) d + c(c/d) |
||
164 | *) |
||
165 | VAR |
||
166 | tmp, denom : REAL; |
||
167 | BEGIN |
||
168 | IF ( ABS(z2.re) > ABS(z2.im) ) THEN |
||
169 | tmp := z2.im / z2.re; |
||
170 | denom := z2.re + z2.im * tmp; |
||
171 | result.re := (z1.re + z1.im * tmp) / denom; |
||
172 | result.im := (z1.im - z1.re * tmp) / denom; |
||
173 | ELSE |
||
174 | tmp := z2.re / z2.im; |
||
175 | denom := z2.im + z2.re * tmp; |
||
176 | result.re := (z1.im + z1.re * tmp) / denom; |
||
177 | result.im := (-z1.re + z1.im * tmp) / denom; |
||
178 | END; |
||
179 | |||
180 | RETURN result |
||
181 | END CDiv; |
||
182 | |||
183 | (* Деление на REAL. |
||
184 | division : z := znum / r1 *) |
||
185 | PROCEDURE CDiv_r* (z1 : complex; r1 : REAL): complex; |
||
186 | BEGIN |
||
187 | result.re := z1.re / r1; |
||
188 | result.im := z1.im / r1; |
||
189 | |||
190 | RETURN result |
||
191 | END CDiv_r; |
||
192 | |||
193 | (* Деление на INTEGER. |
||
194 | division : z := znum / i1 *) |
||
195 | PROCEDURE CDiv_i* (z1 : complex; i1 : INTEGER): complex; |
||
196 | BEGIN |
||
197 | result.re := z1.re / FLT(i1); |
||
198 | result.im := z1.im / FLT(i1); |
||
199 | |||
200 | RETURN result |
||
201 | END CDiv_i; |
||
202 | |||
203 | (* fonctions elementaires *) |
||
204 | |||
205 | (* Вывод на экран. |
||
206 | out complex number *) |
||
207 | PROCEDURE CPrint* (z: complex; width: INTEGER); |
||
208 | BEGIN |
||
209 | Out.Real(z.re, width); |
||
210 | IF z.im>=0.0 THEN |
||
211 | Out.String("+"); |
||
212 | END; |
||
213 | Out.Real(z.im, width); |
||
214 | Out.String("i"); |
||
215 | END CPrint; |
||
216 | |||
217 | PROCEDURE CPrintLn* (z: complex; width: INTEGER); |
||
218 | BEGIN |
||
219 | CPrint(z, width); |
||
220 | Out.Ln; |
||
221 | END CPrintLn; |
||
222 | |||
223 | (* Вывод на экран с фиксированным кол-вом знаков |
||
224 | после запятой (p) *) |
||
225 | PROCEDURE CPrintFix* (z: complex; width, p: INTEGER); |
||
226 | BEGIN |
||
227 | Out.FixReal(z.re, width, p); |
||
228 | IF z.im>=0.0 THEN |
||
229 | Out.String("+"); |
||
230 | END; |
||
231 | Out.FixReal(z.im, width, p); |
||
232 | Out.String("i"); |
||
233 | END CPrintFix; |
||
234 | |||
235 | PROCEDURE CPrintFixLn* (z: complex; width, p: INTEGER); |
||
236 | BEGIN |
||
237 | CPrintFix(z, width, p); |
||
238 | Out.Ln; |
||
239 | END CPrintFixLn; |
||
240 | |||
241 | (* Модуль числа. |
||
242 | module : r = |z| *) |
||
243 | PROCEDURE CMod* (z1 : complex): REAL; |
||
244 | BEGIN |
||
245 | RETURN Math.sqrt((z1.re * z1.re) + (z1.im * z1.im)) |
||
246 | END CMod; |
||
247 | |||
248 | (* Квадрат числа. |
||
249 | square : r := z*z *) |
||
250 | PROCEDURE CSqr* (z1: complex): complex; |
||
251 | BEGIN |
||
252 | result.re := z1.re * z1.re - z1.im * z1.im; |
||
253 | result.im := 2.0 * z1.re * z1.im; |
||
254 | |||
255 | RETURN result |
||
256 | END CSqr; |
||
257 | |||
258 | (* Квадратный корень числа. |
||
259 | square root : r := sqrt(z) *) |
||
260 | PROCEDURE CSqrt* (z1: complex): complex; |
||
261 | VAR |
||
262 | root, q: REAL; |
||
263 | BEGIN |
||
264 | IF (z1.re#0.0) OR (z1.im#0.0) THEN |
||
265 | root := Math.sqrt(0.5 * (ABS(z1.re) + CMod(z1))); |
||
266 | q := z1.im / (2.0 * root); |
||
267 | IF z1.re >= 0.0 THEN |
||
268 | result.re := root; |
||
269 | result.im := q; |
||
270 | ELSE |
||
271 | IF z1.im < 0.0 THEN |
||
272 | result.re := - q; |
||
273 | result.im := - root |
||
274 | ELSE |
||
275 | result.re := q; |
||
276 | result.im := root |
||
277 | END |
||
278 | END |
||
279 | ELSE |
||
280 | result := z1; |
||
281 | END; |
||
282 | |||
283 | RETURN result |
||
284 | END CSqrt; |
||
285 | |||
286 | (* Экспонента. |
||
287 | exponantial : r := exp(z) *) |
||
288 | (* exp(x + iy) = exp(x).exp(iy) = exp(x).[cos(y) + i sin(y)] *) |
||
289 | PROCEDURE CExp* (z: complex): complex; |
||
290 | VAR |
||
291 | expz : REAL; |
||
292 | BEGIN |
||
293 | expz := Math.exp(z.re); |
||
294 | result.re := expz * Math.cos(z.im); |
||
295 | result.im := expz * Math.sin(z.im); |
||
296 | |||
297 | RETURN result |
||
298 | END CExp; |
||
299 | |||
300 | (* Натуральный логарифм. |
||
301 | natural logarithm : r := ln(z) *) |
||
302 | (* ln( p exp(i0)) = ln(p) + i0 + 2kpi *) |
||
303 | PROCEDURE CLn* (z: complex): complex; |
||
304 | BEGIN |
||
305 | result.re := Math.ln(CMod(z)); |
||
306 | result.im := Math.arctan2(z.im, z.re); |
||
307 | |||
308 | RETURN result |
||
309 | END CLn; |
||
310 | |||
311 | (* Число в степени. |
||
312 | exp : z := z1^z2 *) |
||
313 | PROCEDURE CPower* (z1, z2 : complex): complex; |
||
314 | VAR |
||
315 | a: complex; |
||
316 | BEGIN |
||
317 | a:=CLn(z1); |
||
318 | a:=CMul(z2, a); |
||
319 | result:=CExp(a); |
||
320 | |||
321 | RETURN result |
||
322 | END CPower; |
||
323 | |||
324 | (* Число в степени REAL. |
||
325 | multiplication : z := z1^r *) |
||
326 | PROCEDURE CPower_r* (z1: complex; r: REAL): complex; |
||
327 | VAR |
||
328 | a: complex; |
||
329 | BEGIN |
||
330 | a:=CLn(z1); |
||
331 | a:=CMul_r(a, r); |
||
332 | result:=CExp(a); |
||
333 | |||
334 | RETURN result |
||
335 | END CPower_r; |
||
336 | |||
337 | (* Обратное число. |
||
338 | inverse : r := 1 / z *) |
||
339 | PROCEDURE CInv* (z: complex): complex; |
||
340 | VAR |
||
341 | denom : REAL; |
||
342 | BEGIN |
||
343 | denom := (z.re * z.re) + (z.im * z.im); |
||
344 | (* generates a fpu exception if denom=0 as for reals *) |
||
345 | result.re:=z.re/denom; |
||
346 | result.im:=-z.im/denom; |
||
347 | |||
348 | RETURN result |
||
349 | END CInv; |
||
350 | |||
351 | (* direct trigonometric functions *) |
||
352 | |||
353 | (* Косинус. |
||
354 | complex cosinus *) |
||
355 | (* cos(x+iy) = cos(x).cos(iy) - sin(x).sin(iy) *) |
||
356 | (* cos(ix) = cosh(x) et sin(ix) = i.sinh(x) *) |
||
357 | PROCEDURE CCos* (z: complex): complex; |
||
358 | BEGIN |
||
359 | result.re := Math.cos(z.re) * Math.cosh(z.im); |
||
360 | result.im := - Math.sin(z.re) * Math.sinh(z.im); |
||
361 | |||
362 | RETURN result |
||
363 | END CCos; |
||
364 | |||
365 | (* Синус. |
||
366 | sinus complex *) |
||
367 | (* sin(x+iy) = sin(x).cos(iy) + cos(x).sin(iy) *) |
||
368 | (* cos(ix) = cosh(x) et sin(ix) = i.sinh(x) *) |
||
369 | PROCEDURE CSin (z: complex): complex; |
||
370 | BEGIN |
||
371 | result.re := Math.sin(z.re) * Math.cosh(z.im); |
||
372 | result.im := Math.cos(z.re) * Math.sinh(z.im); |
||
373 | |||
374 | RETURN result |
||
375 | END CSin; |
||
376 | |||
377 | (* Тангенс. |
||
378 | tangente *) |
||
379 | PROCEDURE CTg* (z: complex): complex; |
||
380 | VAR |
||
381 | temp1, temp2: complex; |
||
382 | BEGIN |
||
383 | temp1:=CSin(z); |
||
384 | temp2:=CCos(z); |
||
385 | result:=CDiv(temp1, temp2); |
||
386 | |||
387 | RETURN result |
||
388 | END CTg; |
||
389 | |||
390 | (* inverse complex hyperbolic functions *) |
||
391 | |||
392 | (* Гиперболический арккосинус. |
||
393 | hyberbolic arg cosinus *) |
||
394 | (* _________ *) |
||
395 | (* argch(z) = -/+ ln(z + i.V 1 - z.z) *) |
||
396 | PROCEDURE CArcCosh* (z : complex): complex; |
||
397 | BEGIN |
||
398 | result:=CNeg(CLn(CAdd(z, CMul(i, CSqrt(CSub_r2(1.0, CMul(z, z))))))); |
||
399 | |||
400 | RETURN result |
||
401 | END CArcCosh; |
||
402 | |||
403 | (* Гиперболический арксинус. |
||
404 | hyperbolic arc sinus *) |
||
405 | (* ________ *) |
||
406 | (* argsh(z) = ln(z + V 1 + z.z) *) |
||
407 | PROCEDURE CArcSinh* (z : complex): complex; |
||
408 | BEGIN |
||
409 | result:=CLn(CAdd(z, CSqrt(CAdd_r(CMul(z, z), 1.0)))); |
||
410 | |||
411 | RETURN result |
||
412 | END CArcSinh; |
||
413 | |||
414 | (* Гиперболический арктангенс. |
||
415 | hyperbolic arc tangent *) |
||
416 | (* argth(z) = 1/2 ln((z + 1) / (1 - z)) *) |
||
417 | PROCEDURE CArcTgh (z : complex): complex; |
||
418 | BEGIN |
||
419 | result:=CDiv_r(CLn(CDiv(CAdd_r(z, 1.0), CSub_r2(1.0, z))), 2.0); |
||
420 | |||
421 | RETURN result |
||
422 | END CArcTgh; |
||
423 | |||
424 | (* trigonometriques inverses *) |
||
425 | |||
426 | (* Арккосинус. |
||
427 | arc cosinus complex *) |
||
428 | (* arccos(z) = -i.argch(z) *) |
||
429 | PROCEDURE CArcCos* (z: complex): complex; |
||
430 | BEGIN |
||
431 | result := CNeg(CMul(i, CArcCosh(z))); |
||
432 | |||
433 | RETURN result |
||
434 | END CArcCos; |
||
435 | |||
436 | (* Арксинус. |
||
437 | arc sinus complex *) |
||
438 | (* arcsin(z) = -i.argsh(i.z) *) |
||
439 | PROCEDURE CArcSin* (z : complex): complex; |
||
440 | BEGIN |
||
441 | result := CNeg(CMul(i, CArcSinh(z))); |
||
442 | |||
443 | RETURN result |
||
444 | END CArcSin; |
||
445 | |||
446 | (* Арктангенс. |
||
447 | arc tangente complex *) |
||
448 | (* arctg(z) = -i.argth(i.z) *) |
||
449 | PROCEDURE CArcTg* (z : complex): complex; |
||
450 | BEGIN |
||
451 | result := CNeg(CMul(i, CArcTgh(CMul(i, z)))); |
||
452 | |||
453 | RETURN result |
||
454 | END CArcTg; |
||
455 | |||
456 | BEGIN |
||
457 | |||
458 | result:=CInit(0.0, 0.0); |
||
459 | i :=CInit(0.0, 1.0); |
||
460 | _0:=CInit(0.0, 0.0); |
||
461 | |||
462 | END CMath.>> |