cmplx.odin 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. package math_cmplx
  2. import "core:builtin"
  3. import "core:math"
  4. // The original C code, the long comment, and the constants
  5. // below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
  6. // The go code is a simplified version of the original C.
  7. //
  8. // Cephes Math Library Release 2.8: June, 2000
  9. // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
  10. //
  11. // The readme file at http://netlib.sandia.gov/cephes/ says:
  12. // Some software in this archive may be from the book _Methods and
  13. // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
  14. // International, 1989) or from the Cephes Mathematical Library, a
  15. // commercial product. In either event, it is copyrighted by the author.
  16. // What you see here may be used freely but it comes with no support or
  17. // guarantee.
  18. //
  19. // The two known misprints in the book are repaired here in the
  20. // source listings for the gamma function and the incomplete beta
  21. // integral.
  22. //
  23. // Stephen L. Moshier
  24. // [email protected]
  25. abs :: builtin.abs
  26. conj :: builtin.conj
  27. real :: builtin.real
  28. imag :: builtin.imag
  29. jmag :: builtin.jmag
  30. kmag :: builtin.kmag
  31. sin :: proc{
  32. sin_complex128,
  33. }
  34. cos :: proc{
  35. cos_complex128,
  36. }
  37. tan :: proc{
  38. tan_complex128,
  39. }
  40. cot :: proc{
  41. cot_complex128,
  42. }
  43. sinh :: proc{
  44. sinh_complex128,
  45. }
  46. cosh :: proc{
  47. cosh_complex128,
  48. }
  49. tanh :: proc{
  50. tanh_complex128,
  51. }
  52. // sqrt returns the square root of x.
  53. // The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x).
  54. sqrt :: proc{
  55. sqrt_complex32,
  56. sqrt_complex64,
  57. sqrt_complex128,
  58. }
  59. ln :: proc{
  60. ln_complex32,
  61. ln_complex64,
  62. ln_complex128,
  63. }
  64. log10 :: proc{
  65. log10_complex32,
  66. log10_complex64,
  67. log10_complex128,
  68. }
  69. exp :: proc{
  70. exp_complex32,
  71. exp_complex64,
  72. exp_complex128,
  73. }
  74. pow :: proc{
  75. pow_complex32,
  76. pow_complex64,
  77. pow_complex128,
  78. }
  79. phase :: proc{
  80. phase_complex32,
  81. phase_complex64,
  82. phase_complex128,
  83. }
  84. polar :: proc{
  85. polar_complex32,
  86. polar_complex64,
  87. polar_complex128,
  88. }
  89. is_inf :: proc{
  90. is_inf_complex32,
  91. is_inf_complex64,
  92. is_inf_complex128,
  93. }
  94. is_nan :: proc{
  95. is_nan_complex32,
  96. is_nan_complex64,
  97. is_nan_complex128,
  98. }
  99. // sqrt_complex32 returns the square root of x.
  100. // The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x).
  101. sqrt_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  102. return complex32(sqrt_complex128(complex128(x)))
  103. }
  104. // sqrt_complex64 returns the square root of x.
  105. // The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x).
  106. sqrt_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  107. return complex64(sqrt_complex128(complex128(x)))
  108. }
  109. // sqrt_complex128 returns the square root of x.
  110. // The result r is chosen so that real(r) ≥ 0 and imag(r) has the same sign as imag(x).
  111. sqrt_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  112. // The original C code, the long comment, and the constants
  113. // below are from http://netlib.sandia.gov/cephes/c9x-complex/clog.c.
  114. // The go code is a simplified version of the original C.
  115. //
  116. // Cephes Math Library Release 2.8: June, 2000
  117. // Copyright 1984, 1987, 1989, 1992, 2000 by Stephen L. Moshier
  118. //
  119. // The readme file at http://netlib.sandia.gov/cephes/ says:
  120. // Some software in this archive may be from the book _Methods and
  121. // Programs for Mathematical Functions_ (Prentice-Hall or Simon & Schuster
  122. // International, 1989) or from the Cephes Mathematical Library, a
  123. // commercial product. In either event, it is copyrighted by the author.
  124. // What you see here may be used freely but it comes with no support or
  125. // guarantee.
  126. //
  127. // The two known misprints in the book are repaired here in the
  128. // source listings for the gamma function and the incomplete beta
  129. // integral.
  130. //
  131. // Stephen L. Moshier
  132. // [email protected]
  133. // Complex square root
  134. //
  135. // DESCRIPTION:
  136. //
  137. // If z = x + iy, r = |z|, then
  138. //
  139. // 1/2
  140. // Re w = [ (r + x)/2 ] ,
  141. //
  142. // 1/2
  143. // Im w = [ (r - x)/2 ] .
  144. //
  145. // Cancellation error in r-x or r+x is avoided by using the
  146. // identity 2 Re w Im w = y.
  147. //
  148. // Note that -w is also a square root of z. The root chosen
  149. // is always in the right half plane and Im w has the same sign as y.
  150. //
  151. // ACCURACY:
  152. //
  153. // Relative error:
  154. // arithmetic domain # trials peak rms
  155. // DEC -10,+10 25000 3.2e-17 9.6e-18
  156. // IEEE -10,+10 1,000,000 2.9e-16 6.1e-17
  157. if imag(x) == 0 {
  158. // Ensure that imag(r) has the same sign as imag(x) for imag(x) == signed zero.
  159. if real(x) == 0 {
  160. return complex(0, imag(x))
  161. }
  162. if real(x) < 0 {
  163. return complex(0, math.copy_sign(math.sqrt(-real(x)), imag(x)))
  164. }
  165. return complex(math.sqrt(real(x)), imag(x))
  166. } else if math.is_inf(imag(x), 0) {
  167. return complex(math.inf_f64(1.0), imag(x))
  168. }
  169. if real(x) == 0 {
  170. if imag(x) < 0 {
  171. r := math.sqrt(-0.5 * imag(x))
  172. return complex(r, -r)
  173. }
  174. r := math.sqrt(0.5 * imag(x))
  175. return complex(r, r)
  176. }
  177. a := real(x)
  178. b := imag(x)
  179. scale: f64
  180. // Rescale to avoid internal overflow or underflow.
  181. if abs(a) > 4 || abs(b) > 4 {
  182. a *= 0.25
  183. b *= 0.25
  184. scale = 2
  185. } else {
  186. a *= 1.8014398509481984e16 // 2**54
  187. b *= 1.8014398509481984e16
  188. scale = 7.450580596923828125e-9 // 2**-27
  189. }
  190. r := math.hypot(a, b)
  191. t: f64
  192. if a > 0 {
  193. t = math.sqrt(0.5*r + 0.5*a)
  194. r = scale * abs((0.5*b)/t)
  195. t *= scale
  196. } else {
  197. r = math.sqrt(0.5*r - 0.5*a)
  198. t = scale * abs((0.5*b)/r)
  199. r *= scale
  200. }
  201. if b < 0 {
  202. return complex(t, -r)
  203. }
  204. return complex(t, r)
  205. }
  206. ln_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  207. return complex(math.ln(abs(x)), phase(x))
  208. }
  209. ln_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  210. return complex(math.ln(abs(x)), phase(x))
  211. }
  212. ln_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  213. return complex(math.ln(abs(x)), phase(x))
  214. }
  215. exp_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  216. switch re, im := real(x), imag(x); {
  217. case math.is_inf(re, 0):
  218. switch {
  219. case re > 0 && im == 0:
  220. return x
  221. case math.is_inf(im, 0) || math.is_nan(im):
  222. if re < 0 {
  223. return complex(0, math.copy_sign(0, im))
  224. } else {
  225. return complex(math.inf_f64(1.0), math.nan_f64())
  226. }
  227. }
  228. case math.is_nan(re):
  229. if im == 0 {
  230. return complex(math.nan_f16(), im)
  231. }
  232. }
  233. r := math.exp(real(x))
  234. s, c := math.sincos(imag(x))
  235. return complex(r*c, r*s)
  236. }
  237. exp_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  238. switch re, im := real(x), imag(x); {
  239. case math.is_inf(re, 0):
  240. switch {
  241. case re > 0 && im == 0:
  242. return x
  243. case math.is_inf(im, 0) || math.is_nan(im):
  244. if re < 0 {
  245. return complex(0, math.copy_sign(0, im))
  246. } else {
  247. return complex(math.inf_f64(1.0), math.nan_f64())
  248. }
  249. }
  250. case math.is_nan(re):
  251. if im == 0 {
  252. return complex(math.nan_f32(), im)
  253. }
  254. }
  255. r := math.exp(real(x))
  256. s, c := math.sincos(imag(x))
  257. return complex(r*c, r*s)
  258. }
  259. exp_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  260. switch re, im := real(x), imag(x); {
  261. case math.is_inf(re, 0):
  262. switch {
  263. case re > 0 && im == 0:
  264. return x
  265. case math.is_inf(im, 0) || math.is_nan(im):
  266. if re < 0 {
  267. return complex(0, math.copy_sign(0, im))
  268. } else {
  269. return complex(math.inf_f64(1.0), math.nan_f64())
  270. }
  271. }
  272. case math.is_nan(re):
  273. if im == 0 {
  274. return complex(math.nan_f64(), im)
  275. }
  276. }
  277. r := math.exp(real(x))
  278. s, c := math.sincos(imag(x))
  279. return complex(r*c, r*s)
  280. }
  281. pow_complex32 :: proc "contextless" (x, y: complex32) -> complex32 {
  282. if x == 0 { // Guaranteed also true for x == -0.
  283. if is_nan(y) {
  284. return nan_complex32()
  285. }
  286. r, i := real(y), imag(y)
  287. switch {
  288. case r == 0:
  289. return 1
  290. case r < 0:
  291. if i == 0 {
  292. return complex(math.inf_f16(1), 0)
  293. }
  294. return inf_complex32()
  295. case r > 0:
  296. return 0
  297. }
  298. unreachable()
  299. }
  300. modulus := abs(x)
  301. if modulus == 0 {
  302. return complex(0, 0)
  303. }
  304. r := math.pow(modulus, real(y))
  305. arg := phase(x)
  306. theta := real(y) * arg
  307. if imag(y) != 0 {
  308. r *= math.exp(-imag(y) * arg)
  309. theta += imag(y) * math.ln(modulus)
  310. }
  311. s, c := math.sincos(theta)
  312. return complex(r*c, r*s)
  313. }
  314. pow_complex64 :: proc "contextless" (x, y: complex64) -> complex64 {
  315. if x == 0 { // Guaranteed also true for x == -0.
  316. if is_nan(y) {
  317. return nan_complex64()
  318. }
  319. r, i := real(y), imag(y)
  320. switch {
  321. case r == 0:
  322. return 1
  323. case r < 0:
  324. if i == 0 {
  325. return complex(math.inf_f32(1), 0)
  326. }
  327. return inf_complex64()
  328. case r > 0:
  329. return 0
  330. }
  331. unreachable()
  332. }
  333. modulus := abs(x)
  334. if modulus == 0 {
  335. return complex(0, 0)
  336. }
  337. r := math.pow(modulus, real(y))
  338. arg := phase(x)
  339. theta := real(y) * arg
  340. if imag(y) != 0 {
  341. r *= math.exp(-imag(y) * arg)
  342. theta += imag(y) * math.ln(modulus)
  343. }
  344. s, c := math.sincos(theta)
  345. return complex(r*c, r*s)
  346. }
  347. pow_complex128 :: proc "contextless" (x, y: complex128) -> complex128 {
  348. if x == 0 { // Guaranteed also true for x == -0.
  349. if is_nan(y) {
  350. return nan_complex128()
  351. }
  352. r, i := real(y), imag(y)
  353. switch {
  354. case r == 0:
  355. return 1
  356. case r < 0:
  357. if i == 0 {
  358. return complex(math.inf_f64(1), 0)
  359. }
  360. return inf_complex128()
  361. case r > 0:
  362. return 0
  363. }
  364. unreachable()
  365. }
  366. modulus := abs(x)
  367. if modulus == 0 {
  368. return complex(0, 0)
  369. }
  370. r := math.pow(modulus, real(y))
  371. arg := phase(x)
  372. theta := real(y) * arg
  373. if imag(y) != 0 {
  374. r *= math.exp(-imag(y) * arg)
  375. theta += imag(y) * math.ln(modulus)
  376. }
  377. s, c := math.sincos(theta)
  378. return complex(r*c, r*s)
  379. }
  380. log10_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  381. return math.LN10*ln(x)
  382. }
  383. log10_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  384. return math.LN10*ln(x)
  385. }
  386. log10_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  387. return math.LN10*ln(x)
  388. }
  389. phase_complex32 :: proc "contextless" (x: complex32) -> f16 {
  390. return math.atan2(imag(x), real(x))
  391. }
  392. phase_complex64 :: proc "contextless" (x: complex64) -> f32 {
  393. return math.atan2(imag(x), real(x))
  394. }
  395. phase_complex128 :: proc "contextless" (x: complex128) -> f64 {
  396. return math.atan2(imag(x), real(x))
  397. }
  398. rect_complex32 :: proc "contextless" (r, θ: f16) -> complex32 {
  399. s, c := math.sincos(θ)
  400. return complex(r*c, r*s)
  401. }
  402. rect_complex64 :: proc "contextless" (r, θ: f32) -> complex64 {
  403. s, c := math.sincos(θ)
  404. return complex(r*c, r*s)
  405. }
  406. rect_complex128 :: proc "contextless" (r, θ: f64) -> complex128 {
  407. s, c := math.sincos(θ)
  408. return complex(r*c, r*s)
  409. }
  410. polar_complex32 :: proc "contextless" (x: complex32) -> (r, θ: f16) {
  411. return abs(x), phase(x)
  412. }
  413. polar_complex64 :: proc "contextless" (x: complex64) -> (r, θ: f32) {
  414. return abs(x), phase(x)
  415. }
  416. polar_complex128 :: proc "contextless" (x: complex128) -> (r, θ: f64) {
  417. return abs(x), phase(x)
  418. }
  419. nan_complex32 :: proc "contextless" () -> complex32 {
  420. return complex(math.nan_f16(), math.nan_f16())
  421. }
  422. nan_complex64 :: proc "contextless" () -> complex64 {
  423. return complex(math.nan_f32(), math.nan_f32())
  424. }
  425. nan_complex128 :: proc "contextless" () -> complex128 {
  426. return complex(math.nan_f64(), math.nan_f64())
  427. }
  428. inf_complex32 :: proc "contextless" () -> complex32 {
  429. inf := math.inf_f16(1)
  430. return complex(inf, inf)
  431. }
  432. inf_complex64 :: proc "contextless" () -> complex64 {
  433. inf := math.inf_f32(1)
  434. return complex(inf, inf)
  435. }
  436. inf_complex128 :: proc "contextless" () -> complex128 {
  437. inf := math.inf_f64(1)
  438. return complex(inf, inf)
  439. }
  440. is_inf_complex32 :: proc "contextless" (x: complex32) -> bool {
  441. return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0)
  442. }
  443. is_inf_complex64 :: proc "contextless" (x: complex64) -> bool {
  444. return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0)
  445. }
  446. is_inf_complex128 :: proc "contextless" (x: complex128) -> bool {
  447. return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0)
  448. }
  449. is_nan_complex32 :: proc "contextless" (x: complex32) -> bool {
  450. if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) {
  451. return false
  452. }
  453. return math.is_nan(real(x)) || math.is_nan(imag(x))
  454. }
  455. is_nan_complex64 :: proc "contextless" (x: complex64) -> bool {
  456. if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) {
  457. return false
  458. }
  459. return math.is_nan(real(x)) || math.is_nan(imag(x))
  460. }
  461. is_nan_complex128 :: proc "contextless" (x: complex128) -> bool {
  462. if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) {
  463. return false
  464. }
  465. return math.is_nan(real(x)) || math.is_nan(imag(x))
  466. }