cmplx.odin 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. package math_cmplx
  2. import "base: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 complex32(ln_complex64(complex64(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. return complex32(exp_complex64(complex64(x)))
  217. }
  218. exp_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  219. switch re, im := real(x), imag(x); {
  220. case math.is_inf(re, 0):
  221. switch {
  222. case re > 0 && im == 0:
  223. return x
  224. case math.is_inf(im, 0) || math.is_nan(im):
  225. if re < 0 {
  226. return complex(0, math.copy_sign(0, im))
  227. } else {
  228. return complex(math.inf_f64(1.0), math.nan_f64())
  229. }
  230. }
  231. case math.is_nan(re):
  232. if im == 0 {
  233. return complex(math.nan_f32(), im)
  234. }
  235. }
  236. r := math.exp(real(x))
  237. s, c := math.sincos(imag(x))
  238. return complex(r*c, r*s)
  239. }
  240. exp_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  241. switch re, im := real(x), imag(x); {
  242. case math.is_inf(re, 0):
  243. switch {
  244. case re > 0 && im == 0:
  245. return x
  246. case math.is_inf(im, 0) || math.is_nan(im):
  247. if re < 0 {
  248. return complex(0, math.copy_sign(0, im))
  249. } else {
  250. return complex(math.inf_f64(1.0), math.nan_f64())
  251. }
  252. }
  253. case math.is_nan(re):
  254. if im == 0 {
  255. return complex(math.nan_f64(), im)
  256. }
  257. }
  258. r := math.exp(real(x))
  259. s, c := math.sincos(imag(x))
  260. return complex(r*c, r*s)
  261. }
  262. pow_complex32 :: proc "contextless" (x, y: complex32) -> complex32 {
  263. return complex32(pow_complex64(complex64(x), complex64(y)))
  264. }
  265. pow_complex64 :: proc "contextless" (x, y: complex64) -> complex64 {
  266. if x == 0 { // Guaranteed also true for x == -0.
  267. if is_nan(y) {
  268. return nan_complex64()
  269. }
  270. r, i := real(y), imag(y)
  271. switch {
  272. case r == 0:
  273. return 1
  274. case r < 0:
  275. if i == 0 {
  276. return complex(math.inf_f32(1), 0)
  277. }
  278. return inf_complex64()
  279. case r > 0:
  280. return 0
  281. }
  282. unreachable()
  283. }
  284. modulus := abs(x)
  285. if modulus == 0 {
  286. return complex(0, 0)
  287. }
  288. r := math.pow(modulus, real(y))
  289. arg := phase(x)
  290. theta := real(y) * arg
  291. if imag(y) != 0 {
  292. r *= math.exp(-imag(y) * arg)
  293. theta += imag(y) * math.ln(modulus)
  294. }
  295. s, c := math.sincos(theta)
  296. return complex(r*c, r*s)
  297. }
  298. pow_complex128 :: proc "contextless" (x, y: complex128) -> complex128 {
  299. if x == 0 { // Guaranteed also true for x == -0.
  300. if is_nan(y) {
  301. return nan_complex128()
  302. }
  303. r, i := real(y), imag(y)
  304. switch {
  305. case r == 0:
  306. return 1
  307. case r < 0:
  308. if i == 0 {
  309. return complex(math.inf_f64(1), 0)
  310. }
  311. return inf_complex128()
  312. case r > 0:
  313. return 0
  314. }
  315. unreachable()
  316. }
  317. modulus := abs(x)
  318. if modulus == 0 {
  319. return complex(0, 0)
  320. }
  321. r := math.pow(modulus, real(y))
  322. arg := phase(x)
  323. theta := real(y) * arg
  324. if imag(y) != 0 {
  325. r *= math.exp(-imag(y) * arg)
  326. theta += imag(y) * math.ln(modulus)
  327. }
  328. s, c := math.sincos(theta)
  329. return complex(r*c, r*s)
  330. }
  331. log10_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  332. return complex32(log10_complex64(complex64(x)))
  333. }
  334. log10_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  335. return math.LN10*ln(x)
  336. }
  337. log10_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  338. return math.LN10*ln(x)
  339. }
  340. phase_complex32 :: proc "contextless" (x: complex32) -> f16 {
  341. return f16(phase_complex64(complex64(x)))
  342. }
  343. phase_complex64 :: proc "contextless" (x: complex64) -> f32 {
  344. return math.atan2(imag(x), real(x))
  345. }
  346. phase_complex128 :: proc "contextless" (x: complex128) -> f64 {
  347. return math.atan2(imag(x), real(x))
  348. }
  349. rect_complex32 :: proc "contextless" (r, θ: f16) -> complex32 {
  350. return complex32(rect_complex64(f32(r), f32(θ)))
  351. }
  352. rect_complex64 :: proc "contextless" (r, θ: f32) -> complex64 {
  353. s, c := math.sincos(θ)
  354. return complex(r*c, r*s)
  355. }
  356. rect_complex128 :: proc "contextless" (r, θ: f64) -> complex128 {
  357. s, c := math.sincos(θ)
  358. return complex(r*c, r*s)
  359. }
  360. polar_complex32 :: proc "contextless" (x: complex32) -> (r, θ: f16) {
  361. return abs(x), phase(x)
  362. }
  363. polar_complex64 :: proc "contextless" (x: complex64) -> (r, θ: f32) {
  364. return abs(x), phase(x)
  365. }
  366. polar_complex128 :: proc "contextless" (x: complex128) -> (r, θ: f64) {
  367. return abs(x), phase(x)
  368. }
  369. nan_complex32 :: proc "contextless" () -> complex32 {
  370. return complex(math.nan_f16(), math.nan_f16())
  371. }
  372. nan_complex64 :: proc "contextless" () -> complex64 {
  373. return complex(math.nan_f32(), math.nan_f32())
  374. }
  375. nan_complex128 :: proc "contextless" () -> complex128 {
  376. return complex(math.nan_f64(), math.nan_f64())
  377. }
  378. inf_complex32 :: proc "contextless" () -> complex32 {
  379. inf := math.inf_f16(1)
  380. return complex(inf, inf)
  381. }
  382. inf_complex64 :: proc "contextless" () -> complex64 {
  383. inf := math.inf_f32(1)
  384. return complex(inf, inf)
  385. }
  386. inf_complex128 :: proc "contextless" () -> complex128 {
  387. inf := math.inf_f64(1)
  388. return complex(inf, inf)
  389. }
  390. is_inf_complex32 :: proc "contextless" (x: complex32) -> bool {
  391. return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0)
  392. }
  393. is_inf_complex64 :: proc "contextless" (x: complex64) -> bool {
  394. return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0)
  395. }
  396. is_inf_complex128 :: proc "contextless" (x: complex128) -> bool {
  397. return math.is_inf(real(x), 0) || math.is_inf(imag(x), 0)
  398. }
  399. is_nan_complex32 :: proc "contextless" (x: complex32) -> bool {
  400. if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) {
  401. return false
  402. }
  403. return math.is_nan(real(x)) || math.is_nan(imag(x))
  404. }
  405. is_nan_complex64 :: proc "contextless" (x: complex64) -> bool {
  406. if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) {
  407. return false
  408. }
  409. return math.is_nan(real(x)) || math.is_nan(imag(x))
  410. }
  411. is_nan_complex128 :: proc "contextless" (x: complex128) -> bool {
  412. if math.is_inf(real(x), 0) || math.is_inf(imag(x), 0) {
  413. return false
  414. }
  415. return math.is_nan(real(x)) || math.is_nan(imag(x))
  416. }