bessel_jy_series.hpp 7.1 KB

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