bessel_jy_series.hpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. // Copyright (c) 2011 John Maddock
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_BESSEL_JN_SERIES_HPP
  6. #define BOOST_MATH_BESSEL_JN_SERIES_HPP
  7. #ifdef _MSC_VER
  8. #pragma once
  9. #endif
  10. #include <cmath>
  11. #include <cstdint>
  12. #include <boost/math/tools/config.hpp>
  13. #include <boost/math/tools/assert.hpp>
  14. namespace boost { namespace math { namespace detail{
  15. template <class T, class Policy>
  16. struct bessel_j_small_z_series_term
  17. {
  18. typedef T result_type;
  19. bessel_j_small_z_series_term(T v_, T x)
  20. : N(0), v(v_)
  21. {
  22. BOOST_MATH_STD_USING
  23. mult = x / 2;
  24. mult *= -mult;
  25. term = 1;
  26. }
  27. T operator()()
  28. {
  29. T r = term;
  30. ++N;
  31. term *= mult / (N * (N + v));
  32. return r;
  33. }
  34. private:
  35. unsigned N;
  36. T v;
  37. T mult;
  38. T term;
  39. };
  40. //
  41. // Series evaluation for BesselJ(v, z) as z -> 0.
  42. // See http://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/06/01/04/01/01/0003/
  43. // Converges rapidly for all z << v.
  44. //
  45. template <class T, class Policy>
  46. inline T bessel_j_small_z_series(T v, T x, const Policy& pol)
  47. {
  48. BOOST_MATH_STD_USING
  49. T prefix;
  50. if(v < max_factorial<T>::value)
  51. {
  52. prefix = pow(x / 2, v) / boost::math::tgamma(v+1, pol);
  53. }
  54. else
  55. {
  56. prefix = v * log(x / 2) - boost::math::lgamma(v+1, pol);
  57. prefix = exp(prefix);
  58. }
  59. if(0 == prefix)
  60. return prefix;
  61. bessel_j_small_z_series_term<T, Policy> s(v, x);
  62. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  63. T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
  64. policies::check_series_iterations<T>("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
  65. return prefix * result;
  66. }
  67. template <class T, class Policy>
  68. struct bessel_y_small_z_series_term_a
  69. {
  70. typedef T result_type;
  71. bessel_y_small_z_series_term_a(T v_, T x)
  72. : N(0), v(v_)
  73. {
  74. BOOST_MATH_STD_USING
  75. mult = x / 2;
  76. mult *= -mult;
  77. term = 1;
  78. }
  79. T operator()()
  80. {
  81. BOOST_MATH_STD_USING
  82. T r = term;
  83. ++N;
  84. term *= mult / (N * (N - v));
  85. return r;
  86. }
  87. private:
  88. unsigned N;
  89. T v;
  90. T mult;
  91. T term;
  92. };
  93. template <class T, class Policy>
  94. struct bessel_y_small_z_series_term_b
  95. {
  96. typedef T result_type;
  97. bessel_y_small_z_series_term_b(T v_, T x)
  98. : N(0), v(v_)
  99. {
  100. BOOST_MATH_STD_USING
  101. mult = x / 2;
  102. mult *= -mult;
  103. term = 1;
  104. }
  105. T operator()()
  106. {
  107. T r = term;
  108. ++N;
  109. term *= mult / (N * (N + v));
  110. return r;
  111. }
  112. private:
  113. unsigned N;
  114. T v;
  115. T mult;
  116. T term;
  117. };
  118. //
  119. // Series form for BesselY as z -> 0,
  120. // see: http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/01/0003/
  121. // This series is only useful when the second term is small compared to the first
  122. // otherwise we get catastrophic cancellation errors.
  123. //
  124. // Approximating tgamma(v) by v^v, and assuming |tgamma(-z)| < eps we end up requiring:
  125. // eps/2 * v^v(x/2)^-v > (x/2)^v or log(eps/2) > v log((x/2)^2/v)
  126. //
  127. template <class T, class Policy>
  128. inline T bessel_y_small_z_series(T v, T x, T* pscale, const Policy& pol)
  129. {
  130. BOOST_MATH_STD_USING
  131. static const char* function = "bessel_y_small_z_series<%1%>(%1%,%1%)";
  132. T prefix;
  133. T gam;
  134. T p = log(x / 2);
  135. T scale = 1;
  136. bool need_logs = (v >= max_factorial<T>::value) || (tools::log_max_value<T>() / v < fabs(p));
  137. if(!need_logs)
  138. {
  139. gam = boost::math::tgamma(v, pol);
  140. p = pow(x / 2, v);
  141. if(tools::max_value<T>() * p < gam)
  142. {
  143. scale /= gam;
  144. gam = 1;
  145. /*
  146. * We can never get here, it would require p < 1/max_value.
  147. if(tools::max_value<T>() * p < gam)
  148. {
  149. return -policies::raise_overflow_error<T>(function, nullptr, pol);
  150. }
  151. */
  152. }
  153. prefix = -gam / (constants::pi<T>() * p);
  154. }
  155. else
  156. {
  157. gam = boost::math::lgamma(v, pol);
  158. p = v * p;
  159. prefix = gam - log(constants::pi<T>()) - p;
  160. if(tools::log_max_value<T>() < prefix)
  161. {
  162. prefix -= log(tools::max_value<T>() / 4);
  163. scale /= (tools::max_value<T>() / 4);
  164. if(tools::log_max_value<T>() < prefix)
  165. {
  166. return -policies::raise_overflow_error<T>(function, nullptr, pol);
  167. }
  168. }
  169. prefix = -exp(prefix);
  170. }
  171. bessel_y_small_z_series_term_a<T, Policy> s(v, x);
  172. std::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  173. *pscale = scale;
  174. T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
  175. policies::check_series_iterations<T>("boost::math::bessel_y_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
  176. result *= prefix;
  177. if(!need_logs)
  178. {
  179. prefix = boost::math::tgamma(-v, pol) * boost::math::cos_pi(v, pol) * p / constants::pi<T>();
  180. }
  181. else
  182. {
  183. int sgn {};
  184. prefix = boost::math::lgamma(-v, &sgn, pol) + p;
  185. prefix = exp(prefix) * sgn / constants::pi<T>();
  186. }
  187. bessel_y_small_z_series_term_b<T, Policy> s2(v, x);
  188. max_iter = policies::get_max_series_iterations<Policy>();
  189. T b = boost::math::tools::sum_series(s2, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
  190. result -= scale * prefix * b;
  191. return result;
  192. }
  193. template <class T, class Policy>
  194. T bessel_yn_small_z(int n, T z, T* scale, const Policy& pol)
  195. {
  196. //
  197. // See http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/02/
  198. //
  199. // Note that when called we assume that x < epsilon and n is a positive integer.
  200. //
  201. BOOST_MATH_STD_USING
  202. BOOST_MATH_ASSERT(n >= 0);
  203. BOOST_MATH_ASSERT((z < policies::get_epsilon<T, Policy>()));
  204. if(n == 0)
  205. {
  206. return (2 / constants::pi<T>()) * (log(z / 2) + constants::euler<T>());
  207. }
  208. else if(n == 1)
  209. {
  210. return (z / constants::pi<T>()) * log(z / 2)
  211. - 2 / (constants::pi<T>() * z)
  212. - (z / (2 * constants::pi<T>())) * (1 - 2 * constants::euler<T>());
  213. }
  214. else if(n == 2)
  215. {
  216. return (z * z) / (4 * constants::pi<T>()) * log(z / 2)
  217. - (4 / (constants::pi<T>() * z * z))
  218. - ((z * z) / (8 * constants::pi<T>())) * (T(3)/2 - 2 * constants::euler<T>());
  219. }
  220. else
  221. {
  222. #if (defined(__GNUC__) && __GNUC__ == 13)
  223. auto p = static_cast<T>(pow(z / 2, T(n)));
  224. #else
  225. auto p = static_cast<T>(pow(z / 2, n));
  226. #endif
  227. T result = -((boost::math::factorial<T>(n - 1, pol) / constants::pi<T>()));
  228. if(p * tools::max_value<T>() < fabs(result))
  229. {
  230. T div = tools::max_value<T>() / 8;
  231. result /= div;
  232. *scale /= div;
  233. if(p * tools::max_value<T>() < result)
  234. {
  235. // Impossible to get here??
  236. return -policies::raise_overflow_error<T>("bessel_yn_small_z<%1%>(%1%,%1%)", nullptr, pol); // LCOV_EXCL_LINE
  237. }
  238. }
  239. return result / p;
  240. }
  241. }
  242. }}} // namespaces
  243. #endif // BOOST_MATH_BESSEL_JN_SERIES_HPP