ucomplex.pp 16 KB

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