cmplx_invtrig.odin 7.2 KB

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