hypergeometric_1F1_scaled_series.hpp 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright 2017 John Maddock
  3. // Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. #ifndef BOOST_MATH_HYPERGEOMETRIC_1F1_SCALED_SERIES_HPP
  8. #define BOOST_MATH_HYPERGEOMETRIC_1F1_SCALED_SERIES_HPP
  9. #include <boost/array.hpp>
  10. namespace boost{ namespace math{ namespace detail{
  11. template <class T, class Policy>
  12. T hypergeometric_1F1_scaled_series(const T& a, const T& b, T z, const Policy& pol, const char* function)
  13. {
  14. BOOST_MATH_STD_USING
  15. //
  16. // Result is returned scaled by e^-z.
  17. // Whenever the terms start becoming too large, we scale by some factor e^-n
  18. // and keep track of the integer scaling factor n. At the end we can perform
  19. // an exact subtraction of n from z and scale the result:
  20. //
  21. T sum(0), term(1), upper_limit(sqrt(boost::math::tools::max_value<T>())), diff;
  22. unsigned n = 0;
  23. boost::intmax_t log_scaling_factor = 1 - itrunc(boost::math::tools::log_max_value<T>());
  24. T scaling_factor = exp(T(log_scaling_factor));
  25. boost::intmax_t current_scaling = 0;
  26. do
  27. {
  28. sum += term;
  29. if (sum >= upper_limit)
  30. {
  31. sum *= scaling_factor;
  32. term *= scaling_factor;
  33. current_scaling += log_scaling_factor;
  34. }
  35. term *= (((a + n) / ((b + n) * (n + 1))) * z);
  36. if (n > boost::math::policies::get_max_series_iterations<Policy>())
  37. return boost::math::policies::raise_evaluation_error(function, "Series did not converge, best value is %1%", sum, pol);
  38. ++n;
  39. diff = fabs(term / sum);
  40. } while (diff > boost::math::policies::get_epsilon<T, Policy>());
  41. z = -z - current_scaling;
  42. while (z < log_scaling_factor)
  43. {
  44. z -= log_scaling_factor;
  45. sum *= scaling_factor;
  46. }
  47. return sum * exp(z);
  48. }
  49. } } } // namespaces
  50. #endif // BOOST_MATH_HYPERGEOMETRIC_1F1_SCALED_SERIES_HPP