ucomplex.pp 16 KB

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