123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179 |
- #ifndef BOOST_MATH_HYPERGEOMETRIC_ASYM_HPP
- #define BOOST_MATH_HYPERGEOMETRIC_ASYM_HPP
- #include <boost/math/special_functions/gamma.hpp>
- #include <boost/math/special_functions/hypergeometric_2F0.hpp>
- #ifdef _MSC_VER
- #pragma warning(push)
- #pragma warning(disable:4127)
- #endif
- namespace boost { namespace math {
- namespace detail {
-
-
-
-
-
-
- template <class T, class Policy>
- inline T hypergeometric_1F1_asym_large_z_series(T a, const T& b, T z, const Policy& pol, long long& log_scaling)
- {
- BOOST_MATH_STD_USING
- static const char* function = "boost::math::hypergeometric_1F1_asym_large_z_series<%1%>(%1%, %1%, %1%)";
- T prefix;
- long long e;
- int s;
- if (z < 0)
- {
- a = b - a;
- z = -z;
- prefix = 1;
- }
- else
- {
- e = z > static_cast<T>((std::numeric_limits<long long>::max)()) ? (std::numeric_limits<long long>::max)() : lltrunc(z, pol);
- log_scaling += e;
- prefix = exp(z - e);
- }
- if ((fabs(a) < 10) && (fabs(b) < 10))
- {
- prefix *= pow(z, a) * pow(z, -b) * boost::math::tgamma(b, pol) / boost::math::tgamma(a, pol);
- }
- else
- {
- T t = log(z) * (a - b);
- e = lltrunc(t, pol);
- log_scaling += e;
- prefix *= exp(t - e);
- t = boost::math::lgamma(b, &s, pol);
- e = lltrunc(t, pol);
- log_scaling += e;
- prefix *= s * exp(t - e);
- t = boost::math::lgamma(a, &s, pol);
- e = lltrunc(t, pol);
- log_scaling -= e;
- prefix /= s * exp(t - e);
- }
-
-
-
- unsigned k = 0;
- T a1_poch(1 - a);
- T a2_poch(b - a);
- T z_mult(1 / z);
- T sum = 0;
- T abs_sum = 0;
- T term = 1;
- T last_term = 0;
- do
- {
- sum += term;
- last_term = term;
- abs_sum += fabs(sum);
- term *= a1_poch * a2_poch * z_mult;
- term /= ++k;
- a1_poch += 1;
- a2_poch += 1;
- if (fabs(sum) * boost::math::policies::get_epsilon<T, Policy>() > fabs(term))
- break;
- if(fabs(sum) / abs_sum < boost::math::policies::get_epsilon<T, Policy>())
- return boost::math::policies::raise_evaluation_error<T>(function, "Large-z asymptotic approximation to 1F1 has destroyed all the digits in the result due to cancellation. Current best guess is %1%",
- prefix * sum, Policy());
- if(k > boost::math::policies::get_max_series_iterations<Policy>())
- return boost::math::policies::raise_evaluation_error<T>(function, "1F1: Unable to locate solution in a reasonable time:"
- " large-z asymptotic approximation. Current best guess is %1%", prefix * sum, Policy());
- if((k > 10) && (fabs(term) > fabs(last_term)))
- return boost::math::policies::raise_evaluation_error<T>(function, "Large-z asymptotic approximation to 1F1 is divergent. Current best guess is %1%", prefix * sum, Policy());
- } while (true);
- return prefix * sum;
- }
-
- template <class T, class Policy>
- inline bool hypergeometric_1F1_asym_region(const T& a, const T& b, const T& z, const Policy&)
- {
- BOOST_MATH_STD_USING
- int half_digits = policies::digits<T, Policy>() / 2;
- bool in_region = false;
- if (fabs(a) < 0.001f)
- return false;
-
-
-
-
-
-
-
- if (z > 0)
- {
- T one_minus_a = 1 - a;
- T b_minus_a = b - a;
- if (fabs((one_minus_a + half_digits) * (b_minus_a + half_digits) / (half_digits * z)) < 0.7)
- {
- in_region = true;
-
-
-
- if ((one_minus_a < 0) || (b_minus_a < 0))
- {
- if (fabs(one_minus_a * b_minus_a / z) > 0.5)
- in_region = false;
- }
- }
- }
- else if (fabs((1 - (b - a) + half_digits) * (a + half_digits) / (half_digits * z)) < 0.7)
- {
- if ((floor(b - a) == (b - a)) && (b - a < 0))
- return false;
- in_region = true;
-
-
-
- T a1 = 1 - (b - a);
- if ((a1 < 0) || (a < 0))
- {
- if (fabs(a1 * a / z) > 0.5)
- in_region = false;
- }
- }
-
-
-
- if (in_region)
- {
- if ((a < 0) && (floor(a) == a))
- in_region = false;
- if ((b < 0) && (floor(b) == b))
- in_region = false;
- if (fabs(z) < 40)
- in_region = false;
- }
- return in_region;
- }
- } } }
- #ifdef _MSC_VER
- #pragma warning(pop)
- #endif
- #endif
|