cmplx_invtrig.odin 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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. acos :: proc{
  26. acos_complex32,
  27. acos_complex64,
  28. acos_complex128,
  29. }
  30. acosh :: proc{
  31. acosh_complex32,
  32. acosh_complex64,
  33. acosh_complex128,
  34. }
  35. asin :: proc{
  36. asin_complex32,
  37. asin_complex64,
  38. asin_complex128,
  39. }
  40. asinh :: proc{
  41. asinh_complex32,
  42. asinh_complex64,
  43. asinh_complex128,
  44. }
  45. atan :: proc{
  46. atan_complex32,
  47. atan_complex64,
  48. atan_complex128,
  49. }
  50. atanh :: proc{
  51. atanh_complex32,
  52. atanh_complex64,
  53. atanh_complex128,
  54. }
  55. acos_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  56. return complex32(acos_complex64(complex64(x)))
  57. }
  58. acos_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  59. w := asin(x)
  60. return complex(math.PI/2 - real(w), -imag(w))
  61. }
  62. acos_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  63. w := asin(x)
  64. return complex(math.PI/2 - real(w), -imag(w))
  65. }
  66. acosh_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  67. return complex32(acosh_complex64(complex64(x)))
  68. }
  69. acosh_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  70. if x == 0 {
  71. return complex(0, math.copy_sign(math.PI/2, imag(x)))
  72. }
  73. w := acos(x)
  74. if imag(w) <= 0 {
  75. return complex(-imag(w), real(w))
  76. }
  77. return complex(imag(w), -real(w))
  78. }
  79. acosh_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  80. if x == 0 {
  81. return complex(0, math.copy_sign(math.PI/2, imag(x)))
  82. }
  83. w := acos(x)
  84. if imag(w) <= 0 {
  85. return complex(-imag(w), real(w))
  86. }
  87. return complex(imag(w), -real(w))
  88. }
  89. asin_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  90. return complex32(asin_complex128(complex128(x)))
  91. }
  92. asin_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  93. return complex64(asin_complex128(complex128(x)))
  94. }
  95. asin_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  96. switch re, im := real(x), imag(x); {
  97. case im == 0 && abs(re) <= 1:
  98. return complex(math.asin(re), im)
  99. case re == 0 && abs(im) <= 1:
  100. return complex(re, math.asinh(im))
  101. case math.is_nan(im):
  102. switch {
  103. case re == 0:
  104. return complex(re, math.nan_f64())
  105. case math.is_inf(re, 0):
  106. return complex(math.nan_f64(), re)
  107. case:
  108. return nan_complex128()
  109. }
  110. case math.is_inf(im, 0):
  111. switch {
  112. case math.is_nan(re):
  113. return x
  114. case math.is_inf(re, 0):
  115. return complex(math.copy_sign(math.PI/4, re), im)
  116. case:
  117. return complex(math.copy_sign(0, re), im)
  118. }
  119. case math.is_inf(re, 0):
  120. return complex(math.copy_sign(math.PI/2, re), math.copy_sign(re, im))
  121. }
  122. ct := complex(-imag(x), real(x)) // i * x
  123. xx := x * x
  124. x1 := complex(1-real(xx), -imag(xx)) // 1 - x*x
  125. x2 := sqrt(x1) // x2 = sqrt(1 - x*x)
  126. w := ln(ct + x2)
  127. return complex(imag(w), -real(w)) // -i * w
  128. }
  129. asinh_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  130. return complex32(asinh_complex128(complex128(x)))
  131. }
  132. asinh_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  133. return complex64(asinh_complex128(complex128(x)))
  134. }
  135. asinh_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  136. switch re, im := real(x), imag(x); {
  137. case im == 0 && abs(re) <= 1:
  138. return complex(math.asinh(re), im)
  139. case re == 0 && abs(im) <= 1:
  140. return complex(re, math.asin(im))
  141. case math.is_inf(re, 0):
  142. switch {
  143. case math.is_inf(im, 0):
  144. return complex(re, math.copy_sign(math.PI/4, im))
  145. case math.is_nan(im):
  146. return x
  147. case:
  148. return complex(re, math.copy_sign(0.0, im))
  149. }
  150. case math.is_nan(re):
  151. switch {
  152. case im == 0:
  153. return x
  154. case math.is_inf(im, 0):
  155. return complex(im, re)
  156. case:
  157. return nan_complex128()
  158. }
  159. case math.is_inf(im, 0):
  160. return complex(math.copy_sign(im, re), math.copy_sign(math.PI/2, im))
  161. }
  162. xx := x * x
  163. x1 := complex(1+real(xx), imag(xx)) // 1 + x*x
  164. return ln(x + sqrt(x1)) // log(x + sqrt(1 + x*x))
  165. }
  166. atan_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  167. return complex32(atan_complex128(complex128(x)))
  168. }
  169. atan_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  170. return complex64(atan_complex128(complex128(x)))
  171. }
  172. atan_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  173. // Complex circular arc tangent
  174. //
  175. // DESCRIPTION:
  176. //
  177. // If
  178. // z = x + iy,
  179. //
  180. // then
  181. // 1 ( 2x )
  182. // Re w = - arctan(-----------) + k PI
  183. // 2 ( 2 2)
  184. // (1 - x - y )
  185. //
  186. // ( 2 2)
  187. // 1 (x + (y+1) )
  188. // Im w = - log(------------)
  189. // 4 ( 2 2)
  190. // (x + (y-1) )
  191. //
  192. // Where k is an arbitrary integer.
  193. //
  194. // catan(z) = -i catanh(iz).
  195. //
  196. // ACCURACY:
  197. //
  198. // Relative error:
  199. // arithmetic domain # trials peak rms
  200. // DEC -10,+10 5900 1.3e-16 7.8e-18
  201. // IEEE -10,+10 30000 2.3e-15 8.5e-17
  202. // The check catan( ctan(z) ) = z, with |x| and |y| < PI/2,
  203. // had peak relative error 1.5e-16, rms relative error
  204. // 2.9e-17. See also clog().
  205. switch re, im := real(x), imag(x); {
  206. case im == 0:
  207. return complex(math.atan(re), im)
  208. case re == 0 && abs(im) <= 1:
  209. return complex(re, math.atanh(im))
  210. case math.is_inf(im, 0) || math.is_inf(re, 0):
  211. if math.is_nan(re) {
  212. return complex(math.nan_f64(), math.copy_sign(0, im))
  213. }
  214. return complex(math.copy_sign(math.PI/2, re), math.copy_sign(0, im))
  215. case math.is_nan(re) || math.is_nan(im):
  216. return nan_complex128()
  217. }
  218. x2 := real(x) * real(x)
  219. a := 1 - x2 - imag(x)*imag(x)
  220. if a == 0 {
  221. return nan_complex128()
  222. }
  223. t := 0.5 * math.atan2(2*real(x), a)
  224. w := _reduce_pi_f64(t)
  225. t = imag(x) - 1
  226. b := x2 + t*t
  227. if b == 0 {
  228. return nan_complex128()
  229. }
  230. t = imag(x) + 1
  231. c := (x2 + t*t) / b
  232. return complex(w, 0.25*math.ln(c))
  233. }
  234. atanh_complex32 :: proc "contextless" (x: complex32) -> complex32 {
  235. return complex32(atanh_complex64(complex64(x)))
  236. }
  237. atanh_complex64 :: proc "contextless" (x: complex64) -> complex64 {
  238. z := complex(-imag(x), real(x)) // z = i * x
  239. z = atan(z)
  240. return complex(imag(z), -real(z)) // z = -i * z
  241. }
  242. atanh_complex128 :: proc "contextless" (x: complex128) -> complex128 {
  243. z := complex(-imag(x), real(x)) // z = i * x
  244. z = atan(z)
  245. return complex(imag(z), -real(z)) // z = -i * z
  246. }