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