jacobi_elliptic.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. // Copyright John Maddock 2012.
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_MATH_JACOBI_ELLIPTIC_HPP
  7. #define BOOST_MATH_JACOBI_ELLIPTIC_HPP
  8. #include <boost/math/tools/precision.hpp>
  9. #include <boost/math/tools/promotion.hpp>
  10. #include <boost/math/policies/error_handling.hpp>
  11. #include <boost/math/special_functions/math_fwd.hpp>
  12. namespace boost{ namespace math{
  13. namespace detail{
  14. template <class T, class Policy>
  15. T jacobi_recurse(const T& x, const T& k, T anm1, T bnm1, unsigned N, T* pTn, const Policy& pol)
  16. {
  17. BOOST_MATH_STD_USING
  18. ++N;
  19. T Tn;
  20. T cn = (anm1 - bnm1) / 2;
  21. T an = (anm1 + bnm1) / 2;
  22. if(cn < policies::get_epsilon<T, Policy>())
  23. {
  24. Tn = ldexp(T(1), (int)N) * x * an;
  25. }
  26. else
  27. Tn = jacobi_recurse<T>(x, k, an, sqrt(anm1 * bnm1), N, 0, pol);
  28. if(pTn)
  29. *pTn = Tn;
  30. return (Tn + asin((cn / an) * sin(Tn))) / 2;
  31. }
  32. template <class T, class Policy>
  33. T jacobi_imp(const T& x, const T& k, T* cn, T* dn, const Policy& pol, const char* function)
  34. {
  35. BOOST_MATH_STD_USING
  36. if(k < 0)
  37. {
  38. *cn = policies::raise_domain_error<T>(function, "Modulus k must be positive but got %1%.", k, pol);
  39. *dn = *cn;
  40. return *cn;
  41. }
  42. if(k > 1)
  43. {
  44. T xp = x * k;
  45. T kp = 1 / k;
  46. T snp, cnp, dnp;
  47. snp = jacobi_imp(xp, kp, &cnp, &dnp, pol, function);
  48. *cn = dnp;
  49. *dn = cnp;
  50. return snp * kp;
  51. }
  52. //
  53. // Special cases first:
  54. //
  55. if(x == 0)
  56. {
  57. *cn = *dn = 1;
  58. return 0;
  59. }
  60. if(k == 0)
  61. {
  62. *cn = cos(x);
  63. *dn = 1;
  64. return sin(x);
  65. }
  66. if(k == 1)
  67. {
  68. *cn = *dn = 1 / cosh(x);
  69. return tanh(x);
  70. }
  71. //
  72. // Asymptotic forms from A&S 16.13:
  73. //
  74. if(k < tools::forth_root_epsilon<T>())
  75. {
  76. T su = sin(x);
  77. T cu = cos(x);
  78. T m = k * k;
  79. *dn = 1 - m * su * su / 2;
  80. *cn = cu + m * (x - su * cu) * su / 4;
  81. return su - m * (x - su * cu) * cu / 4;
  82. }
  83. /* Can't get this to work to adequate precision - disabled for now...
  84. //
  85. // Asymptotic forms from A&S 16.15:
  86. //
  87. if(k > 1 - tools::root_epsilon<T>())
  88. {
  89. T tu = tanh(x);
  90. T su = sinh(x);
  91. T cu = cosh(x);
  92. T sec = 1 / cu;
  93. T kp = 1 - k;
  94. T m1 = 2 * kp - kp * kp;
  95. *dn = sec + m1 * (su * cu + x) * tu * sec / 4;
  96. *cn = sec - m1 * (su * cu - x) * tu * sec / 4;
  97. T sn = tu;
  98. T sn2 = m1 * (x * sec * sec - tu) / 4;
  99. T sn3 = (72 * x * cu + 4 * (8 * x * x - 5) * su - 19 * sinh(3 * x) + sinh(5 * x)) * sec * sec * sec * m1 * m1 / 512;
  100. return sn + sn2 - sn3;
  101. }*/
  102. T T1;
  103. T kc = 1 - k;
  104. T k_prime = k < T(0.5) ? T(sqrt(1 - k * k)) : T(sqrt(2 * kc - kc * kc));
  105. T T0 = jacobi_recurse(x, k, T(1), k_prime, 0, &T1, pol);
  106. *cn = cos(T0);
  107. *dn = cos(T0) / cos(T1 - T0);
  108. return sin(T0);
  109. }
  110. } // namespace detail
  111. template <class T, class U, class V, class Policy>
  112. inline typename tools::promote_args<T, U, V>::type jacobi_elliptic(T k, U theta, V* pcn, V* pdn, const Policy&)
  113. {
  114. BOOST_FPU_EXCEPTION_GUARD
  115. typedef typename tools::promote_args<T>::type result_type;
  116. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  117. typedef typename policies::normalise<
  118. Policy,
  119. policies::promote_float<false>,
  120. policies::promote_double<false>,
  121. policies::discrete_quantile<>,
  122. policies::assert_undefined<> >::type forwarding_policy;
  123. static const char* function = "boost::math::jacobi_elliptic<%1%>(%1%)";
  124. value_type sn, cn, dn;
  125. sn = detail::jacobi_imp<value_type>(static_cast<value_type>(theta), static_cast<value_type>(k), &cn, &dn, forwarding_policy(), function);
  126. if(pcn)
  127. *pcn = policies::checked_narrowing_cast<result_type, Policy>(cn, function);
  128. if(pdn)
  129. *pdn = policies::checked_narrowing_cast<result_type, Policy>(dn, function);
  130. return policies::checked_narrowing_cast<result_type, Policy>(sn, function);
  131. }
  132. template <class T, class U, class V>
  133. inline typename tools::promote_args<T, U, V>::type jacobi_elliptic(T k, U theta, V* pcn, V* pdn)
  134. {
  135. return jacobi_elliptic(k, theta, pcn, pdn, policies::policy<>());
  136. }
  137. template <class U, class T, class Policy>
  138. inline typename tools::promote_args<T, U>::type jacobi_sn(U k, T theta, const Policy& pol)
  139. {
  140. typedef typename tools::promote_args<T, U>::type result_type;
  141. return jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(nullptr), static_cast<result_type*>(nullptr), pol);
  142. }
  143. template <class U, class T>
  144. inline typename tools::promote_args<T, U>::type jacobi_sn(U k, T theta)
  145. {
  146. return jacobi_sn(k, theta, policies::policy<>());
  147. }
  148. template <class T, class U, class Policy>
  149. inline typename tools::promote_args<T, U>::type jacobi_cn(T k, U theta, const Policy& pol)
  150. {
  151. typedef typename tools::promote_args<T, U>::type result_type;
  152. result_type cn;
  153. jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, static_cast<result_type*>(nullptr), pol);
  154. return cn;
  155. }
  156. template <class T, class U>
  157. inline typename tools::promote_args<T, U>::type jacobi_cn(T k, U theta)
  158. {
  159. return jacobi_cn(k, theta, policies::policy<>());
  160. }
  161. template <class T, class U, class Policy>
  162. inline typename tools::promote_args<T, U>::type jacobi_dn(T k, U theta, const Policy& pol)
  163. {
  164. typedef typename tools::promote_args<T, U>::type result_type;
  165. result_type dn;
  166. jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(nullptr), &dn, pol);
  167. return dn;
  168. }
  169. template <class T, class U>
  170. inline typename tools::promote_args<T, U>::type jacobi_dn(T k, U theta)
  171. {
  172. return jacobi_dn(k, theta, policies::policy<>());
  173. }
  174. template <class T, class U, class Policy>
  175. inline typename tools::promote_args<T, U>::type jacobi_cd(T k, U theta, const Policy& pol)
  176. {
  177. typedef typename tools::promote_args<T, U>::type result_type;
  178. result_type cn, dn;
  179. jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, &dn, pol);
  180. return cn / dn;
  181. }
  182. template <class T, class U>
  183. inline typename tools::promote_args<T, U>::type jacobi_cd(T k, U theta)
  184. {
  185. return jacobi_cd(k, theta, policies::policy<>());
  186. }
  187. template <class T, class U, class Policy>
  188. inline typename tools::promote_args<T, U>::type jacobi_dc(T k, U theta, const Policy& pol)
  189. {
  190. typedef typename tools::promote_args<T, U>::type result_type;
  191. result_type cn, dn;
  192. jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, &dn, pol);
  193. return dn / cn;
  194. }
  195. template <class T, class U>
  196. inline typename tools::promote_args<T, U>::type jacobi_dc(T k, U theta)
  197. {
  198. return jacobi_dc(k, theta, policies::policy<>());
  199. }
  200. template <class T, class U, class Policy>
  201. inline typename tools::promote_args<T, U>::type jacobi_ns(T k, U theta, const Policy& pol)
  202. {
  203. typedef typename tools::promote_args<T, U>::type result_type;
  204. return 1 / jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(nullptr), static_cast<result_type*>(nullptr), pol);
  205. }
  206. template <class T, class U>
  207. inline typename tools::promote_args<T, U>::type jacobi_ns(T k, U theta)
  208. {
  209. return jacobi_ns(k, theta, policies::policy<>());
  210. }
  211. template <class T, class U, class Policy>
  212. inline typename tools::promote_args<T, U>::type jacobi_sd(T k, U theta, const Policy& pol)
  213. {
  214. typedef typename tools::promote_args<T, U>::type result_type;
  215. result_type sn, dn;
  216. sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(nullptr), &dn, pol);
  217. return sn / dn;
  218. }
  219. template <class T, class U>
  220. inline typename tools::promote_args<T, U>::type jacobi_sd(T k, U theta)
  221. {
  222. return jacobi_sd(k, theta, policies::policy<>());
  223. }
  224. template <class T, class U, class Policy>
  225. inline typename tools::promote_args<T, U>::type jacobi_ds(T k, U theta, const Policy& pol)
  226. {
  227. typedef typename tools::promote_args<T, U>::type result_type;
  228. result_type sn, dn;
  229. sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(nullptr), &dn, pol);
  230. return dn / sn;
  231. }
  232. template <class T, class U>
  233. inline typename tools::promote_args<T, U>::type jacobi_ds(T k, U theta)
  234. {
  235. return jacobi_ds(k, theta, policies::policy<>());
  236. }
  237. template <class T, class U, class Policy>
  238. inline typename tools::promote_args<T, U>::type jacobi_nc(T k, U theta, const Policy& pol)
  239. {
  240. return 1 / jacobi_cn(k, theta, pol);
  241. }
  242. template <class T, class U>
  243. inline typename tools::promote_args<T, U>::type jacobi_nc(T k, U theta)
  244. {
  245. return jacobi_nc(k, theta, policies::policy<>());
  246. }
  247. template <class T, class U, class Policy>
  248. inline typename tools::promote_args<T, U>::type jacobi_nd(T k, U theta, const Policy& pol)
  249. {
  250. return 1 / jacobi_dn(k, theta, pol);
  251. }
  252. template <class T, class U>
  253. inline typename tools::promote_args<T, U>::type jacobi_nd(T k, U theta)
  254. {
  255. return jacobi_nd(k, theta, policies::policy<>());
  256. }
  257. template <class T, class U, class Policy>
  258. inline typename tools::promote_args<T, U>::type jacobi_sc(T k, U theta, const Policy& pol)
  259. {
  260. typedef typename tools::promote_args<T, U>::type result_type;
  261. result_type sn, cn;
  262. sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, static_cast<result_type*>(nullptr), pol);
  263. return sn / cn;
  264. }
  265. template <class T, class U>
  266. inline typename tools::promote_args<T, U>::type jacobi_sc(T k, U theta)
  267. {
  268. return jacobi_sc(k, theta, policies::policy<>());
  269. }
  270. template <class T, class U, class Policy>
  271. inline typename tools::promote_args<T, U>::type jacobi_cs(T k, U theta, const Policy& pol)
  272. {
  273. typedef typename tools::promote_args<T, U>::type result_type;
  274. result_type sn, cn;
  275. sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, static_cast<result_type*>(nullptr), pol);
  276. return cn / sn;
  277. }
  278. template <class T, class U>
  279. inline typename tools::promote_args<T, U>::type jacobi_cs(T k, U theta)
  280. {
  281. return jacobi_cs(k, theta, policies::policy<>());
  282. }
  283. }} // namespaces
  284. #endif // BOOST_MATH_JACOBI_ELLIPTIC_HPP