ucomplex.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Pierre Muller,
  4. member of the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. Unit UComplex;
  12. {$INLINE ON}
  13. {$define TEST_INLINE}
  14. { created for FPC by Pierre Muller }
  15. { inpired from the complex unit from JD GAYRARD mai 95 }
  16. { FPC supports operator overloading }
  17. interface
  18. {$ifndef FPUNONE}
  19. uses math;
  20. type complex = record
  21. re : real;
  22. im : real;
  23. end;
  24. pcomplex = ^complex;
  25. const i : complex = (re : 0.0; im : 1.0);
  26. _0 : complex = (re : 0.0; im : 0.0);
  27. { assignment overloading is also used in type conversions
  28. (beware also in implicit type conversions)
  29. after this operator any real can be passed to a function
  30. as a complex arg !! }
  31. operator := (r : real) z : complex;
  32. {$ifdef TEST_INLINE}
  33. inline;
  34. {$endif TEST_INLINE}
  35. { operator := (i : longint) z : complex;
  36. not needed because longint can be converted to real }
  37. { four operator : +, -, * , / and comparison = }
  38. operator + (z1, z2 : complex) z : complex;
  39. {$ifdef TEST_INLINE}
  40. inline;
  41. {$endif TEST_INLINE}
  42. { these ones are created because the code
  43. is simpler and thus faster }
  44. operator + (z1 : complex; r : real) z : complex;
  45. {$ifdef TEST_INLINE}
  46. inline;
  47. {$endif TEST_INLINE}
  48. operator + (r : real; z1 : complex) z : complex;
  49. {$ifdef TEST_INLINE}
  50. inline;
  51. {$endif TEST_INLINE}
  52. operator - (z1, z2 : complex) z : complex;
  53. {$ifdef TEST_INLINE}
  54. inline;
  55. {$endif TEST_INLINE}
  56. operator - (z1 : complex;r : real) z : complex;
  57. {$ifdef TEST_INLINE}
  58. inline;
  59. {$endif TEST_INLINE}
  60. operator - (r : real; z1 : complex) z : complex;
  61. {$ifdef TEST_INLINE}
  62. inline;
  63. {$endif TEST_INLINE}
  64. operator * (z1, z2 : complex) z : complex;
  65. {$ifdef TEST_INLINE}
  66. inline;
  67. {$endif TEST_INLINE}
  68. operator * (z1 : complex; r : real) z : complex;
  69. {$ifdef TEST_INLINE}
  70. inline;
  71. {$endif TEST_INLINE}
  72. operator * (r : real; z1 : complex) z : complex;
  73. {$ifdef TEST_INLINE}
  74. inline;
  75. {$endif TEST_INLINE}
  76. operator / (znum, zden : complex) z : complex;
  77. {$ifdef TEST_INLINE}
  78. inline;
  79. {$endif TEST_INLINE}
  80. operator / (znum : complex; r : real) z : complex;
  81. {$ifdef TEST_INLINE}
  82. inline;
  83. {$endif TEST_INLINE}
  84. operator / (r : real; zden : complex) z : complex;
  85. {$ifdef TEST_INLINE}
  86. inline;
  87. {$endif TEST_INLINE}
  88. { ** is the exponentiation operator }
  89. operator ** (z1, z2 : complex) z : complex;
  90. {$ifdef TEST_INLINE}
  91. inline;
  92. {$endif TEST_INLINE}
  93. operator ** (z1 : complex; r : real) z : complex;
  94. {$ifdef TEST_INLINE}
  95. inline;
  96. {$endif TEST_INLINE}
  97. operator ** (r : real; z1 : complex) z : complex;
  98. {$ifdef TEST_INLINE}
  99. inline;
  100. {$endif TEST_INLINE}
  101. operator = (z1, z2 : complex) b : boolean;
  102. {$ifdef TEST_INLINE}
  103. inline;
  104. {$endif TEST_INLINE}
  105. operator = (z1 : complex;r : real) b : boolean;
  106. {$ifdef TEST_INLINE}
  107. inline;
  108. {$endif TEST_INLINE}
  109. operator = (r : real; z1 : complex) b : boolean;
  110. {$ifdef TEST_INLINE}
  111. inline;
  112. {$endif TEST_INLINE}
  113. operator - (z1 : complex) z : complex;
  114. {$ifdef TEST_INLINE}
  115. inline;
  116. {$endif TEST_INLINE}
  117. function cinit(_re,_im : real) : complex;inline;
  118. function csamevalue(z1, z2 : complex) : boolean;
  119. { complex functions }
  120. function cong (z : complex) : complex; { conjuge }
  121. { inverse function 1/z }
  122. function cinv (z : complex) : complex;
  123. { complex functions with real return values }
  124. function cmod (z : complex) : real; { module }
  125. function carg (z : complex) : real; { argument : a / z = p.e^ia }
  126. { fonctions elementaires }
  127. function cexp (z : complex) : complex; { exponential }
  128. function cln (z : complex) : complex; { natural logarithm }
  129. function csqr (z: complex) : complex; { square }
  130. function csqrt (z : complex) : complex; { square root }
  131. { complex trigonometric functions }
  132. function ccos (z : complex) : complex; { cosinus }
  133. function csin (z : complex) : complex; { sinus }
  134. function ctg (z : complex) : complex; { tangent }
  135. { inverse complex trigonometric functions }
  136. function carc_cos (z : complex) : complex; { arc cosinus }
  137. function carc_sin (z : complex) : complex; { arc sinus }
  138. function carc_tg (z : complex) : complex; { arc tangent }
  139. { hyperbolic complex functions }
  140. function cch (z : complex) : complex; { hyperbolic cosinus }
  141. function csh (z : complex) : complex; { hyperbolic sinus }
  142. function cth (z : complex) : complex; { hyperbolic tangent }
  143. { inverse hyperbolic complex functions }
  144. function carg_ch (z : complex) : complex; { hyperbolic arc cosinus }
  145. function carg_sh (z : complex) : complex; { hyperbolic arc sinus }
  146. function carg_th (z : complex) : complex; { hyperbolic arc tangente }
  147. { functions to write out a complex value }
  148. function cstr(z : complex) : string;
  149. function cstr(z:complex;len : integer) : string;
  150. function cstr(z:complex;len,dec : integer) : string;
  151. implementation
  152. function cinit(_re,_im : real) : complex;inline;
  153. begin
  154. cinit.re:=_re;
  155. cinit.im:=_im;
  156. end;
  157. function csamevalue(z1, z2: complex): boolean;
  158. begin
  159. csamevalue:=SameValue(z1.re, z2.re) and SameValue(z1.im, z2.im);
  160. end;
  161. operator := (r : real) z : complex;
  162. {$ifdef TEST_INLINE}
  163. inline;
  164. {$endif TEST_INLINE}
  165. begin
  166. z.re:=r;
  167. z.im:=0.0;
  168. end;
  169. { four base operations +, -, * , / }
  170. operator + (z1, z2 : complex) z : complex;
  171. {$ifdef TEST_INLINE}
  172. inline;
  173. {$endif TEST_INLINE}
  174. { addition : z := z1 + z2 }
  175. begin
  176. z.re := z1.re + z2.re;
  177. z.im := z1.im + z2.im;
  178. end;
  179. operator + (z1 : complex; r : real) z : complex;
  180. { addition : z := z1 + r }
  181. {$ifdef TEST_INLINE}
  182. inline;
  183. {$endif TEST_INLINE}
  184. begin
  185. z.re := z1.re + r;
  186. z.im := z1.im;
  187. end;
  188. operator + (r : real; z1 : complex) z : complex;
  189. { addition : z := r + z1 }
  190. {$ifdef TEST_INLINE}
  191. inline;
  192. {$endif TEST_INLINE}
  193. begin
  194. z.re := z1.re + r;
  195. z.im := z1.im;
  196. end;
  197. operator - (z1, z2 : complex) z : complex;
  198. {$ifdef TEST_INLINE}
  199. inline;
  200. {$endif TEST_INLINE}
  201. { substraction : z := z1 - z2 }
  202. begin
  203. z.re := z1.re - z2.re;
  204. z.im := z1.im - z2.im;
  205. end;
  206. operator - (z1 : complex; r : real) z : complex;
  207. {$ifdef TEST_INLINE}
  208. inline;
  209. {$endif TEST_INLINE}
  210. { substraction : z := z1 - r }
  211. begin
  212. z.re := z1.re - r;
  213. z.im := z1.im;
  214. end;
  215. operator - (z1 : complex) z : complex;
  216. {$ifdef TEST_INLINE}
  217. inline;
  218. {$endif TEST_INLINE}
  219. { substraction : z := - z1 }
  220. begin
  221. z.re := -z1.re;
  222. z.im := -z1.im;
  223. end;
  224. operator - (r : real; z1 : complex) z : complex;
  225. {$ifdef TEST_INLINE}
  226. inline;
  227. {$endif TEST_INLINE}
  228. { substraction : z := r - z1 }
  229. begin
  230. z.re := r - z1.re;
  231. z.im := - z1.im;
  232. end;
  233. operator * (z1, z2 : complex) z : complex;
  234. { multiplication : z := z1 * z2 }
  235. {$ifdef TEST_INLINE}
  236. inline;
  237. {$endif TEST_INLINE}
  238. begin
  239. z.re := (z1.re * z2.re) - (z1.im * z2.im);
  240. z.im := (z1.re * z2.im) + (z1.im * z2.re);
  241. end;
  242. operator * (z1 : complex; r : real) z : complex;
  243. {$ifdef TEST_INLINE}
  244. inline;
  245. {$endif TEST_INLINE}
  246. { multiplication : z := z1 * r }
  247. begin
  248. z.re := z1.re * r;
  249. z.im := z1.im * r;
  250. end;
  251. operator * (r : real; z1 : complex) z : complex;
  252. {$ifdef TEST_INLINE}
  253. inline;
  254. {$endif TEST_INLINE}
  255. { multiplication : z := r * z1 }
  256. begin
  257. z.re := z1.re * r;
  258. z.im := z1.im * r;
  259. end;
  260. operator / (znum, zden : complex) z : complex;
  261. {$ifdef TEST_INLINE}
  262. inline;
  263. {$endif TEST_INLINE}
  264. { division : z := znum / zden }
  265. { The following algorithm is used to properly handle
  266. denominator overflow:
  267. | a + b(d/c) c - a(d/c)
  268. | ---------- + ---------- I if |d| < |c|
  269. a + b I | c + d(d/c) a + d(d/c)
  270. ------- = |
  271. c + d I | b + a(c/d) -a+ b(c/d)
  272. | ---------- + ---------- I if |d| >= |c|
  273. | d + c(c/d) d + c(c/d)
  274. }
  275. var
  276. tmp, denom : real;
  277. begin
  278. if ( abs(zden.re) > abs(zden.im) ) then
  279. begin
  280. tmp := zden.im / zden.re;
  281. denom := zden.re + zden.im * tmp;
  282. z.re := (znum.re + znum.im * tmp) / denom;
  283. z.im := (znum.im - znum.re * tmp) / denom;
  284. end
  285. else
  286. begin
  287. tmp := zden.re / zden.im;
  288. denom := zden.im + zden.re * tmp;
  289. z.re := (znum.im + znum.re * tmp) / denom;
  290. z.im := (-znum.re + znum.im * tmp) / denom;
  291. end;
  292. end;
  293. operator / (znum : complex; r : real) z : complex;
  294. { division : z := znum / r }
  295. begin
  296. z.re := znum.re / r;
  297. z.im := znum.im / r;
  298. end;
  299. operator / (r : real; zden : complex) z : complex;
  300. { division : z := r / zden }
  301. var denom : real;
  302. begin
  303. with zden do denom := (re * re) + (im * im);
  304. { generates a fpu exception if denom=0 as for reals }
  305. z.re := (r * zden.re) / denom;
  306. z.im := - (r * zden.im) / denom;
  307. end;
  308. function cmod (z : complex): real;
  309. { module : r = |z| }
  310. begin
  311. with z do
  312. cmod := sqrt((re * re) + (im * im));
  313. end;
  314. function carg (z : complex): real;
  315. { argument : 0 / z = p ei0 }
  316. begin
  317. carg := arctan2(z.im, z.re);
  318. end;
  319. function cong (z : complex) : complex;
  320. { complex conjugee :
  321. if z := x + i.y
  322. then cong is x - i.y }
  323. begin
  324. cong.re := z.re;
  325. cong.im := - z.im;
  326. end;
  327. function cinv (z : complex) : complex;
  328. { inverse : r := 1 / z }
  329. var
  330. denom : real;
  331. begin
  332. with z do denom := (re * re) + (im * im);
  333. { generates a fpu exception if denom=0 as for reals }
  334. cinv.re:=z.re/denom;
  335. cinv.im:=-z.im/denom;
  336. end;
  337. operator = (z1, z2 : complex) b : boolean;
  338. { returns TRUE if z1 = z2 }
  339. begin
  340. b := (z1.re = z2.re) and (z1.im = z2.im);
  341. end;
  342. operator = (z1 : complex; r :real) b : boolean;
  343. { returns TRUE if z1 = r }
  344. begin
  345. b := (z1.re = r) and (z1.im = 0.0)
  346. end;
  347. operator = (r : real; z1 : complex) b : boolean;
  348. { returns TRUE if z1 = r }
  349. begin
  350. b := (z1.re = r) and (z1.im = 0.0)
  351. end;
  352. { fonctions elementaires }
  353. function cexp (z : complex) : complex;
  354. { exponantial : r := exp(z) }
  355. { exp(x + iy) = exp(x).exp(iy) = exp(x).[cos(y) + i sin(y)] }
  356. var expz : real;
  357. begin
  358. expz := exp(z.re);
  359. cexp.re := expz * cos(z.im);
  360. cexp.im := expz * sin(z.im);
  361. end;
  362. function cln (z : complex) : complex;
  363. { natural logarithm : r := ln(z) }
  364. { ln( p exp(i0)) = ln(p) + i0 + 2kpi }
  365. begin
  366. cln.re := ln(cmod(z));
  367. cln.im := arctan2(z.im, z.re);
  368. end;
  369. function csqr(z: complex): complex;
  370. { square : r := z*z }
  371. begin
  372. csqr.re := z.re * z.re - z.im * z.im;
  373. csqr.im := 2 * z.re * z.im;
  374. end;
  375. function csqrt (z : complex) : complex;
  376. { square root : r := sqrt(z) }
  377. var
  378. root, q : real;
  379. begin
  380. if (z.re<>0.0) or (z.im<>0.0) then
  381. begin
  382. root := sqrt(0.5 * (abs(z.re) + cmod(z)));
  383. q := z.im / (2.0 * root);
  384. if z.re >= 0.0 then
  385. begin
  386. csqrt.re := root;
  387. csqrt.im := q;
  388. end
  389. else if z.im < 0.0 then
  390. begin
  391. csqrt.re := - q;
  392. csqrt.im := - root
  393. end
  394. else
  395. begin
  396. csqrt.re := q;
  397. csqrt.im := root
  398. end
  399. end
  400. else csqrt := z;
  401. end;
  402. operator ** (z1, z2 : complex) z : complex;
  403. { exp : z := z1 ** z2 }
  404. begin
  405. z := cexp(z2*cln(z1));
  406. end;
  407. operator ** (z1 : complex; r : real) z : complex;
  408. { multiplication : z := z1 * r }
  409. begin
  410. z := cexp( r *cln(z1));
  411. end;
  412. operator ** (r : real; z1 : complex) z : complex;
  413. { multiplication : z := r + z1 }
  414. begin
  415. z := cexp(z1*ln(r));
  416. end;
  417. { direct trigonometric functions }
  418. function ccos (z : complex) : complex;
  419. { complex cosinus }
  420. { cos(x+iy) = cos(x).cos(iy) - sin(x).sin(iy) }
  421. { cos(ix) = cosh(x) et sin(ix) = i.sinh(x) }
  422. begin
  423. ccos.re := cos(z.re) * cosh(z.im);
  424. ccos.im := - sin(z.re) * sinh(z.im);
  425. end;
  426. function csin (z : complex) : complex;
  427. { sinus complex }
  428. { sin(x+iy) = sin(x).cos(iy) + cos(x).sin(iy) }
  429. { cos(ix) = cosh(x) et sin(ix) = i.sinh(x) }
  430. begin
  431. csin.re := sin(z.re) * cosh(z.im);
  432. csin.im := cos(z.re) * sinh(z.im);
  433. end;
  434. function ctg (z : complex) : complex;
  435. { tangente }
  436. var ccosz, temp : complex;
  437. begin
  438. ccosz := ccos(z);
  439. temp := csin(z);
  440. ctg := temp / ccosz;
  441. end;
  442. { fonctions trigonometriques inverses }
  443. function carc_cos (z : complex) : complex;
  444. { arc cosinus complex }
  445. { arccos(z) = -i.argch(z) }
  446. begin
  447. carc_cos := -i*carg_ch(z);
  448. end;
  449. function carc_sin (z : complex) : complex;
  450. { arc sinus complex }
  451. { arcsin(z) = -i.argsh(i.z) }
  452. begin
  453. carc_sin := -i*carg_sh(i*z);
  454. end;
  455. function carc_tg (z : complex) : complex;
  456. { arc tangente complex }
  457. { arctg(z) = -i.argth(i.z) }
  458. begin
  459. carc_tg := -i*carg_th(i*z);
  460. end;
  461. { hyberbolic complex functions }
  462. function cch (z : complex) : complex;
  463. { hyberbolic cosinus }
  464. { cosh(x+iy) = cosh(x).cosh(iy) + sinh(x).sinh(iy) }
  465. { cosh(iy) = cos(y) et sinh(iy) = i.sin(y) }
  466. begin
  467. cch.re := cosh(z.re) * cos(z.im);
  468. cch.im := sinh(z.re) * sin(z.im);
  469. end;
  470. function csh (z : complex) : complex;
  471. { hyberbolic sinus }
  472. { sinh(x+iy) = sinh(x).cosh(iy) + cosh(x).sinh(iy) }
  473. { cosh(iy) = cos(y) et sinh(iy) = i.sin(y) }
  474. begin
  475. csh.re := sinh(z.re) * cos(z.im);
  476. csh.im := cosh(z.re) * sin(z.im);
  477. end;
  478. function cth (z : complex) : complex;
  479. { hyberbolic complex tangent }
  480. { th(x) = sinh(x) / cosh(x) }
  481. { cosh(x) > 1 qq x }
  482. var temp : complex;
  483. begin
  484. temp := cch(z);
  485. z := csh(z);
  486. cth := z / temp;
  487. end;
  488. { inverse complex hyperbolic functions }
  489. function carg_ch (z : complex) : complex;
  490. { hyberbolic arg cosinus }
  491. { _________ }
  492. { argch(z) = -/+ ln(z + i.V 1 - z.z) }
  493. begin
  494. carg_ch:=-cln(z+i*csqrt(1.0-z*z));
  495. end;
  496. function carg_sh (z : complex) : complex;
  497. { hyperbolic arc sinus }
  498. { ________ }
  499. { argsh(z) = ln(z + V 1 + z.z) }
  500. begin
  501. carg_sh:=cln(z+csqrt(z*z+1.0));
  502. end;
  503. function carg_th (z : complex) : complex;
  504. { hyperbolic arc tangent }
  505. { argth(z) = 1/2 ln((z + 1) / (1 - z)) }
  506. begin
  507. carg_th:=cln((z+1.0)/(1.0-z))/2.0;
  508. end;
  509. { functions to write out a complex value }
  510. function cstr(z : complex) : string;
  511. var
  512. istr : string;
  513. begin
  514. str(z.im,istr);
  515. str(z.re,cstr);
  516. while istr[1]=' ' do
  517. delete(istr,1,1);
  518. if z.im<0 then
  519. cstr:=cstr+istr+'i'
  520. else if z.im>0 then
  521. cstr:=cstr+'+'+istr+'i';
  522. end;
  523. function cstr(z:complex;len : integer) : string;
  524. var
  525. istr : string;
  526. begin
  527. str(z.im:len,istr);
  528. while istr[1]=' ' do
  529. delete(istr,1,1);
  530. str(z.re:len,cstr);
  531. if z.im<0 then
  532. cstr:=cstr+istr+'i'
  533. else if z.im>0 then
  534. cstr:=cstr+'+'+istr+'i';
  535. end;
  536. function cstr(z:complex;len,dec : integer) : string;
  537. var
  538. istr : string;
  539. begin
  540. str(z.im:len:dec,istr);
  541. while istr[1]=' ' do
  542. delete(istr,1,1);
  543. str(z.re:len:dec,cstr);
  544. if z.im<0 then
  545. cstr:=cstr+istr+'i'
  546. else if z.im>0 then
  547. cstr:=cstr+'+'+istr+'i';
  548. end;
  549. {$else}
  550. implementation
  551. {$endif FPUNONE}
  552. end.