2
0
mirror of https://github.com/boostorg/math.git synced 2026-02-17 13:52:15 +00:00

Import SOC headers, Test and fix up 1F0 and 0F1.

This commit is contained in:
jzmaddock
2017-10-29 19:33:39 +00:00
parent 81c8a80dd5
commit 47fa45bee4
15 changed files with 2046 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_0F1_BESSEL_HPP
#define BOOST_MATH_HYPERGEOMETRIC_0F1_BESSEL_HPP
namespace boost { namespace math { namespace detail {
template <class T, class Policy>
inline T hypergeometric_0f1_bessel(const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING
const bool is_z_nonpositive = z <= 0;
const T sqrt_z = is_z_nonpositive ? T(sqrt(-z)) : T(sqrt(z));
const T bessel_mult = is_z_nonpositive ?
boost::math::cyl_bessel_j(b - 1, 2 * sqrt_z, pol) :
boost::math::cyl_bessel_i(b - 1, 2 * sqrt_z, pol) ;
if (b > boost::math::max_factorial<T>::value)
{
const T lsqrt_z = log(sqrt_z);
const T lsqrt_z_pow_b = (b - 1) * lsqrt_z;
T lg = (boost::math::lgamma(b, pol) - lsqrt_z_pow_b);
lg = exp(lg);
return lg * bessel_mult;
}
else
{
const T sqrt_z_pow_b = pow(sqrt_z, b - 1);
return (boost::math::tgamma(b, pol) / sqrt_z_pow_b) * bessel_mult;
}
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_0F1_BESSEL_HPP

View File

@@ -0,0 +1,312 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_1F1_BESSEL_HPP
#define BOOST_MATH_HYPERGEOMETRIC_1F1_BESSEL_HPP
#include <boost/math/tools/series.hpp>
#include <boost/math/special_functions/bessel.hpp>
#include <boost/math/special_functions/laguerre.hpp>
namespace boost { namespace math { namespace detail {
// declarations of helpers for 13_3_7 and 13_3_8:
// bessel_j recurrence relation based on finite continued fractions;
// it is stable forward recurrence algorithm, see William J. Lentz
// "Generating Bessel functions in Mie scattering calculations
// using continued fractions" for details
template <class T>
inline T hypergeometric_bessel_j_recurrence_next(const T& jvm1, const T& v, const T& z);
// swap values of Bessel functions:
template <class T>
inline void hypergeometric_bessel_j_recurrence_iterate(T& jvm1, T& jv, const T& v, const T& z);
// next coefficient for 13_3_7
template <class T>
inline T hypergeometric_13_3_7_coefficient_next(const T& anm3, const T& anm2, const T& a, const T& b, const unsigned n);
// next coefficient for 13_3_8
template <class T>
inline T hypergeometric_13_3_8_coefficient_next(const T& cnm3, const T& cnm2, const T& cnm1, const T& a, const T& b, const unsigned n);
// swap values of coefficients:
template <class T>
inline void hypergeometric_coefficient_13_3_7_iterate(T& anm3, T& anm2, T& anm1, T& an, const T& a, const T& b, const unsigned n);
template <class T>
inline void hypergeometric_coefficient_13_3_8_iterate(T& cnm3, T& cnm2, T& cnm1, T& cn, const T& a, const T& b, const unsigned n);
// term class of Abramowitz & Stegun 13_3_7 formula
template <class T>
struct hypergeometric_1f1_13_3_7_series_term
{
typedef T result_type;
hypergeometric_1f1_13_3_7_series_term(const T& a, const T& b, const T& z):
a(a), b(b), z(z), n(0u)
{
BOOST_MATH_STD_USING
sqrt_z_pow_n = sqrt_z = sqrt(z);
sqrt_2b_minus_4a_pow_n = sqrt_2b_minus_4a = sqrt(2 * (b - (2 * a)));
sqrt_2zb_minus_4za = sqrt_z * sqrt_2b_minus_4a;
v_current = b - 1;
anm3 = 1;
anm2 = 0;
anm1 = b / 2;
an = detail::hypergeometric_13_3_7_coefficient_next(anm3, anm2, a, b, 3u);
jvm1 = boost::math::cyl_bessel_j(v_current, sqrt_2zb_minus_4za);
v_current++;
jv = detail::hypergeometric_bessel_j_recurrence_next(jvm1, v_current, sqrt_2zb_minus_4za);
term = jvm1;
++n;
}
T operator()()
{
const T result = term;
iterate();
term = ((anm2 * sqrt_z_pow_n) / sqrt_2b_minus_4a_pow_n) * jv;
return result;
}
private:
void iterate()
{
++n; ++v_current;
sqrt_z_pow_n *= sqrt_z;
sqrt_2b_minus_4a_pow_n *= sqrt_2b_minus_4a;
detail::hypergeometric_coefficient_13_3_7_iterate(anm3, anm2, anm1, an, a, b, n + 2);
detail::hypergeometric_bessel_j_recurrence_iterate(jvm1, jv, v_current, sqrt_2zb_minus_4za);
}
const T a, b, z;
unsigned n;
T sqrt_z, sqrt_2b_minus_4a, sqrt_2zb_minus_4za;
T sqrt_z_pow_n, sqrt_2b_minus_4a_pow_n;
T v_current;
T anm3, anm2, anm1, an;
T jvm1, jv;
T term;
};
// function for 13_3_7 evaluation
template <class T, class Policy>
inline T hypergeometric_1f1_13_3_7_series(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING
const T sqrt_bz_div_2_minus_az = sqrt(((b * z) / 2) - (a * z));
const T prefix = ((boost::math::tgamma(b, pol) * sqrt_bz_div_2_minus_az) /
pow(sqrt_bz_div_2_minus_az, b)) * exp(z / 2);
detail::hypergeometric_1f1_13_3_7_series_term<T> s(a, b, z);
boost::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
T zero = 0;
T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
#else
T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
#endif
boost::math::policies::check_series_iterations<T>("boost::math::hypergeometric_1f1_13_3_7_series<%1%>(%1%,%1%,%1%)", max_iter, pol);
return prefix * result;
}
// term class of Abramowitz & Stegun 13_3_8 formula
template <class T>
struct hypergeometric_1f1_13_3_8_series_term
{
typedef T result_type;
static const T h;
hypergeometric_1f1_13_3_8_series_term(const T& a, const T& b, const T& z):
a(a), b(b), z(z), n(0u)
{
BOOST_MATH_STD_USING
sqrt_minus_az = sqrt(-a * z);
const T double_sqrt_minus_az = 2 * sqrt_minus_az;
v_current = b - 1;
z_pow_n = z; sqrt_minus_az_pow_n = sqrt_minus_az;
cnm3 = 1;
cnm2 = -b * h;
cnm1 = (((1 - (2 * h)) * a) + ((b * (b + 1)) * (h * h))) / 2;
cn = detail::hypergeometric_13_3_8_coefficient_next(cnm3, cnm2, cnm1, a, b, 3u);
jvm1 = boost::math::cyl_bessel_j(v_current, double_sqrt_minus_az);
++v_current;
jv = detail::hypergeometric_bessel_j_recurrence_next(jvm1, b, double_sqrt_minus_az);
}
T operator()()
{
++n;
switch (n - 1)
{
case 0u:
return jvm1;
case 1u:
detail::hypergeometric_bessel_j_recurrence_iterate(jvm1, jv, v_current, T(2 * sqrt_minus_az));
return ((cnm2 * z) / sqrt_minus_az) * jvm1;
}
++v_current;
z_pow_n *= z;
sqrt_minus_az_pow_n *= sqrt_minus_az;
const T result = ((cnm1 * z_pow_n) / sqrt_minus_az_pow_n) * jv;
detail::hypergeometric_coefficient_13_3_8_iterate(cnm3, cnm2, cnm1, cn, a, b, n + 1);
detail::hypergeometric_bessel_j_recurrence_iterate(jvm1, jv, v_current, T(2 * sqrt_minus_az));
return result;
}
private:
const T a, b, z;
unsigned n;
T sqrt_minus_az;
T z_pow_n, sqrt_minus_az_pow_n;
T v_current;
T cnm3, cnm2, cnm1, cn;
T jvm1, jv;
};
template <class T>
const T hypergeometric_1f1_13_3_8_series_term<T>::h = -boost::math::constants::pi<T>() / T(10.);
// function for 13_3_8 evaluation
template <class T, class Policy>
inline T hypergeometric_1f1_13_3_8_series(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING
const T sqrt_minus_az_pow_b_minus_one = pow(sqrt(-a * z), b - 1);
const T prefix = (boost::math::tgamma(b, pol) / sqrt_minus_az_pow_b_minus_one) *
exp(detail::hypergeometric_1f1_13_3_8_series_term<T>::h * z);
detail::hypergeometric_1f1_13_3_8_series_term<T> s(a, b, z);
boost::uintmax_t max_iter = boost::math::policies::get_max_series_iterations<Policy>();
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
T zero = 0;
T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
#else
T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
#endif
boost::math::policies::check_series_iterations<T>("boost::math::hypergeometric_1f1_13_3_8_series<%1%>(%1%,%1%,%1%)", max_iter, pol);
return prefix * result;
}
// definitions of helpers:
template <class T>
inline T hypergeometric_bessel_j_recurrence_next(const T& jvm1, const T& v, const T& z)
{
BOOST_MATH_STD_USING
// TODO: we can estimate a possible capacity for these vectors
std::vector<T> finite_cf_nums;
std::vector<T> finite_cf_denoms;
const T a_coef_when_i_is_one = (2 * v) / z;
const T a_coef_when_i_is_two = (-2 * (v + 1)) / z;
finite_cf_nums.push_back(a_coef_when_i_is_one);
finite_cf_nums.push_back(a_coef_when_i_is_two + (1. / a_coef_when_i_is_one));
finite_cf_denoms.push_back(a_coef_when_i_is_two);
unsigned i = 3u;
do {
const T temp = (2 * (v + (i - 1))) / z;
const T next_coef = i & 1 ? temp : T(-temp);
finite_cf_nums.push_back(next_coef + (1. / finite_cf_nums.back()));
finite_cf_denoms.push_back(next_coef + (1. / finite_cf_denoms.back()));
++i;
} while (fabs(finite_cf_nums.back() - finite_cf_denoms.back()) > boost::math::tools::epsilon<T>());
T ratio = finite_cf_nums.front();
for (i = 0u; i < finite_cf_denoms.size(); ++i)
ratio *= finite_cf_nums[i+1] / finite_cf_denoms[i];
return jvm1 / ratio;
}
template <class T>
inline void hypergeometric_bessel_j_recurrence_iterate(T& jvm1, T& jv, const T& v, const T& z)
{
using std::swap;
swap(jvm1, jv);
jv = detail::hypergeometric_bessel_j_recurrence_next(jvm1, v, z);
}
template <class T>
inline T hypergeometric_13_3_7_coefficient_next(const T& anm3, const T& anm2, const T& a, const T& b, const unsigned n)
{
const T term_anm2 = ((n + b) - 2) * anm2;
const T term_anm3 = ((2 * a) - b) * anm3;
return (term_anm2 + term_anm3) / n;
}
template <class T>
inline T hypergeometric_13_3_8_coefficient_next(const T& cnm3, const T& cnm2, const T& cnm1, const T& a, const T& b, const unsigned n)
{
static const T& h = detail::hypergeometric_1f1_13_3_8_series_term<T>::h;
const T one_minus_two_h = 1 - (2 * h);
const T h_minus_one = h - 1;
const T term_cnm1 = ((one_minus_two_h * n) - (b * h)) * cnm1;
const T term_cnm2 = ((one_minus_two_h * a) - ((h * h_minus_one) * (b + (n - 1)))) * cnm2;
const T term_cnm3 = ((-h * h_minus_one) * a) * cnm3;
return ((term_cnm1 + term_cnm2) + term_cnm3) / (n + 1);
}
template <class T>
inline void hypergeometric_coefficient_13_3_7_iterate(T& anm3, T& anm2, T& anm1, T& an, const T& a, const T& b, const unsigned n)
{
using std::swap;
swap(anm3, anm2);
swap(anm2, anm1);
swap(anm1, an);
an = detail::hypergeometric_13_3_7_coefficient_next(anm3, anm2, a, b, n);
}
template <class T>
inline void hypergeometric_coefficient_13_3_8_iterate(T& cnm3, T& cnm2, T& cnm1, T& cn, const T& a, const T& b, const unsigned n)
{
using std::swap;
swap(cnm3, cnm2);
swap(cnm2, cnm1);
swap(cnm1, cn);
cn = detail::hypergeometric_13_3_8_coefficient_next(cnm3, cnm2, cnm1, a, b, n);
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_1F1_BESSEL_HPP

View File

@@ -0,0 +1,200 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_
#define BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_
#include <boost/math/special_functions/modf.hpp>
#include <boost/math/special_functions/next.hpp>
#include <boost/math/tools/recurrence.hpp>
namespace boost { namespace math { namespace detail {
template <class T>
struct hypergeometric_1f1_recurrence_a_coefficients
{
typedef boost::math::tuple<T, T, T> result_type;
hypergeometric_1f1_recurrence_a_coefficients(const T& a, const T& b, const T& z):
a(a), b(b), z(z)
{
}
result_type operator()(boost::intmax_t i) const
{
const T ai = a + i;
const T an = -ai;
const T bn = (b - (2 * ai)) - z;
const T cn = b - ai;
return boost::math::make_tuple(an, bn, cn);
}
private:
const T a, b, z;
};
template <class T>
struct hypergeometric_1f1_recurrence_b_coefficients
{
typedef boost::math::tuple<T, T, T> result_type;
hypergeometric_1f1_recurrence_b_coefficients(const T& a, const T& b, const T& z):
a(a), b(b), z(z)
{
}
result_type operator()(boost::intmax_t i) const
{
const T bi = b + i;
const T an = z * (bi - a);
const T bn = bi * ((z + bi) - 1);
const T cn = bi * (bi - 1);
return boost::math::make_tuple(an, bn, cn);
}
private:
const T a, b, z;
};
template <class T>
struct hypergeometric_1f1_recurrence_a_and_b_coefficients
{
typedef boost::math::tuple<T, T, T> result_type;
hypergeometric_1f1_recurrence_a_and_b_coefficients(const T& a, const T& b, const T& z):
a(a), b(b), z(z)
{
}
result_type operator()(boost::intmax_t i) const
{
const T ai = a + i;
const T bi = b + i;
const T an = ai * z;
const T bn = bi * ((1 - bi) + z);
const T cn = bi * (1 - bi);
return boost::math::make_tuple(an, bn, cn);
}
private:
const T a, b, z;
};
// forward declaration for initial values
template <class T, class Policy>
inline T hypergeometric_1f1_imp(const T& a, const T& b, const T& z, const Policy& pol);
template <class T, class Policy>
inline T hypergeometric_1f1_backward_recurrence_for_negative_a(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING // modf, frexp, fabs, pow
boost::intmax_t integer_part = 0;
const T bk = modf(b, &integer_part);
T ak = modf(a, &integer_part);
int exp_of_a = 0; frexp(a, &exp_of_a);
int exp_of_b = 0; frexp(b, &exp_of_b);
const bool are_fractional_parts_close_enough =
fabs(boost::math::float_distance(ak, bk)) <= pow(2, (std::max)(exp_of_a, exp_of_b));
if ((a < b) && (b < 0) && (are_fractional_parts_close_enough)) // TODO: has to be researched deeper
{
ak = b - 1;
integer_part -= (boost::math::lltrunc(ceil(b)) - 1);
}
T first = detail::hypergeometric_1f1_imp(ak, b, z, pol);
--ak;
T second = detail::hypergeometric_1f1_imp(ak, b, z, pol);
detail::hypergeometric_1f1_recurrence_a_coefficients<T> s(ak, b, z);
return tools::solve_recurrence_relation_backward(s,
static_cast<unsigned int>(std::abs(integer_part)),
first,
second);
}
template <class T, class Policy>
inline T hypergeometric_1f1_forward_recurrence_for_positive_a(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING // modf, fabs
boost::intmax_t integer_part = 0;
T ak = modf(a, &integer_part);
T first = detail::hypergeometric_1f1_imp(ak, b, z, pol);
++ak;
T second = detail::hypergeometric_1f1_imp(ak, b, z, pol);
detail::hypergeometric_1f1_recurrence_a_coefficients<T> s(ak, b, z);
return tools::solve_recurrence_relation_forward(s, integer_part, first, second);
}
template <class T, class Policy>
inline T hypergeometric_1f1_backward_recurrence_for_negative_b(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING // modf, fabs
boost::intmax_t integer_part = 0;
T bk = modf(b, &integer_part);
T first = detail::hypergeometric_1f1_imp(a, bk, z, pol);
--bk;
T second = detail::hypergeometric_1f1_imp(a, bk, z, pol);
detail::hypergeometric_1f1_recurrence_b_coefficients<T> s(a, bk, z);
return tools::solve_recurrence_relation_backward(s,
static_cast<unsigned int>(std::abs(integer_part)),
first,
second);
}
// this method works provided that integer part of a is the same as integer part of b
// we don't make this check inside it.
template <class T, class Policy>
inline T hypergeometric_1f1_backward_recurrence_for_negative_a_and_b(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING // modf, fabs
boost::intmax_t integer_part = 0;
T ak = modf(a, &integer_part);
T bk = modf(b, &integer_part);
T first = detail::hypergeometric_1f1_imp(ak, bk, z, pol);
--ak; --bk;
T second = detail::hypergeometric_1f1_imp(ak, bk, z, pol);
detail::hypergeometric_1f1_recurrence_a_and_b_coefficients<T> s(ak, bk, z);
return tools::solve_recurrence_relation_backward(s, fabs(integer_part), first, second);
}
// ranges
template <class T>
inline bool hypergeometric_1f1_is_a_small_enough(const T& a)
{
return a < -10; // TODO: make dependent on precision
}
} } } // namespaces
#endif // BOOST_HYPERGEOMETRIC_1F1_RECURRENCE_HPP_

View File

@@ -0,0 +1,87 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_ASYM_HPP
#define BOOST_MATH_HYPERGEOMETRIC_ASYM_HPP
#include <boost/math/special_functions/gamma.hpp>
namespace boost { namespace math {
// forward declaration of used function 2f0
template <class T1, class T2, class T3, class Policy>
inline typename tools::promote_args<T1, T2, T3>::type hypergeometric_2f0(T1 a1, T2 a2, T3 z, const Policy& /* pol */);
namespace detail {
// assumes a and b are not non-positive integers
template <class T, class Policy>
inline T hypergeometric_1f1_asym_positive_series(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* const function = "boost::math::hypergeometric_1f1_asym_positive_series<%1%>(%1%,%1%,%1%)";
const bool is_a_integer = (a == floor(a));
const bool is_b_integer = (b == floor(b));
BOOST_ASSERT(!(is_a_integer && a <= 0) && !(is_b_integer && b <= 0));
const T gamma_ratio = (b > 0 && a > 0) ?
boost::math::tgamma_ratio(b, a, pol) :
T(boost::math::tgamma(b, pol) / boost::math::tgamma(a, pol));
const T prefix_a = (exp(z) * gamma_ratio) * pow(z, (a - b));
return prefix_a * boost::math::hypergeometric_2f0(b - a, 1 - a, 1 / z, pol);
}
// assumes b and (b - a) are not non-positive integers
template <class T, class Policy>
inline T hypergeometric_1f1_asym_negative_series(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* const function = "boost::math::hypergeometric_1f1_asym_negative_series<%1%>(%1%,%1%,%1%)";
const T b_minus_a = b - a;
const bool is_a_integer = (a == floor(a));
const bool is_b_minus_a_integer = (b_minus_a == floor(b_minus_a));
BOOST_ASSERT(!(is_a_integer && a <= 0) && !(is_b_minus_a_integer && b_minus_a <= 0));
const T gamma_ratio = (b > 0 && b_minus_a > 0) ?
boost::math::tgamma_ratio(b, b_minus_a, pol) :
boost::math::tgamma(b) / boost::math::tgamma((b_minus_a), pol);
const T prefix_b = gamma_ratio / pow(-z, a);
return prefix_b * boost::math::hypergeometric_2f0(a, 1 - b_minus_a, -1 / z, pol);
}
// experimental range
template <class T>
inline bool hypergeometric_1f1_asym_region(const T& a, const T& b, const T& z)
{
BOOST_MATH_STD_USING
const T the_max_of_one_and_b_minus_a ((std::max)(T(1), fabs(b - a)));
const T the_max_of_one_and_one_minus_a((std::max)(T(1), fabs(1 - a)));
const T the_product_of_these_maxima(the_max_of_one_and_b_minus_a * the_max_of_one_and_one_minus_a);
const T abs_of_z(fabs(z));
if ((abs_of_z > 100) && (the_product_of_these_maxima < (abs_of_z / 2))) // TODO: not a good way
return true;
return false;
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_ASYM_HPP

View File

@@ -0,0 +1,228 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_CF_HPP
#define BOOST_MATH_HYPERGEOMETRIC_CF_HPP
namespace boost { namespace math { namespace detail {
// primary template for term of continued fraction
template <class T, unsigned p, unsigned q>
struct hypergeometric_pfq_cf_term;
// partial specialization for 0f1
template <class T>
struct hypergeometric_pfq_cf_term<T, 0u, 1u>
{
typedef std::pair<T,T> result_type;
hypergeometric_pfq_cf_term(const T& b, const T& z):
n(1), b(b), z(z),
term(std::make_pair(T(0), T(1)))
{
}
result_type operator()()
{
const result_type result = term;
++b; ++n;
numer = -(z / (b * n));
term = std::make_pair(numer, 1 - numer);
return result;
}
private:
unsigned n;
T b;
const T z;
T numer;
result_type term;
};
// partial specialization for 1f0
template <class T>
struct hypergeometric_pfq_cf_term<T, 1u, 0u>
{
typedef std::pair<T,T> result_type;
hypergeometric_pfq_cf_term(const T& a, const T& z):
n(1), a(a), z(z),
term(std::make_pair(T(0), T(1)))
{
}
result_type operator()()
{
const result_type result = term;
++a; ++n;
numer = -((a * z) / n);
term = std::make_pair(numer, 1 - numer);
return result;
}
private:
unsigned n;
T a;
const T z;
T numer;
result_type term;
};
// partial specialization for 1f1
template <class T>
struct hypergeometric_pfq_cf_term<T, 1u, 1u>
{
typedef std::pair<T,T> result_type;
hypergeometric_pfq_cf_term(const T& a, const T& b, const T& z):
n(1), a(a), b(b), z(z),
term(std::make_pair(T(0), T(1)))
{
}
result_type operator()()
{
const result_type result = term;
++a; ++b; ++n;
numer = -((a * z) / (b * n));
term = std::make_pair(numer, 1 - numer);
return result;
}
private:
unsigned n;
T a, b;
const T z;
T numer;
result_type term;
};
// partial specialization for 1f2
template <class T>
struct hypergeometric_pfq_cf_term<T, 1u, 2u>
{
typedef std::pair<T,T> result_type;
hypergeometric_pfq_cf_term(const T& a, const T& b, const T& c, const T& z):
n(1), a(a), b(b), c(c), z(z),
term(std::make_pair(T(0), T(1)))
{
}
result_type operator()()
{
const result_type result = term;
++a; ++b; ++c; ++n;
numer = -((a * z) / ((b * c) * n));
term = std::make_pair(numer, 1 - numer);
return result;
}
private:
unsigned n;
T a, b, c;
const T z;
T numer;
result_type term;
};
// partial specialization for 2f1
template <class T>
struct hypergeometric_pfq_cf_term<T, 2u, 1u>
{
typedef std::pair<T,T> result_type;
hypergeometric_pfq_cf_term(const T& a, const T& b, const T& c, const T& z):
n(1), a(a), b(b), c(c), z(z),
term(std::make_pair(T(0), T(1)))
{
}
result_type operator()()
{
const result_type result = term;
++a; ++b; ++c; ++n;
numer = -(((a * b) * z) / (c * n));
term = std::make_pair(numer, 1 - numer);
return result;
}
private:
unsigned n;
T a, b, c;
const T z;
T numer;
result_type term;
};
template <class T, unsigned p, unsigned q, class Policy>
inline T compute_cf_pfq(detail::hypergeometric_pfq_cf_term<T, p, q>& term, const Policy& pol)
{
BOOST_MATH_STD_USING
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
const T result = tools::continued_fraction_b(
term,
boost::math::policies::get_epsilon<T, Policy>(),
max_iter);
boost::math::policies::check_series_iterations<T>(
"boost::math::hypergeometric_pfq_cf<%1%>(%1%,%1%,%1%)",
max_iter,
pol);
return result;
}
template <class T, class Policy>
inline T hypergeometric_0f1_cf(const T& b, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_cf_term<T, 0u, 1u> f(b, z);
T result = detail::compute_cf_pfq(f, pol);
result = ((z / b) / result) + 1;
return result;
}
template <class T, class Policy>
inline T hypergeometric_1f0_cf(const T& a, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_cf_term<T, 1u, 0u> f(a, z);
T result = detail::compute_cf_pfq(f, pol);
result = ((a * z) / result) + 1;
return result;
}
template <class T, class Policy>
inline T hypergeometric_1f1_cf(const T& a, const T& b, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_cf_term<T, 1u, 1u> f(a, b, z);
T result = detail::compute_cf_pfq(f, pol);
result = (((a * z) / b) / result) + 1;
return result;
}
template <class T, class Policy>
inline T hypergeometric_1f2_cf(const T& a, const T& b, const T& c, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_cf_term<T, 1u, 2u> f(a, b, c, z);
T result = detail::compute_cf_pfq(f, pol);
result = (((a * z) / (b * c)) / result) + 1;
return result;
}
template <class T, class Policy>
inline T hypergeometric_2f1_cf(const T& a, const T& b, const T& c, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_cf_term<T, 2u, 1u> f(a, b, c, z);
T result = detail::compute_cf_pfq(f, pol);
result = ((((a * b) * z) / c) / result) + 1;
return result;
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_CF_HPP

View File

@@ -0,0 +1,131 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_PADE_HPP
#define BOOST_MATH_HYPERGEOMETRIC_PADE_HPP
namespace boost{ namespace math{ namespace detail{
// Luke: C ---------- SUBROUTINE R1F1P(CP, Z, A, B, N) ----------
// Luke: C ----- PADE APPROXIMATION OF 1F1( 1 ; CP ; -Z ) -------
template <class T, class Policy>
inline T hypergeometric_1f1_pade(const T& cp, const T& zp, const Policy& pol)
{
BOOST_MATH_STD_USING
static const T one = T(1);
// Luke: C ------------- INITIALIZATION -------------
const T z = -zp;
const T zz = z * z;
T b0 = one;
T a0 = one;
T xi1 = one;
T ct1 = cp + one;
T cp1 = cp - one;
T b1 = one + (z / ct1);
T a1 = b1 - (z / cp);
const unsigned max_iterations = boost::math::policies::get_max_series_iterations<Policy>();
T b2 = T(0), a2 = T(0);
T result = T(0), prev_result = a1 / b1;
for (unsigned k = 1; k < max_iterations; ++k)
{
// Luke: C ----- CALCULATION OF THE MULTIPLIERS -----
// Luke: C ----------- FOR THE RECURSION ------------
const T ct2 = ct1 * ct1;
const T g1 = one + ((cp1 / (ct2 + ct1 + ct1)) * z);
const T g2 = ((xi1 / (ct2 - one)) * ((xi1 + cp1) / ct2)) * zz;
// Luke: C ------- THE RECURRENCE RELATIONS ---------
// Luke: C ------------ ARE AS FOLLOWS --------------
b2 = (g1 * b1) + (g2 * b0);
a2 = (g1 * a1) + (g2 * a0);
prev_result = result;
result = a2 / b2;
// condition for interruption
if ((fabs(result) * boost::math::tools::epsilon<T>()) > fabs(result - prev_result))
break;
b0 = b1; b1 = b2;
a0 = a1; a1 = a2;
ct1 += 2;
++xi1;
}
return a2 / b2;
}
// Luke: C -------- SUBROUTINE R2F1P(BP, CP, Z, A, B, N) --------
// Luke: C ---- PADE APPROXIMATION OF 2F1( 1 , BP; CP ; -Z ) ----
template <class T, class Policy>
inline T hypergeometric_2f1_pade(const T& bp, const T& cp, const T& zp, const Policy& pol)
{
BOOST_MATH_STD_USING
static const T one = T(1);
// Luke: C ---------- INITIALIZATION -----------
const T z = -zp;
const T zz = z * z;
T b0 = one;
T a0 = one;
T xi1 = one;
T ct1 = cp;
const T b1c1 = (cp - one) * (bp - one);
T b1 = one + ((z / (cp + one)) * (bp + one));
T a1 = b1 - ((bp / cp) * z);
const unsigned max_iterations = boost::math::policies::get_max_series_iterations<Policy>();
T b2 = T(0), a2 = T(0);
T result = T(0), prev_result = a1 / b1;
for (unsigned k = 1; k < max_iterations; ++k)
{
// Luke: C ----- CALCULATION OF THE MULTIPLIERS -----
// Luke: C ----------- FOR THE RECURSION ------------
const T ct2 = ct1 + xi1;
const T ct3 = ct2 * ct2;
const T g2 = (((((ct1 / ct3) * (bp - ct1)) / (ct3 - one)) * xi1) * (bp + xi1)) * zz;
++xi1;
const T g1 = one + (((((xi1 + xi1) * ct1) + b1c1) / (ct3 + ct2 + ct2)) * z);
// Luke: C ------- THE RECURRENCE RELATIONS ---------
// Luke: C ------------ ARE AS FOLLOWS --------------
b2 = (g1 * b1) + (g2 * b0);
a2 = (g1 * a1) + (g2 * a0);
prev_result = result;
result = a2 / b2;
// condition for interruption
if ((fabs(result) * boost::math::tools::epsilon<T>()) > fabs(result - prev_result))
break;
b0 = b1; b1 = b2;
a0 = a1; a1 = a2;
++ct1;
}
return a2 / b2;
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_PADE_HPP

View File

@@ -0,0 +1,165 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_RATIONAL_HPP
#define BOOST_MATH_HYPERGEOMETRIC_RATIONAL_HPP
#include <boost/array.hpp>
namespace boost{ namespace math{ namespace detail{
// Luke: C ------- SUBROUTINE R1F1P(AP, CP, Z, A, B, N) ---------
// Luke: C --- RATIONAL APPROXIMATION OF 1F1( AP ; CP ; -Z ) ----
template <class T, class Policy>
inline T hypergeometric_1f1_rational(const T& ap, const T& cp, const T& zp, const Policy& pol)
{
BOOST_MATH_STD_USING
static const T zero = T(0), one = T(1), two = T(2), three = T(3);
// Luke: C ------------- INITIALIZATION -------------
const T z = -zp;
const T z2 = z / two;
T ct1 = ap * (z / cp);
T ct2 = z2 / (one + cp);
T xn3 = zero;
T xn2 = one;
T xn1 = two;
T xn0 = three;
T b1 = one;
T a1 = one;
T b2 = one + ((one + ap) * (z2 / cp));
T a2 = b2 - ct1;
T b3 = one + ((two + b2) * (((two + ap) / three) * ct2));
T a3 = b3 - ((one + ct2) * ct1);
ct1 = three;
const unsigned max_iterations = boost::math::policies::get_max_series_iterations<Policy>();
T a4 = T(0), b4 = T(0);
T result = T(0), prev_result = a3 / b3;
for (unsigned k = 2; k < max_iterations; ++k)
{
// Luke: C ----- CALCULATION OF THE MULTIPLIERS -----
// Luke: C ----------- FOR THE RECURSION ------------
ct2 = (z2 / ct1) / (cp + xn1);
const T g1 = one + (ct2 * (xn2 - ap));
ct2 *= ((ap + xn1) / (cp + xn2));
const T g2 = ct2 * ((cp - xn1) + (((ap + xn0) / (ct1 + two)) * z2));
const T g3 = ((ct2 * z2) * (((z2 / ct1) / (ct1 - two)) * ((ap + xn2)) / (cp + xn3))) * (ap - xn2);
// Luke: C ------- THE RECURRENCE RELATIONS ---------
// Luke: C ------------ ARE AS FOLLOWS --------------
b4 = (g1 * b3) + (g2 * b2) + (g3 * b1);
a4 = (g1 * a3) + (g2 * a2) + (g3 * a1);
prev_result = result;
result = a4 / b4;
// condition for interruption
if ((fabs(result) * boost::math::tools::epsilon<T>()) > fabs(result - prev_result))
break;
b1 = b2; b2 = b3; b3 = b4;
a1 = a2; a2 = a3; a3 = a4;
xn3 = xn2; xn2 = xn1; xn1 = xn0; ++xn0;
ct1 += two;
}
return result;
}
// Luke: C ----- SUBROUTINE R2F1P(AB, BP, CP, Z, A, B, N) -------
// Luke: C -- RATIONAL APPROXIMATION OF 2F1( AB , BP; CP ; -Z ) -
template <class T, class Policy>
inline T hypergeometric_2f1_rational(const T& ap, const T& bp, const T& cp, const T& zp, const unsigned n, const Policy& pol)
{
BOOST_MATH_STD_USING
static const T one = T(1), two = T(2), three = T(3), four = T(4),
six = T(6), half_7 = T(3.5), half_3 = T(1.5), forth_3 = T(0.75);
// Luke: C ------------- INITIALIZATION -------------
const T z = -zp;
const T z2 = z / two;
T sabz = (ap + bp) * z;
const T ab = ap * bp;
const T abz = ab * z;
const T abz1 = z + (abz + sabz);
const T abz2 = abz1 + (sabz + (three * z));
const T cp1 = cp + one;
const T ct1 = cp1 + cp1;
T b1 = one;
T a1 = one;
T b2 = one + (abz1 / (cp + cp));
T a2 = b2 - (abz / cp);
T b3 = one + ((abz2 / ct1) * (one + (abz1 / ((-six) + (three * ct1)))));
T a3 = b3 - ((abz / cp) * (one + ((abz2 - abz1) / ct1)));
sabz /= four;
const T abz1_div_4 = abz1 / four;
const T cp1_inc = cp1 + one;
const T cp1_mul_cp1_inc = cp1 * cp1_inc;
boost::array<T, 9u> d = {{
((half_7 - ab) * z2) - sabz,
abz1_div_4,
abz1_div_4 - (two * sabz),
cp1_inc,
cp1_mul_cp1_inc,
cp * cp1_mul_cp1_inc,
half_3,
forth_3,
forth_3 * z
}};
T xi = three;
T a4 = T(0), b4 = T(0);
for (unsigned k = 2; k < n; ++k)
{
// Luke: C ----- CALCULATION OF THE MULTIPLIERS -----
// Luke: C ----------- FOR THE RECURSION ------------
T g3 = (d[2] / d[7]) * (d[1] / d[5]);
d[1] += d[8] + sabz;
d[2] += d[8] - sabz;
g3 *= d[1] / d[6];
T g1 = one + (((d[1] + d[0]) / d[6]) / d[3]);
T g2 = (d[1] / d[4]) / d[6];
d[7] += two * d[6];
++d[6];
g2 *= cp1 - (xi + ((d[2] + d[0]) / d[6]));
// Luke: C ------- THE RECURRENCE RELATIONS ---------
// Luke: C ------------ ARE AS FOLLOWS --------------
b4 = (g1 * b3) + (g2 * b2) + (g3 * b1);
a4 = (g1 * a3) + (g2 * a2) + (g3 * a1);
b1 = b2; b2 = b3; b3 = b4;
a1 = a2; a2 = a3; a3 = a4;
d[8] += z2;
d[0] += two * d[8];
d[5] += three * d[4];
d[4] += two * d[3];
++d[3];
++xi;
}
return a4 / b4;
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_RATIONAL_HPP

View File

@@ -0,0 +1,51 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_SEPARATED_SERIES_HPP
#define BOOST_MATH_HYPERGEOMETRIC_SEPARATED_SERIES_HPP
namespace boost { namespace math { namespace detail {
template <class T, class Policy>
inline T hypergeometric_1f1_separated_series(const T& a, const T& b, const T& z, const Policy& pol)
{
BOOST_MATH_STD_USING
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
const T factor = policies::get_epsilon<T, Policy>();
T denom = 1, numer = 1;
T intermediate_result = 1, result = 1;
T a_pochhammer = a, z_pow = z;
unsigned N = 0;
while (--max_iter)
{
++N;
const T mult = (((b + N) - 1) * N);
denom *= mult; numer *= mult;
numer += a_pochhammer * z_pow;
result = numer / denom;
if (fabs(factor * result) > fabs(result - intermediate_result))
break;
intermediate_result = result;
a_pochhammer *= (a + N);
z_pow *= z;
}
return result;
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_SEPARATED_SERIES_HPP

View File

@@ -0,0 +1,242 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_HYPERGEOMETRIC_SERIES_HPP
#define BOOST_MATH_HYPERGEOMETRIC_SERIES_HPP
#include <boost/math/tools/series.hpp>
#include <boost/math/policies/error_handling.hpp>
namespace boost { namespace math { namespace detail {
// primary template for term of Taylor series
template <class T, unsigned p, unsigned q>
struct hypergeometric_pfq_generic_series_term;
// partial specialization for 0F1
template <class T>
struct hypergeometric_pfq_generic_series_term<T, 0u, 1u>
{
typedef T result_type;
hypergeometric_pfq_generic_series_term(const T& b, const T& z)
: n(0), term(1), b(b), z(z)
{
}
T operator()()
{
BOOST_MATH_STD_USING
const T r = term;
term *= ((1 / ((b + n) * (n + 1))) * z);
++n;
return r;
}
private:
unsigned n;
T term;
const T b, z;
};
// partial specialization for 1F0
template <class T>
struct hypergeometric_pfq_generic_series_term<T, 1u, 0u>
{
typedef T result_type;
hypergeometric_pfq_generic_series_term(const T& a, const T& z)
: n(0), term(1), a(a), z(z)
{
}
T operator()()
{
BOOST_MATH_STD_USING
const T r = term;
term *= (((a + n) / (n + 1)) * z);
++n;
return r;
}
private:
unsigned n;
T term;
const T a, z;
};
// partial specialization for 1F1
template <class T>
struct hypergeometric_pfq_generic_series_term<T, 1u, 1u>
{
typedef T result_type;
hypergeometric_pfq_generic_series_term(const T& a, const T& b, const T& z)
: n(0), term(1), a(a), b(b), z(z)
{
}
T operator()()
{
BOOST_MATH_STD_USING
const T r = term;
term *= (((a + n) / ((b + n) * (n + 1))) * z);
++n;
return r;
}
private:
unsigned n;
T term;
const T a, b, z;
};
// partial specialization for 1F2
template <class T>
struct hypergeometric_pfq_generic_series_term<T, 1u, 2u>
{
typedef T result_type;
hypergeometric_pfq_generic_series_term(const T& a, const T& b1, const T& b2, const T& z)
: n(0), term(1), a(a), b1(b1), b2(b2), z(z)
{
}
T operator()()
{
BOOST_MATH_STD_USING
const T r = term;
term *= (((a + n) / ((b1 + n) * (b2 + n) * (n + 1))) * z);
++n;
return r;
}
private:
unsigned n;
T term;
const T a, b1, b2, z;
};
// partial specialization for 2F0
template <class T>
struct hypergeometric_pfq_generic_series_term<T, 2u, 0u>
{
typedef T result_type;
hypergeometric_pfq_generic_series_term(const T& a1, const T& a2, const T& z)
: n(0), term(1), a1(a1), a2(a2), z(z)
{
}
T operator()()
{
BOOST_MATH_STD_USING
const T r = term;
term *= (((a1 + n) * (a2 + n) / (n + 1)) * z);
++n;
return r;
}
private:
unsigned n;
T term;
const T a1, a2, z;
};
// partial specialization for 2F1
template <class T>
struct hypergeometric_pfq_generic_series_term<T, 2u, 1u>
{
typedef T result_type;
hypergeometric_pfq_generic_series_term(const T& a1, const T& a2, const T& b, const T& z)
: n(0), term(1), a1(a1), a2(a2), b(b), z(z)
{
}
T operator()()
{
BOOST_MATH_STD_USING
const T r = term;
term *= (((a1 + n) * (a2 + n) / ((b + n) * (n + 1))) * z);
++n;
return r;
}
private:
unsigned n;
T term;
const T a1, a2, b, z;
};
// we don't need to define extra check and make a polinom from
// series, when p(i) and q(i) are negative integers and p(i) >= q(i)
// as described in functions.wolfram.alpha, because we always
// stop summation when result (in this case numerator) is zero.
template <class T, unsigned p, unsigned q, class Policy>
inline T sum_pfq_series(detail::hypergeometric_pfq_generic_series_term<T, p, q>& term, const Policy& pol)
{
BOOST_MATH_STD_USING
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
const T zero = 0;
const T result = boost::math::tools::sum_series(term, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
#else
const T result = boost::math::tools::sum_series(term, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
#endif
policies::check_series_iterations<T>("boost::math::hypergeometric_pfq_generic_series<%1%>(%1%,%1%,%1%)", max_iter, pol);
return result;
}
template <class T, class Policy>
inline T hypergeometric_0f1_generic_series(const T& b, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_generic_series_term<T, 0u, 1u> s(b, z);
return detail::sum_pfq_series(s, pol);
}
template <class T, class Policy>
inline T hypergeometric_1f0_generic_series(const T& a, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_generic_series_term<T, 1u, 0u> s(a, z);
return detail::sum_pfq_series(s, pol);
}
template <class T, class Policy>
inline T hypergeometric_1f1_generic_series(const T& a, const T& b, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_generic_series_term<T, 1u, 1u> s(a, b, z);
return detail::sum_pfq_series(s, pol);
}
template <class T, class Policy>
inline T hypergeometric_1f2_generic_series(const T& a, const T& b1, const T& b2, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_generic_series_term<T, 1u, 2u> s(a, b1, b2, z);
return detail::sum_pfq_series(s, pol);
}
template <class T, class Policy>
inline T hypergeometric_2f0_generic_series(const T& a1, const T& a2, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_generic_series_term<T, 2u, 0u> s(a1, a2, z);
return detail::sum_pfq_series(s, pol);
}
template <class T, class Policy>
inline T hypergeometric_2f1_generic_series(const T& a1, const T& a2, const T& b, const T& z, const Policy& pol)
{
detail::hypergeometric_pfq_generic_series_term<T, 2u, 1u> s(a1, a2, b, z);
return detail::sum_pfq_series(s, pol);
}
} } } // namespaces
#endif // BOOST_MATH_HYPERGEOMETRIC_SERIES_HPP

View File

@@ -0,0 +1,110 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef _BOOST_HYPERGEOMETRIC_0F1_HPP_
#define _BOOST_HYPERGEOMETRIC_0F1_HPP_
#include <boost/math/policies/policy.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/detail/hypergeometric_series.hpp>
#include <boost/math/special_functions/detail/hypergeometric_0f1_bessel.hpp>
namespace boost { namespace math { namespace detail {
template <class T>
struct hypergeometric_0F1_cf
{
T b, z;
int k;
hypergeometric_0F1_cf(T b_, T z_) : b(b_), z(z_), k(0) {}
typedef std::pair<T, T> result_type;
result_type operator()()
{
++k;
return std::make_pair(-z / ((k + 1) * (b + k)), 1 + z / ((k + 1) * (b + k)));
}
};
template <class T, class Policy>
T hypergeometric_0F1_cf_imp(T b, T z, const Policy& pol, const char* function)
{
hypergeometric_0F1_cf<T> evaluator(b, z);
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T cf = tools::continued_fraction_a(evaluator, policies::get_epsilon<T, Policy>(), max_iter);
policies::check_series_iterations<T>(function, max_iter, pol);
return 1 + z / (b * (1 + cf));
}
template <class T, class Policy>
inline T hypergeometric_0f1_imp(const T& b, const T& z, const Policy& pol)
{
const char* function = "boost::math::hypergeometric_0f1<%1%,%1%>(%1%, %1%)";
BOOST_MATH_STD_USING
// some special cases
if (z == 0)
return T(1);
if ((b <= 0) && (b == floor(b)))
return policies::raise_pole_error<T>(
function,
"Evaluation of 0f1 with nonpositive integer b = %1%.", b, pol);
if (z < -5 && b > -5)
{
// Series is alternating and divergent, need to do something else here,
// Bessel function relation is much more accurate, unless |b| is similarly
// large to |z|, otherwise the CF formula suffers from cancellation when
// the result would be very small.
if (fabs(z / b) > 4)
return hypergeometric_0f1_bessel(b, z, pol);
return hypergeometric_0F1_cf_imp(b, z, pol, function);
}
// evaluation through Taylor series looks
// more precisious than Bessel relation:
// detail::hypergeometric_0f1_bessel(b, z, pol);
return detail::hypergeometric_0f1_generic_series(b, z, pol);
}
} // namespace detail
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type hypergeometric_0F1(T1 b, T2 z, const Policy& /* pol */)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::hypergeometric_0f1_imp<value_type>(
static_cast<value_type>(b),
static_cast<value_type>(z),
forwarding_policy()),
"boost::math::hypergeometric_0f1<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type hypergeometric_0F1(T1 b, T2 z)
{
return hypergeometric_0F1(b, z, policies::policy<>());
}
} } // namespace boost::math
#endif // _BOOST_HYPERGEOMETRIC_2014_04_07_HPP_

View File

@@ -0,0 +1,73 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2014 Anton Bikineev
// Copyright 2014 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2014 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef _BOOST_HYPERGEOMETRIC_1F0_HPP_
#define _BOOST_HYPERGEOMETRIC_1F0_HPP_
#include <boost/math/policies/policy.hpp>
#include <boost/math/policies/error_handling.hpp>
namespace boost { namespace math { namespace detail {
template <class T, class Policy>
inline T hypergeometric_1f0_imp(const T& a, const T& z, const Policy& pol)
{
static const char* function = "boost::math::hypergeometric_1f0<%1%,%1%>(%1%, %1%)";
BOOST_MATH_STD_USING // pow
if (z == 1)
return policies::raise_pole_error<T>(
function,
"Evaluation of 1F0 with z = %1%.",
z,
pol);
if (1 - z < 0)
{
if (floor(a) != a)
return policies::raise_domain_error<T>(function,
"Result is complex when a is non-integral and z > 1, but got z = %1%", z, pol);
}
// more naive and convergent method than series
return pow(T(1 - z), T(-a));
}
} // namespace detail
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type hypergeometric_1f0(T1 a, T2 z, const Policy&)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::hypergeometric_1f0_imp<value_type>(
static_cast<value_type>(a),
static_cast<value_type>(z),
forwarding_policy()),
"boost::math::hypergeometric_1f0<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type hypergeometric_1f0(T1 a, T2 z)
{
return hypergeometric_1f0(a, z, policies::policy<>());
}
} } // namespace boost::math
#endif // _BOOST_HYPERGEOMETRIC_2014_04_07_HPP_