jacobi_elliptic.hpp 9.9 KB

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