ucomplex.pp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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. { 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 csqrt (z : complex) : complex; { square root }
  130. { complex trigonometric functions }
  131. function ccos (z : complex) : complex; { cosinus }
  132. function csin (z : complex) : complex; { sinus }
  133. function ctg (z : complex) : complex; { tangent }
  134. { inverse complex trigonometric functions }
  135. function carc_cos (z : complex) : complex; { arc cosinus }
  136. function carc_sin (z : complex) : complex; { arc sinus }
  137. function carc_tg (z : complex) : complex; { arc tangent }
  138. { hyperbolic complex functions }
  139. function cch (z : complex) : complex; { hyperbolic cosinus }
  140. function csh (z : complex) : complex; { hyperbolic sinus }
  141. function cth (z : complex) : complex; { hyperbolic tangent }
  142. { inverse hyperbolic complex functions }
  143. function carg_ch (z : complex) : complex; { hyperbolic arc cosinus }
  144. function carg_sh (z : complex) : complex; { hyperbolic arc sinus }
  145. function carg_th (z : complex) : complex; { hyperbolic arc tangente }
  146. { functions to write out a complex value }
  147. function cstr(z : complex) : string;
  148. function cstr(z:complex;len : integer) : string;
  149. function cstr(z:complex;len,dec : integer) : string;
  150. implementation
  151. operator := (r : real) z : complex;
  152. {$ifdef TEST_INLINE}
  153. inline;
  154. {$endif TEST_INLINE}
  155. begin
  156. z.re:=r;
  157. z.im:=0.0;
  158. end;
  159. { four base operations +, -, * , / }
  160. operator + (z1, z2 : complex) z : complex;
  161. {$ifdef TEST_INLINE}
  162. inline;
  163. {$endif TEST_INLINE}
  164. { addition : z := z1 + z2 }
  165. begin
  166. z.re := z1.re + z2.re;
  167. z.im := z1.im + z2.im;
  168. end;
  169. operator + (z1 : complex; r : real) z : complex;
  170. { addition : z := z1 + r }
  171. {$ifdef TEST_INLINE}
  172. inline;
  173. {$endif TEST_INLINE}
  174. begin
  175. z.re := z1.re + r;
  176. z.im := z1.im;
  177. end;
  178. operator + (r : real; z1 : complex) z : complex;
  179. { addition : z := r + z1 }
  180. {$ifdef TEST_INLINE}
  181. inline;
  182. {$endif TEST_INLINE}
  183. begin
  184. z.re := z1.re + r;
  185. z.im := z1.im;
  186. end;
  187. operator - (z1, z2 : complex) z : complex;
  188. {$ifdef TEST_INLINE}
  189. inline;
  190. {$endif TEST_INLINE}
  191. { substraction : z := z1 - z2 }
  192. begin
  193. z.re := z1.re - z2.re;
  194. z.im := z1.im - z2.im;
  195. end;
  196. operator - (z1 : complex; r : real) z : complex;
  197. {$ifdef TEST_INLINE}
  198. inline;
  199. {$endif TEST_INLINE}
  200. { substraction : z := z1 - r }
  201. begin
  202. z.re := z1.re - r;
  203. z.im := z1.im;
  204. end;
  205. operator - (z1 : complex) z : complex;
  206. {$ifdef TEST_INLINE}
  207. inline;
  208. {$endif TEST_INLINE}
  209. { substraction : z := - z1 }
  210. begin
  211. z.re := -z1.re;
  212. z.im := -z1.im;
  213. end;
  214. operator - (r : real; z1 : complex) z : complex;
  215. {$ifdef TEST_INLINE}
  216. inline;
  217. {$endif TEST_INLINE}
  218. { substraction : z := r - z1 }
  219. begin
  220. z.re := r - z1.re;
  221. z.im := - z1.im;
  222. end;
  223. operator * (z1, z2 : complex) z : complex;
  224. { multiplication : z := z1 * z2 }
  225. {$ifdef TEST_INLINE}
  226. inline;
  227. {$endif TEST_INLINE}
  228. begin
  229. z.re := (z1.re * z2.re) - (z1.im * z2.im);
  230. z.im := (z1.re * z2.im) + (z1.im * z2.re);
  231. end;
  232. operator * (z1 : complex; r : real) z : complex;
  233. {$ifdef TEST_INLINE}
  234. inline;
  235. {$endif TEST_INLINE}
  236. { multiplication : z := z1 * r }
  237. begin
  238. z.re := z1.re * r;
  239. z.im := z1.im * r;
  240. end;
  241. operator * (r : real; z1 : complex) z : complex;
  242. {$ifdef TEST_INLINE}
  243. inline;
  244. {$endif TEST_INLINE}
  245. { multiplication : z := r * z1 }
  246. begin
  247. z.re := z1.re * r;
  248. z.im := z1.im * r;
  249. end;
  250. operator / (znum, zden : complex) z : complex;
  251. {$ifdef TEST_INLINE}
  252. inline;
  253. {$endif TEST_INLINE}
  254. { division : z := znum / zden }
  255. { The following algorithm is used to properly handle
  256. denominator overflow:
  257. | a + b(d/c) c - a(d/c)
  258. | ---------- + ---------- I if |d| < |c|
  259. a + b I | c + d(d/c) a + d(d/c)
  260. ------- = |
  261. c + d I | b + a(c/d) -a+ b(c/d)
  262. | ---------- + ---------- I if |d| >= |c|
  263. | d + c(c/d) d + c(c/d)
  264. }
  265. var
  266. tmp, denom : real;
  267. begin
  268. if ( abs(zden.re) > abs(zden.im) ) then
  269. begin
  270. tmp := zden.im / zden.re;
  271. denom := zden.re + zden.im * tmp;
  272. z.re := (znum.re + znum.im * tmp) / denom;
  273. z.im := (znum.im - znum.re * tmp) / denom;
  274. end
  275. else
  276. begin
  277. tmp := zden.re / zden.im;
  278. denom := zden.im + zden.re * tmp;
  279. z.re := (znum.im + znum.re * tmp) / denom;
  280. z.im := (-znum.re + znum.im * tmp) / denom;
  281. end;
  282. end;
  283. operator / (znum : complex; r : real) z : complex;
  284. { division : z := znum / r }
  285. begin
  286. z.re := znum.re / r;
  287. z.im := znum.im / r;
  288. end;
  289. operator / (r : real; zden : complex) z : complex;
  290. { division : z := r / zden }
  291. var denom : real;
  292. begin
  293. with zden do denom := (re * re) + (im * im);
  294. { generates a fpu exception if denom=0 as for reals }
  295. z.re := (r * zden.re) / denom;
  296. z.im := - (r * zden.im) / denom;
  297. end;
  298. function cmod (z : complex): real;
  299. { module : r = |z| }
  300. begin
  301. with z do
  302. cmod := sqrt((re * re) + (im * im));
  303. end;
  304. function carg (z : complex): real;
  305. { argument : 0 / z = p ei0 }
  306. begin
  307. carg := arctan2(z.im, z.re);
  308. end;
  309. function cong (z : complex) : complex;
  310. { complex conjugee :
  311. if z := x + i.y
  312. then cong is x - i.y }
  313. begin
  314. cong.re := z.re;
  315. cong.im := - z.im;
  316. end;
  317. function cinv (z : complex) : complex;
  318. { inverse : r := 1 / z }
  319. var
  320. denom : real;
  321. begin
  322. with z do denom := (re * re) + (im * im);
  323. { generates a fpu exception if denom=0 as for reals }
  324. cinv.re:=z.re/denom;
  325. cinv.im:=-z.im/denom;
  326. end;
  327. operator = (z1, z2 : complex) b : boolean;
  328. { returns TRUE if z1 = z2 }
  329. begin
  330. b := (z1.re = z2.re) and (z1.im = z2.im);
  331. end;
  332. operator = (z1 : complex; r :real) b : boolean;
  333. { returns TRUE if z1 = r }
  334. begin
  335. b := (z1.re = r) and (z1.im = 0.0)
  336. end;
  337. operator = (r : real; z1 : complex) b : boolean;
  338. { returns TRUE if z1 = r }
  339. begin
  340. b := (z1.re = r) and (z1.im = 0.0)
  341. end;
  342. { fonctions elementaires }
  343. function cexp (z : complex) : complex;
  344. { exponantial : r := exp(z) }
  345. { exp(x + iy) = exp(x).exp(iy) = exp(x).[cos(y) + i sin(y)] }
  346. var expz : real;
  347. begin
  348. expz := exp(z.re);
  349. cexp.re := expz * cos(z.im);
  350. cexp.im := expz * sin(z.im);
  351. end;
  352. function cln (z : complex) : complex;
  353. { natural logarithm : r := ln(z) }
  354. { ln( p exp(i0)) = ln(p) + i0 + 2kpi }
  355. begin
  356. cln.re := ln(cmod(z));
  357. cln.im := arctan2(z.im, z.re);
  358. end;
  359. function csqrt (z : complex) : complex;
  360. { square root : r := sqrt(z) }
  361. var
  362. root, q : real;
  363. begin
  364. if (z.re<>0.0) or (z.im<>0.0) then
  365. begin
  366. root := sqrt(0.5 * (abs(z.re) + cmod(z)));
  367. q := z.im / (2.0 * root);
  368. if z.re >= 0.0 then
  369. begin
  370. csqrt.re := root;
  371. csqrt.im := q;
  372. end
  373. else if z.im < 0.0 then
  374. begin
  375. csqrt.re := - q;
  376. csqrt.im := - root
  377. end
  378. else
  379. begin
  380. csqrt.re := q;
  381. csqrt.im := root
  382. end
  383. end
  384. else csqrt := z;
  385. end;
  386. operator ** (z1, z2 : complex) z : complex;
  387. { exp : z := z1 ** z2 }
  388. begin
  389. z := cexp(z2*cln(z1));
  390. end;
  391. operator ** (z1 : complex; r : real) z : complex;
  392. { multiplication : z := z1 * r }
  393. begin
  394. z := cexp( r *cln(z1));
  395. end;
  396. operator ** (r : real; z1 : complex) z : complex;
  397. { multiplication : z := r + z1 }
  398. begin
  399. z := cexp(z1*ln(r));
  400. end;
  401. { direct trigonometric functions }
  402. function ccos (z : complex) : complex;
  403. { complex cosinus }
  404. { cos(x+iy) = cos(x).cos(iy) - sin(x).sin(iy) }
  405. { cos(ix) = cosh(x) et sin(ix) = i.sinh(x) }
  406. begin
  407. ccos.re := cos(z.re) * cosh(z.im);
  408. ccos.im := - sin(z.re) * sinh(z.im);
  409. end;
  410. function csin (z : complex) : complex;
  411. { sinus complex }
  412. { sin(x+iy) = sin(x).cos(iy) + cos(x).sin(iy) }
  413. { cos(ix) = cosh(x) et sin(ix) = i.sinh(x) }
  414. begin
  415. csin.re := sin(z.re) * cosh(z.im);
  416. csin.im := cos(z.re) * sinh(z.im);
  417. end;
  418. function ctg (z : complex) : complex;
  419. { tangente }
  420. var ccosz, temp : complex;
  421. begin
  422. ccosz := ccos(z);
  423. temp := csin(z);
  424. ctg := temp / ccosz;
  425. end;
  426. { fonctions trigonometriques inverses }
  427. function carc_cos (z : complex) : complex;
  428. { arc cosinus complex }
  429. { arccos(z) = -i.argch(z) }
  430. begin
  431. carc_cos := -i*carg_ch(z);
  432. end;
  433. function carc_sin (z : complex) : complex;
  434. { arc sinus complex }
  435. { arcsin(z) = -i.argsh(i.z) }
  436. begin
  437. carc_sin := -i*carg_sh(i*z);
  438. end;
  439. function carc_tg (z : complex) : complex;
  440. { arc tangente complex }
  441. { arctg(z) = -i.argth(i.z) }
  442. begin
  443. carc_tg := -i*carg_th(i*z);
  444. end;
  445. { hyberbolic complex functions }
  446. function cch (z : complex) : complex;
  447. { hyberbolic cosinus }
  448. { cosh(x+iy) = cosh(x).cosh(iy) + sinh(x).sinh(iy) }
  449. { cosh(iy) = cos(y) et sinh(iy) = i.sin(y) }
  450. begin
  451. cch.re := cosh(z.re) * cos(z.im);
  452. cch.im := sinh(z.re) * sin(z.im);
  453. end;
  454. function csh (z : complex) : complex;
  455. { hyberbolic sinus }
  456. { sinh(x+iy) = sinh(x).cosh(iy) + cosh(x).sinh(iy) }
  457. { cosh(iy) = cos(y) et sinh(iy) = i.sin(y) }
  458. begin
  459. csh.re := sinh(z.re) * cos(z.im);
  460. csh.im := cosh(z.re) * sin(z.im);
  461. end;
  462. function cth (z : complex) : complex;
  463. { hyberbolic complex tangent }
  464. { th(x) = sinh(x) / cosh(x) }
  465. { cosh(x) > 1 qq x }
  466. var temp : complex;
  467. begin
  468. temp := cch(z);
  469. z := csh(z);
  470. cth := z / temp;
  471. end;
  472. { inverse complex hyperbolic functions }
  473. function carg_ch (z : complex) : complex;
  474. { hyberbolic arg cosinus }
  475. { _________ }
  476. { argch(z) = -/+ ln(z + i.V 1 - z.z) }
  477. begin
  478. carg_ch:=-cln(z+i*csqrt(z*z-1.0));
  479. end;
  480. function carg_sh (z : complex) : complex;
  481. { hyperbolic arc sinus }
  482. { ________ }
  483. { argsh(z) = ln(z + V 1 + z.z) }
  484. begin
  485. carg_sh:=cln(z+csqrt(z*z+1.0));
  486. end;
  487. function carg_th (z : complex) : complex;
  488. { hyperbolic arc tangent }
  489. { argth(z) = 1/2 ln((z + 1) / (1 - z)) }
  490. begin
  491. carg_th:=cln((z+1.0)/(z-1.0))/2.0;
  492. end;
  493. { functions to write out a complex value }
  494. function cstr(z : complex) : string;
  495. var
  496. istr : string;
  497. begin
  498. str(z.im,istr);
  499. str(z.re,cstr);
  500. while istr[1]=' ' do
  501. delete(istr,1,1);
  502. if z.im<0 then
  503. cstr:=cstr+istr+'i'
  504. else if z.im>0 then
  505. cstr:=cstr+'+'+istr+'i';
  506. end;
  507. function cstr(z:complex;len : integer) : string;
  508. var
  509. istr : string;
  510. begin
  511. str(z.im:len,istr);
  512. while istr[1]=' ' do
  513. delete(istr,1,1);
  514. str(z.re:len,cstr);
  515. if z.im<0 then
  516. cstr:=cstr+istr+'i'
  517. else if z.im>0 then
  518. cstr:=cstr+'+'+istr+'i';
  519. end;
  520. function cstr(z:complex;len,dec : integer) : string;
  521. var
  522. istr : string;
  523. begin
  524. str(z.im:len:dec,istr);
  525. while istr[1]=' ' do
  526. delete(istr,1,1);
  527. str(z.re:len:dec,cstr);
  528. if z.im<0 then
  529. cstr:=cstr+istr+'i'
  530. else if z.im>0 then
  531. cstr:=cstr+'+'+istr+'i';
  532. end;
  533. {$else}
  534. implementation
  535. {$endif FPUNONE}
  536. end.