hypergeometric_2F0.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2014 Anton Bikineev
  3. // Copyright 2014 Christopher Kormanyos
  4. // Copyright 2014 John Maddock
  5. // Copyright 2014 Paul Bristow
  6. // Distributed under the Boost
  7. // Software License, Version 1.0. (See accompanying file
  8. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. #ifndef BOOST_MATH_HYPERGEOMETRIC_2F0_HPP
  10. #define BOOST_MATH_HYPERGEOMETRIC_2F0_HPP
  11. #include <boost/math/policies/policy.hpp>
  12. #include <boost/math/policies/error_handling.hpp>
  13. #include <boost/math/special_functions/detail/hypergeometric_series.hpp>
  14. #include <boost/math/special_functions/laguerre.hpp>
  15. #include <boost/math/special_functions/hermite.hpp>
  16. #include <boost/math/tools/fraction.hpp>
  17. namespace boost { namespace math { namespace detail {
  18. template <class T>
  19. struct hypergeometric_2F0_cf
  20. {
  21. //
  22. // We start this continued fraction at b on index -1
  23. // and treat the -1 and 0 cases as special cases.
  24. // We do this to avoid adding the continued fraction result
  25. // to 1 so that we can accurately evaluate for small results
  26. // as well as large ones. See http://functions.wolfram.com/07.31.10.0002.01
  27. //
  28. T a1, a2, z;
  29. int k;
  30. hypergeometric_2F0_cf(T a1_, T a2_, T z_) : a1(a1_), a2(a2_), z(z_), k(-2) {}
  31. typedef std::pair<T, T> result_type;
  32. result_type operator()()
  33. {
  34. ++k;
  35. if (k <= 0)
  36. return std::make_pair(z * a1 * a2, 1);
  37. return std::make_pair(-z * (a1 + k) * (a2 + k) / (k + 1), 1 + z * (a1 + k) * (a2 + k) / (k + 1));
  38. }
  39. };
  40. template <class T, class Policy>
  41. T hypergeometric_2F0_cf_imp(T a1, T a2, T z, const Policy& pol, const char* function)
  42. {
  43. using namespace boost::math;
  44. hypergeometric_2F0_cf<T> evaluator(a1, a2, z);
  45. boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
  46. T cf = tools::continued_fraction_b(evaluator, policies::get_epsilon<T, Policy>(), max_iter);
  47. policies::check_series_iterations<T>(function, max_iter, pol);
  48. return cf;
  49. }
  50. template <class T, class Policy>
  51. inline T hypergeometric_2F0_imp(T a1, T a2, const T& z, const Policy& pol, bool asymptotic = false)
  52. {
  53. //
  54. // The terms in this series go to infinity unless one of a1 and a2 is a negative integer.
  55. //
  56. using std::swap;
  57. BOOST_MATH_STD_USING
  58. static const char* const function = "boost::math::hypergeometric_2F0<%1%,%1%,%1%>(%1%,%1%,%1%)";
  59. if (z == 0)
  60. return 1;
  61. bool is_a1_integer = (a1 == floor(a1));
  62. bool is_a2_integer = (a2 == floor(a2));
  63. if (!asymptotic && !is_a1_integer && !is_a2_integer)
  64. return boost::math::policies::raise_overflow_error<T>(function, 0, pol);
  65. if (!is_a1_integer || (a1 > 0))
  66. {
  67. swap(a1, a2);
  68. swap(is_a1_integer, is_a2_integer);
  69. }
  70. //
  71. // At this point a1 must be a negative integer:
  72. //
  73. if(!asymptotic && (!is_a1_integer || (a1 > 0)))
  74. return boost::math::policies::raise_overflow_error<T>(function, 0, pol);
  75. //
  76. // Special cases first:
  77. //
  78. if (a1 == 0)
  79. return 1;
  80. if ((a1 == a2 - 0.5f) && (z < 0))
  81. {
  82. // http://functions.wolfram.com/07.31.03.0083.01
  83. int n = static_cast<int>(static_cast<boost::uintmax_t>(boost::math::lltrunc(-2 * a1)));
  84. T smz = sqrt(-z);
  85. return pow(2 / smz, -n) * boost::math::hermite(n, 1 / smz, pol);
  86. }
  87. if (is_a1_integer && is_a2_integer)
  88. {
  89. if ((a1 < 1) && (a2 <= a1))
  90. {
  91. const unsigned int n = static_cast<unsigned int>(static_cast<boost::uintmax_t>(boost::math::lltrunc(-a1)));
  92. const unsigned int m = static_cast<unsigned int>(static_cast<boost::uintmax_t>(boost::math::lltrunc(-a2 - n)));
  93. return (pow(z, T(n)) * boost::math::factorial<T>(n, pol)) *
  94. boost::math::laguerre(n, m, -(1 / z), pol);
  95. }
  96. else if ((a2 < 1) && (a1 <= a2))
  97. {
  98. // function is symmetric for a1 and a2
  99. const unsigned int n = static_cast<unsigned int>(static_cast<boost::uintmax_t>(boost::math::lltrunc(-a2)));
  100. const unsigned int m = static_cast<unsigned int>(static_cast<boost::uintmax_t>(boost::math::lltrunc(-a1 - n)));
  101. return (pow(z, T(n)) * boost::math::factorial<T>(n, pol)) *
  102. boost::math::laguerre(n, m, -(1 / z), pol);
  103. }
  104. }
  105. if ((a1 * a2 * z < 0) && (a2 < -5) && (fabs(a1 * a2 * z) > 0.5))
  106. {
  107. // Series is alternating and maybe divergent at least for the first few terms
  108. // (until a2 goes positive), try the continued fraction:
  109. return hypergeometric_2F0_cf_imp(a1, a2, z, pol, function);
  110. }
  111. return detail::hypergeometric_2F0_generic_series(a1, a2, z, pol);
  112. }
  113. } // namespace detail
  114. template <class T1, class T2, class T3, class Policy>
  115. inline typename tools::promote_args<T1, T2, T3>::type hypergeometric_2F0(T1 a1, T2 a2, T3 z, const Policy& /* pol */)
  116. {
  117. BOOST_FPU_EXCEPTION_GUARD
  118. typedef typename tools::promote_args<T1, T2, T3>::type result_type;
  119. typedef typename policies::evaluation<result_type, Policy>::type value_type;
  120. typedef typename policies::normalise<
  121. Policy,
  122. policies::promote_float<false>,
  123. policies::promote_double<false>,
  124. policies::discrete_quantile<>,
  125. policies::assert_undefined<> >::type forwarding_policy;
  126. return policies::checked_narrowing_cast<result_type, Policy>(
  127. detail::hypergeometric_2F0_imp<value_type>(
  128. static_cast<value_type>(a1),
  129. static_cast<value_type>(a2),
  130. static_cast<value_type>(z),
  131. forwarding_policy()),
  132. "boost::math::hypergeometric_2F0<%1%>(%1%,%1%,%1%)");
  133. }
  134. template <class T1, class T2, class T3>
  135. inline typename tools::promote_args<T1, T2, T3>::type hypergeometric_2F0(T1 a1, T2 a2, T3 z)
  136. {
  137. return hypergeometric_2F0(a1, a2, z, policies::policy<>());
  138. }
  139. } } // namespace boost::math
  140. #endif // BOOST_MATH_HYPERGEOMETRIC_HPP