airy.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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_AIRY_HPP
  7. #define BOOST_MATH_AIRY_HPP
  8. #include <boost/math/special_functions/bessel.hpp>
  9. #include <boost/math/special_functions/cbrt.hpp>
  10. #include <boost/math/special_functions/detail/airy_ai_bi_zero.hpp>
  11. #include <boost/math/tools/roots.hpp>
  12. namespace boost{ namespace math{
  13. namespace detail{
  14. template <class T, class Policy>
  15. T airy_ai_imp(T x, const Policy& pol)
  16. {
  17. BOOST_MATH_STD_USING
  18. if(x < 0)
  19. {
  20. T p = (-x * sqrt(-x) * 2) / 3;
  21. T v = T(1) / 3;
  22. T j1 = boost::math::cyl_bessel_j(v, p, pol);
  23. T j2 = boost::math::cyl_bessel_j(-v, p, pol);
  24. T ai = sqrt(-x) * (j1 + j2) / 3;
  25. //T bi = sqrt(-x / 3) * (j2 - j1);
  26. return ai;
  27. }
  28. else if(fabs(x * x * x) / 6 < tools::epsilon<T>())
  29. {
  30. T tg = boost::math::tgamma(constants::twothirds<T>(), pol);
  31. T ai = 1 / (pow(T(3), constants::twothirds<T>()) * tg);
  32. //T bi = 1 / (sqrt(boost::math::cbrt(T(3))) * tg);
  33. return ai;
  34. }
  35. else
  36. {
  37. T p = 2 * x * sqrt(x) / 3;
  38. T v = T(1) / 3;
  39. //T j1 = boost::math::cyl_bessel_i(-v, p, pol);
  40. //T j2 = boost::math::cyl_bessel_i(v, p, pol);
  41. //
  42. // Note that although we can calculate ai from j1 and j2, the accuracy is horrible
  43. // as we're subtracting two very large values, so use the Bessel K relation instead:
  44. //
  45. T ai = cyl_bessel_k(v, p, pol) * sqrt(x / 3) / boost::math::constants::pi<T>(); //sqrt(x) * (j1 - j2) / 3;
  46. //T bi = sqrt(x / 3) * (j1 + j2);
  47. return ai;
  48. }
  49. }
  50. template <class T, class Policy>
  51. T airy_bi_imp(T x, const Policy& pol)
  52. {
  53. BOOST_MATH_STD_USING
  54. if(x < 0)
  55. {
  56. T p = (-x * sqrt(-x) * 2) / 3;
  57. T v = T(1) / 3;
  58. T j1 = boost::math::cyl_bessel_j(v, p, pol);
  59. T j2 = boost::math::cyl_bessel_j(-v, p, pol);
  60. //T ai = sqrt(-x) * (j1 + j2) / 3;
  61. T bi = sqrt(-x / 3) * (j2 - j1);
  62. return bi;
  63. }
  64. else if(fabs(x * x * x) / 6 < tools::epsilon<T>())
  65. {
  66. T tg = boost::math::tgamma(constants::twothirds<T>(), pol);
  67. //T ai = 1 / (pow(T(3), constants::twothirds<T>()) * tg);
  68. T bi = 1 / (sqrt(boost::math::cbrt(T(3))) * tg);
  69. return bi;
  70. }
  71. else
  72. {
  73. T p = 2 * x * sqrt(x) / 3;
  74. T v = T(1) / 3;
  75. T j1 = boost::math::cyl_bessel_i(-v, p, pol);
  76. T j2 = boost::math::cyl_bessel_i(v, p, pol);
  77. T bi = sqrt(x / 3) * (j1 + j2);
  78. return bi;
  79. }
  80. }
  81. template <class T, class Policy>
  82. T airy_ai_prime_imp(T x, const Policy& pol)
  83. {
  84. BOOST_MATH_STD_USING
  85. if(x < 0)
  86. {
  87. T p = (-x * sqrt(-x) * 2) / 3;
  88. T v = T(2) / 3;
  89. T j1 = boost::math::cyl_bessel_j(v, p, pol);
  90. T j2 = boost::math::cyl_bessel_j(-v, p, pol);
  91. T aip = -x * (j1 - j2) / 3;
  92. return aip;
  93. }
  94. else if(fabs(x * x) / 2 < tools::epsilon<T>())
  95. {
  96. T tg = boost::math::tgamma(constants::third<T>(), pol);
  97. T aip = 1 / (boost::math::cbrt(T(3)) * tg);
  98. return -aip;
  99. }
  100. else
  101. {
  102. T p = 2 * x * sqrt(x) / 3;
  103. T v = T(2) / 3;
  104. //T j1 = boost::math::cyl_bessel_i(-v, p, pol);
  105. //T j2 = boost::math::cyl_bessel_i(v, p, pol);
  106. //
  107. // Note that although we can calculate ai from j1 and j2, the accuracy is horrible
  108. // as we're subtracting two very large values, so use the Bessel K relation instead:
  109. //
  110. T aip = -cyl_bessel_k(v, p, pol) * x / (boost::math::constants::root_three<T>() * boost::math::constants::pi<T>());
  111. return aip;
  112. }
  113. }
  114. template <class T, class Policy>
  115. T airy_bi_prime_imp(T x, const Policy& pol)
  116. {
  117. BOOST_MATH_STD_USING
  118. if(x < 0)
  119. {
  120. T p = (-x * sqrt(-x) * 2) / 3;
  121. T v = T(2) / 3;
  122. T j1 = boost::math::cyl_bessel_j(v, p, pol);
  123. T j2 = boost::math::cyl_bessel_j(-v, p, pol);
  124. T aip = -x * (j1 + j2) / constants::root_three<T>();
  125. return aip;
  126. }
  127. else if(fabs(x * x) / 2 < tools::epsilon<T>())
  128. {
  129. T tg = boost::math::tgamma(constants::third<T>(), pol);
  130. T bip = sqrt(boost::math::cbrt(T(3))) / tg;
  131. return bip;
  132. }
  133. else
  134. {
  135. T p = 2 * x * sqrt(x) / 3;
  136. T v = T(2) / 3;
  137. T j1 = boost::math::cyl_bessel_i(-v, p, pol);
  138. T j2 = boost::math::cyl_bessel_i(v, p, pol);
  139. T aip = x * (j1 + j2) / boost::math::constants::root_three<T>();
  140. return aip;
  141. }
  142. }
  143. template <class T, class Policy>
  144. T airy_ai_zero_imp(unsigned m, const Policy& pol)
  145. {
  146. BOOST_MATH_STD_USING // ADL of std names, needed for log, sqrt.
  147. // Handle case when the zero'th zero is requested.
  148. if(m == 0U)
  149. {
  150. return policies::raise_domain_error<T>("boost::math::airy_ai_zero<%1%>(%1%,%1%)",
  151. "The requested rank of the zero is %1%, but must be 1 or more !", static_cast<T>(m), pol);
  152. }
  153. // Set up the initial guess for the upcoming root-finding.
  154. const T guess_root = boost::math::detail::airy_zero::airy_ai_zero_detail::initial_guess<T>(m);
  155. // Select the maximum allowed iterations, being at least 24.
  156. boost::uintmax_t number_of_iterations = (std::max)(24, int(std::numeric_limits<T>::digits10));
  157. // Select the desired number of binary digits of precision.
  158. // Account for the radix of number representations having non-two radix!
  159. const int my_digits2 = int(float(std::numeric_limits<T>::digits)
  160. * ( log(float(std::numeric_limits<T>::radix))
  161. / log(2.0F)));
  162. // Use a dynamic tolerance because the roots get closer the higher m gets.
  163. T tolerance;
  164. if (m <= 10U) { tolerance = T(0.3F); }
  165. else if(m <= 100U) { tolerance = T(0.1F); }
  166. else if(m <= 1000U) { tolerance = T(0.05F); }
  167. else { tolerance = T(1) / sqrt(T(m)); }
  168. // Perform the root-finding using Newton-Raphson iteration from Boost.Math.
  169. const T am =
  170. boost::math::tools::newton_raphson_iterate(
  171. boost::math::detail::airy_zero::airy_ai_zero_detail::function_object_ai_and_ai_prime<T, Policy>(pol),
  172. guess_root,
  173. T(guess_root - tolerance),
  174. T(guess_root + tolerance),
  175. my_digits2,
  176. number_of_iterations);
  177. static_cast<void>(number_of_iterations);
  178. return am;
  179. }
  180. template <class T, class Policy>
  181. T airy_bi_zero_imp(unsigned m, const Policy& pol)
  182. {
  183. BOOST_MATH_STD_USING // ADL of std names, needed for log, sqrt.
  184. // Handle case when the zero'th zero is requested.
  185. if(m == 0U)
  186. {
  187. return policies::raise_domain_error<T>("boost::math::airy_bi_zero<%1%>(%1%,%1%)",
  188. "The requested rank of the zero is %1%, but must be 1 or more !", static_cast<T>(m), pol);
  189. }
  190. // Set up the initial guess for the upcoming root-finding.
  191. const T guess_root = boost::math::detail::airy_zero::airy_bi_zero_detail::initial_guess<T>(m);
  192. // Select the maximum allowed iterations, being at least 24.
  193. boost::uintmax_t number_of_iterations = (std::max)(24, int(std::numeric_limits<T>::digits10));
  194. // Select the desired number of binary digits of precision.
  195. // Account for the radix of number representations having non-two radix!
  196. const int my_digits2 = int(float(std::numeric_limits<T>::digits)
  197. * ( log(float(std::numeric_limits<T>::radix))
  198. / log(2.0F)));
  199. // Use a dynamic tolerance because the roots get closer the higher m gets.
  200. T tolerance;
  201. if (m <= 10U) { tolerance = T(0.3F); }
  202. else if(m <= 100U) { tolerance = T(0.1F); }
  203. else if(m <= 1000U) { tolerance = T(0.05F); }
  204. else { tolerance = T(1) / sqrt(T(m)); }
  205. // Perform the root-finding using Newton-Raphson iteration from Boost.Math.
  206. const T bm =
  207. boost::math::tools::newton_raphson_iterate(
  208. boost::math::detail::airy_zero::airy_bi_zero_detail::function_object_bi_and_bi_prime<T, Policy>(pol),
  209. guess_root,
  210. T(guess_root - tolerance),
  211. T(guess_root + tolerance),
  212. my_digits2,
  213. number_of_iterations);
  214. static_cast<void>(number_of_iterations);
  215. return bm;
  216. }
  217. } // namespace detail
  218. template <class T, class Policy>
  219. inline typename tools::promote_args<T>::type airy_ai(T x, const Policy&)
  220. {
  221. BOOST_FPU_EXCEPTION_GUARD
  222. typedef typename tools::promote_args<T>::type result_type;
  223. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  224. typedef typename policies::normalise<
  225. Policy,
  226. policies::promote_float<false>,
  227. policies::promote_double<false>,
  228. policies::discrete_quantile<>,
  229. policies::assert_undefined<> >::type forwarding_policy;
  230. return policies::checked_narrowing_cast<result_type, Policy>(detail::airy_ai_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
  231. }
  232. template <class T>
  233. inline typename tools::promote_args<T>::type airy_ai(T x)
  234. {
  235. return airy_ai(x, policies::policy<>());
  236. }
  237. template <class T, class Policy>
  238. inline typename tools::promote_args<T>::type airy_bi(T x, const Policy&)
  239. {
  240. BOOST_FPU_EXCEPTION_GUARD
  241. typedef typename tools::promote_args<T>::type result_type;
  242. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  243. typedef typename policies::normalise<
  244. Policy,
  245. policies::promote_float<false>,
  246. policies::promote_double<false>,
  247. policies::discrete_quantile<>,
  248. policies::assert_undefined<> >::type forwarding_policy;
  249. return policies::checked_narrowing_cast<result_type, Policy>(detail::airy_bi_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
  250. }
  251. template <class T>
  252. inline typename tools::promote_args<T>::type airy_bi(T x)
  253. {
  254. return airy_bi(x, policies::policy<>());
  255. }
  256. template <class T, class Policy>
  257. inline typename tools::promote_args<T>::type airy_ai_prime(T x, const Policy&)
  258. {
  259. BOOST_FPU_EXCEPTION_GUARD
  260. typedef typename tools::promote_args<T>::type result_type;
  261. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  262. typedef typename policies::normalise<
  263. Policy,
  264. policies::promote_float<false>,
  265. policies::promote_double<false>,
  266. policies::discrete_quantile<>,
  267. policies::assert_undefined<> >::type forwarding_policy;
  268. return policies::checked_narrowing_cast<result_type, Policy>(detail::airy_ai_prime_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
  269. }
  270. template <class T>
  271. inline typename tools::promote_args<T>::type airy_ai_prime(T x)
  272. {
  273. return airy_ai_prime(x, policies::policy<>());
  274. }
  275. template <class T, class Policy>
  276. inline typename tools::promote_args<T>::type airy_bi_prime(T x, const Policy&)
  277. {
  278. BOOST_FPU_EXCEPTION_GUARD
  279. typedef typename tools::promote_args<T>::type result_type;
  280. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  281. typedef typename policies::normalise<
  282. Policy,
  283. policies::promote_float<false>,
  284. policies::promote_double<false>,
  285. policies::discrete_quantile<>,
  286. policies::assert_undefined<> >::type forwarding_policy;
  287. return policies::checked_narrowing_cast<result_type, Policy>(detail::airy_bi_prime_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
  288. }
  289. template <class T>
  290. inline typename tools::promote_args<T>::type airy_bi_prime(T x)
  291. {
  292. return airy_bi_prime(x, policies::policy<>());
  293. }
  294. template <class T, class Policy>
  295. inline T airy_ai_zero(unsigned m, const Policy& /*pol*/)
  296. {
  297. BOOST_FPU_EXCEPTION_GUARD
  298. typedef typename policies::evaluation<T, Policy>::type value_type;
  299. typedef typename policies::normalise<
  300. Policy,
  301. policies::promote_float<false>,
  302. policies::promote_double<false>,
  303. policies::discrete_quantile<>,
  304. policies::assert_undefined<> >::type forwarding_policy;
  305. BOOST_STATIC_ASSERT_MSG(false == std::numeric_limits<T>::is_integer, "Airy return type must be a floating-point type.");
  306. return policies::checked_narrowing_cast<T, Policy>(detail::airy_ai_zero_imp<value_type>(m, forwarding_policy()), "boost::math::airy_ai_zero<%1%>(unsigned)");
  307. }
  308. template <class T>
  309. inline T airy_ai_zero(unsigned m)
  310. {
  311. return airy_ai_zero<T>(m, policies::policy<>());
  312. }
  313. template <class T, class OutputIterator, class Policy>
  314. inline OutputIterator airy_ai_zero(
  315. unsigned start_index,
  316. unsigned number_of_zeros,
  317. OutputIterator out_it,
  318. const Policy& pol)
  319. {
  320. typedef T result_type;
  321. BOOST_STATIC_ASSERT_MSG(false == std::numeric_limits<result_type>::is_integer, "Airy return type must be a floating-point type.");
  322. for(unsigned i = 0; i < number_of_zeros; ++i)
  323. {
  324. *out_it = boost::math::airy_ai_zero<result_type>(start_index + i, pol);
  325. ++out_it;
  326. }
  327. return out_it;
  328. }
  329. template <class T, class OutputIterator>
  330. inline OutputIterator airy_ai_zero(
  331. unsigned start_index,
  332. unsigned number_of_zeros,
  333. OutputIterator out_it)
  334. {
  335. return airy_ai_zero<T>(start_index, number_of_zeros, out_it, policies::policy<>());
  336. }
  337. template <class T, class Policy>
  338. inline T airy_bi_zero(unsigned m, const Policy& /*pol*/)
  339. {
  340. BOOST_FPU_EXCEPTION_GUARD
  341. typedef typename policies::evaluation<T, Policy>::type value_type;
  342. typedef typename policies::normalise<
  343. Policy,
  344. policies::promote_float<false>,
  345. policies::promote_double<false>,
  346. policies::discrete_quantile<>,
  347. policies::assert_undefined<> >::type forwarding_policy;
  348. BOOST_STATIC_ASSERT_MSG(false == std::numeric_limits<T>::is_integer, "Airy return type must be a floating-point type.");
  349. return policies::checked_narrowing_cast<T, Policy>(detail::airy_bi_zero_imp<value_type>(m, forwarding_policy()), "boost::math::airy_bi_zero<%1%>(unsigned)");
  350. }
  351. template <typename T>
  352. inline T airy_bi_zero(unsigned m)
  353. {
  354. return airy_bi_zero<T>(m, policies::policy<>());
  355. }
  356. template <class T, class OutputIterator, class Policy>
  357. inline OutputIterator airy_bi_zero(
  358. unsigned start_index,
  359. unsigned number_of_zeros,
  360. OutputIterator out_it,
  361. const Policy& pol)
  362. {
  363. typedef T result_type;
  364. BOOST_STATIC_ASSERT_MSG(false == std::numeric_limits<result_type>::is_integer, "Airy return type must be a floating-point type.");
  365. for(unsigned i = 0; i < number_of_zeros; ++i)
  366. {
  367. *out_it = boost::math::airy_bi_zero<result_type>(start_index + i, pol);
  368. ++out_it;
  369. }
  370. return out_it;
  371. }
  372. template <class T, class OutputIterator>
  373. inline OutputIterator airy_bi_zero(
  374. unsigned start_index,
  375. unsigned number_of_zeros,
  376. OutputIterator out_it)
  377. {
  378. return airy_bi_zero<T>(start_index, number_of_zeros, out_it, policies::policy<>());
  379. }
  380. }} // namespaces
  381. #endif // BOOST_MATH_AIRY_HPP