1
0

Initial commit

This commit is contained in:
Tibeuleu
2022-01-19 14:26:18 +01:00
parent 2378dec60c
commit 43889993a9
2044 changed files with 6553027 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
// Copyright (c) 2013 Christopher Kormanyos
// Use, modification and distribution are subject to 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)
//
// This work is based on an earlier work:
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
//
// This header contains implementation details for estimating the zeros
// of the Airy functions airy_ai and airy_bi on the negative real axis.
//
#ifndef _AIRY_AI_BI_ZERO_2013_01_20_HPP_
#define _AIRY_AI_BI_ZERO_2013_01_20_HPP_
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/cbrt.hpp>
namespace boost { namespace math {
namespace detail
{
// Forward declarations of the needed Airy function implementations.
template <class T, class Policy>
T airy_ai_imp(T x, const Policy& pol);
template <class T, class Policy>
T airy_bi_imp(T x, const Policy& pol);
template <class T, class Policy>
T airy_ai_prime_imp(T x, const Policy& pol);
template <class T, class Policy>
T airy_bi_prime_imp(T x, const Policy& pol);
namespace airy_zero
{
template<class T>
T equation_as_10_4_105(const T& z)
{
const T one_over_z (T(1) / z);
const T one_over_z_squared(one_over_z * one_over_z);
const T z_pow_third (boost::math::cbrt(z));
const T z_pow_two_thirds(z_pow_third * z_pow_third);
// Implement the top line of Eq. 10.4.105.
const T fz(z_pow_two_thirds * ((((( + (T(162375596875.0) / 334430208UL)
* one_over_z_squared - ( T(108056875.0) / 6967296UL))
* one_over_z_squared + ( T(77125UL) / 82944UL))
* one_over_z_squared - ( T(5U) / 36U))
* one_over_z_squared + ( T(5U) / 48U))
* one_over_z_squared + (1)));
return fz;
}
namespace airy_ai_zero_detail
{
template<class T>
T initial_guess(const int m)
{
T guess;
switch(m)
{
case 0: { guess = T(0); break; }
case 1: { guess = T(-2.33810741045976703849); break; }
case 2: { guess = T(-4.08794944413097061664); break; }
case 3: { guess = T(-5.52055982809555105913); break; }
case 4: { guess = T(-6.78670809007175899878); break; }
case 5: { guess = T(-7.94413358712085312314); break; }
case 6: { guess = T(-9.02265085334098038016); break; }
case 7: { guess = T(-10.0401743415580859306); break; }
case 8: { guess = T(-11.0085243037332628932); break; }
case 9: { guess = T(-11.9360155632362625170); break; }
case 10:{ guess = T(-12.8287767528657572004); break; }
default:
{
const T t(((boost::math::constants::pi<T>() * 3) * ((T(m) * 4) - 1)) / 8);
guess = -boost::math::detail::airy_zero::equation_as_10_4_105(t);
break;
}
}
return guess;
}
template<class T, class Policy>
class function_object_ai_and_ai_prime
{
public:
function_object_ai_and_ai_prime(const Policy& pol) : my_pol(pol) { }
boost::math::tuple<T, T> operator()(const T& x) const
{
// Return a tuple containing both Ai(x) and Ai'(x).
return boost::math::make_tuple(
boost::math::detail::airy_ai_imp (x, my_pol),
boost::math::detail::airy_ai_prime_imp(x, my_pol));
}
private:
const Policy& my_pol;
const function_object_ai_and_ai_prime& operator=(const function_object_ai_and_ai_prime&);
};
} // namespace airy_ai_zero_detail
namespace airy_bi_zero_detail
{
template<class T>
T initial_guess(const int m)
{
T guess;
switch(m)
{
case 0: { guess = T(0); break; }
case 1: { guess = T(-1.17371322270912792492); break; }
case 2: { guess = T(-3.27109330283635271568); break; }
case 3: { guess = T(-4.83073784166201593267); break; }
case 4: { guess = T(-6.16985212831025125983); break; }
case 5: { guess = T(-7.37676207936776371360); break; }
case 6: { guess = T(-8.49194884650938801345); break; }
case 7: { guess = T(-9.53819437934623888663); break; }
case 8: { guess = T(-10.5299135067053579244); break; }
case 9: { guess = T(-11.4769535512787794379); break; }
case 10: { guess = T(-12.3864171385827387456); break; }
default:
{
const T t(((boost::math::constants::pi<T>() * 3) * ((T(m) * 4) - 3)) / 8);
guess = -boost::math::detail::airy_zero::equation_as_10_4_105(t);
break;
}
}
return guess;
}
template<class T, class Policy>
class function_object_bi_and_bi_prime
{
public:
function_object_bi_and_bi_prime(const Policy& pol) : my_pol(pol) { }
boost::math::tuple<T, T> operator()(const T& x) const
{
// Return a tuple containing both Bi(x) and Bi'(x).
return boost::math::make_tuple(
boost::math::detail::airy_bi_imp (x, my_pol),
boost::math::detail::airy_bi_prime_imp(x, my_pol));
}
private:
const Policy& my_pol;
const function_object_bi_and_bi_prime& operator=(const function_object_bi_and_bi_prime&);
};
} // namespace airy_bi_zero_detail
} // namespace airy_zero
} // namespace detail
} // namespace math
} // namespaces boost
#endif // _AIRY_AI_BI_ZERO_2013_01_20_HPP_

View File

@@ -0,0 +1,665 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2013 John Maddock
// 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_BERNOULLI_DETAIL_HPP
#define BOOST_MATH_BERNOULLI_DETAIL_HPP
#include <boost/config.hpp>
#include <boost/detail/lightweight_mutex.hpp>
#include <boost/math/tools/atomic.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/math/tools/toms748_solve.hpp>
#include <vector>
namespace boost{ namespace math{ namespace detail{
//
// Asymptotic expansion for B2n due to
// Luschny LogB3 formula (http://www.luschny.de/math/primes/bernincl.html)
//
template <class T, class Policy>
T b2n_asymptotic(int n)
{
BOOST_MATH_STD_USING
const T nx = static_cast<T>(n);
const T nx2(nx * nx);
const T approximate_log_of_bernoulli_bn =
((boost::math::constants::half<T>() + nx) * log(nx))
+ ((boost::math::constants::half<T>() - nx) * log(boost::math::constants::pi<T>()))
+ (((T(3) / 2) - nx) * boost::math::constants::ln_two<T>())
+ ((nx * (T(2) - (nx2 * 7) * (1 + ((nx2 * 30) * ((nx2 * 12) - 1))))) / (((nx2 * nx2) * nx2) * 2520));
return ((n / 2) & 1 ? 1 : -1) * (approximate_log_of_bernoulli_bn > tools::log_max_value<T>()
? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, nx, Policy())
: static_cast<T>(exp(approximate_log_of_bernoulli_bn)));
}
template <class T, class Policy>
T t2n_asymptotic(int n)
{
BOOST_MATH_STD_USING
// Just get B2n and convert to a Tangent number:
T t2n = fabs(b2n_asymptotic<T, Policy>(2 * n)) / (2 * n);
T p2 = ldexp(T(1), n);
if(tools::max_value<T>() / p2 < t2n)
return policies::raise_overflow_error<T>("boost::math::tangent_t2n<%1%>(std::size_t)", 0, T(n), Policy());
t2n *= p2;
p2 -= 1;
if(tools::max_value<T>() / p2 < t2n)
return policies::raise_overflow_error<T>("boost::math::tangent_t2n<%1%>(std::size_t)", 0, Policy());
t2n *= p2;
return t2n;
}
//
// We need to know the approximate value of /n/ which will
// cause bernoulli_b2n<T>(n) to return infinity - this allows
// us to elude a great deal of runtime checking for values below
// n, and only perform the full overflow checks when we know that we're
// getting close to the point where our calculations will overflow.
// We use Luschny's LogB3 formula (http://www.luschny.de/math/primes/bernincl.html)
// to find the limit, and since we're dealing with the log of the Bernoulli numbers
// we need only perform the calculation at double precision and not with T
// (which may be a multiprecision type). The limit returned is within 1 of the true
// limit for all the types tested. Note that although the code below is basically
// the same as b2n_asymptotic above, it has been recast as a continuous real-valued
// function as this makes the root finding go smoother/faster. It also omits the
// sign of the Bernoulli number.
//
struct max_bernoulli_root_functor
{
max_bernoulli_root_functor(long long t) : target(static_cast<double>(t)) {}
double operator()(double n)
{
BOOST_MATH_STD_USING
// Luschny LogB3(n) formula.
const double nx2(n * n);
const double approximate_log_of_bernoulli_bn
= ((boost::math::constants::half<double>() + n) * log(n))
+ ((boost::math::constants::half<double>() - n) * log(boost::math::constants::pi<double>()))
+ (((double(3) / 2) - n) * boost::math::constants::ln_two<double>())
+ ((n * (2 - (nx2 * 7) * (1 + ((nx2 * 30) * ((nx2 * 12) - 1))))) / (((nx2 * nx2) * nx2) * 2520));
return approximate_log_of_bernoulli_bn - target;
}
private:
double target;
};
template <class T, class Policy>
inline std::size_t find_bernoulli_overflow_limit(const mpl::false_&)
{
long long t = lltrunc(boost::math::tools::log_max_value<T>());
max_bernoulli_root_functor fun(t);
boost::math::tools::equal_floor tol;
boost::uintmax_t max_iter = boost::math::policies::get_max_root_iterations<Policy>();
return static_cast<std::size_t>(boost::math::tools::toms748_solve(fun, sqrt(double(t)), double(t), tol, max_iter).first) / 2;
}
template <class T, class Policy>
inline std::size_t find_bernoulli_overflow_limit(const mpl::true_&)
{
return max_bernoulli_index<bernoulli_imp_variant<T>::value>::value;
}
template <class T, class Policy>
std::size_t b2n_overflow_limit()
{
// This routine is called at program startup if it's called at all:
// that guarantees safe initialization of the static variable.
typedef mpl::bool_<(bernoulli_imp_variant<T>::value >= 1) && (bernoulli_imp_variant<T>::value <= 3)> tag_type;
static const std::size_t lim = find_bernoulli_overflow_limit<T, Policy>(tag_type());
return lim;
}
//
// The tangent numbers grow larger much more rapidly than the Bernoulli numbers do....
// so to compute the Bernoulli numbers from the tangent numbers, we need to avoid spurious
// overflow in the calculation, we can do this by scaling all the tangent number by some scale factor:
//
template <class T>
inline typename enable_if_c<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::radix == 2), T>::type tangent_scale_factor()
{
BOOST_MATH_STD_USING
return ldexp(T(1), std::numeric_limits<T>::min_exponent + 5);
}
template <class T>
inline typename disable_if_c<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::radix == 2), T>::type tangent_scale_factor()
{
return tools::min_value<T>() * 16;
}
//
// Initializer: ensure all our constants are initialized prior to the first call of main:
//
template <class T, class Policy>
struct bernoulli_initializer
{
struct init
{
init()
{
//
// We call twice, once to initialize our static table, and once to
// initialize our dymanic table:
//
boost::math::bernoulli_b2n<T>(2, Policy());
#ifndef BOOST_NO_EXCEPTIONS
try{
#endif
boost::math::bernoulli_b2n<T>(max_bernoulli_b2n<T>::value + 1, Policy());
#ifndef BOOST_NO_EXCEPTIONS
} catch(const std::overflow_error&){}
#endif
boost::math::tangent_t2n<T>(2, Policy());
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename bernoulli_initializer<T, Policy>::init bernoulli_initializer<T, Policy>::initializer;
//
// We need something to act as a cache for our calculated Bernoulli numbers. In order to
// ensure both fast access and thread safety, we need a stable table which may be extended
// in size, but which never reallocates: that way values already calculated may be accessed
// concurrently with another thread extending the table with new values.
//
// Very very simple vector class that will never allocate more than once, we could use
// boost::container::static_vector here, but that allocates on the stack, which may well
// cause issues for the amount of memory we want in the extreme case...
//
template <class T>
struct fixed_vector : private std::allocator<T>
{
typedef unsigned size_type;
typedef T* iterator;
typedef const T* const_iterator;
fixed_vector() : m_used(0)
{
std::size_t overflow_limit = 5 + b2n_overflow_limit<T, policies::policy<> >();
m_capacity = static_cast<unsigned>((std::min)(overflow_limit, static_cast<std::size_t>(100000u)));
m_data = this->allocate(m_capacity);
}
~fixed_vector()
{
#ifdef BOOST_NO_CXX11_ALLOCATOR
for(unsigned i = 0; i < m_used; ++i)
this->destroy(&m_data[i]);
this->deallocate(m_data, m_capacity);
#else
typedef std::allocator<T> allocator_type;
typedef std::allocator_traits<allocator_type> allocator_traits;
allocator_type& alloc = *this;
for(unsigned i = 0; i < m_used; ++i)
allocator_traits::destroy(alloc, &m_data[i]);
allocator_traits::deallocate(alloc, m_data, m_capacity);
#endif
}
T& operator[](unsigned n) { BOOST_ASSERT(n < m_used); return m_data[n]; }
const T& operator[](unsigned n)const { BOOST_ASSERT(n < m_used); return m_data[n]; }
unsigned size()const { return m_used; }
unsigned size() { return m_used; }
void resize(unsigned n, const T& val)
{
if(n > m_capacity)
{
BOOST_THROW_EXCEPTION(std::runtime_error("Exhausted storage for Bernoulli numbers."));
}
for(unsigned i = m_used; i < n; ++i)
new (m_data + i) T(val);
m_used = n;
}
void resize(unsigned n) { resize(n, T()); }
T* begin() { return m_data; }
T* end() { return m_data + m_used; }
T* begin()const { return m_data; }
T* end()const { return m_data + m_used; }
unsigned capacity()const { return m_capacity; }
void clear() { m_used = 0; }
private:
T* m_data;
unsigned m_used, m_capacity;
};
template <class T, class Policy>
class bernoulli_numbers_cache
{
public:
bernoulli_numbers_cache() : m_overflow_limit((std::numeric_limits<std::size_t>::max)())
#if defined(BOOST_HAS_THREADS) && !defined(BOOST_MATH_NO_ATOMIC_INT)
, m_counter(0)
#endif
, m_current_precision(boost::math::tools::digits<T>())
{}
typedef fixed_vector<T> container_type;
void tangent(std::size_t m)
{
static const std::size_t min_overflow_index = b2n_overflow_limit<T, Policy>() - 1;
tn.resize(static_cast<typename container_type::size_type>(m), T(0U));
BOOST_MATH_INSTRUMENT_VARIABLE(min_overflow_index);
std::size_t prev_size = m_intermediates.size();
m_intermediates.resize(m, T(0U));
if(prev_size == 0)
{
m_intermediates[1] = tangent_scale_factor<T>() /*T(1U)*/;
tn[0U] = T(0U);
tn[1U] = tangent_scale_factor<T>()/* T(1U)*/;
BOOST_MATH_INSTRUMENT_VARIABLE(tn[0]);
BOOST_MATH_INSTRUMENT_VARIABLE(tn[1]);
}
for(std::size_t i = std::max<size_t>(2, prev_size); i < m; i++)
{
bool overflow_check = false;
if(i >= min_overflow_index && (boost::math::tools::max_value<T>() / (i-1) < m_intermediates[1]) )
{
std::fill(tn.begin() + i, tn.end(), boost::math::tools::max_value<T>());
break;
}
m_intermediates[1] = m_intermediates[1] * (i-1);
for(std::size_t j = 2; j <= i; j++)
{
overflow_check =
(i >= min_overflow_index) && (
(boost::math::tools::max_value<T>() / (i - j) < m_intermediates[j])
|| (boost::math::tools::max_value<T>() / (i - j + 2) < m_intermediates[j-1])
|| (boost::math::tools::max_value<T>() - m_intermediates[j] * (i - j) < m_intermediates[j-1] * (i - j + 2))
|| ((boost::math::isinf)(m_intermediates[j]))
);
if(overflow_check)
{
std::fill(tn.begin() + i, tn.end(), boost::math::tools::max_value<T>());
break;
}
m_intermediates[j] = m_intermediates[j] * (i - j) + m_intermediates[j-1] * (i - j + 2);
}
if(overflow_check)
break; // already filled the tn...
tn[static_cast<typename container_type::size_type>(i)] = m_intermediates[i];
BOOST_MATH_INSTRUMENT_VARIABLE(i);
BOOST_MATH_INSTRUMENT_VARIABLE(tn[static_cast<typename container_type::size_type>(i)]);
}
}
void tangent_numbers_series(const std::size_t m)
{
BOOST_MATH_STD_USING
static const std::size_t min_overflow_index = b2n_overflow_limit<T, Policy>() - 1;
typename container_type::size_type old_size = bn.size();
tangent(m);
bn.resize(static_cast<typename container_type::size_type>(m));
if(!old_size)
{
bn[0] = 1;
old_size = 1;
}
T power_two(ldexp(T(1), static_cast<int>(2 * old_size)));
for(std::size_t i = old_size; i < m; i++)
{
T b(static_cast<T>(i * 2));
//
// Not only do we need to take care to avoid spurious over/under flow in
// the calculation, but we also need to avoid overflow altogether in case
// we're calculating with a type where "bad things" happen in that case:
//
b = b / (power_two * tangent_scale_factor<T>());
b /= (power_two - 1);
bool overflow_check = (i >= min_overflow_index) && (tools::max_value<T>() / tn[static_cast<typename container_type::size_type>(i)] < b);
if(overflow_check)
{
m_overflow_limit = i;
while(i < m)
{
b = std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : tools::max_value<T>();
bn[static_cast<typename container_type::size_type>(i)] = ((i % 2U) ? b : T(-b));
++i;
}
break;
}
else
{
b *= tn[static_cast<typename container_type::size_type>(i)];
}
power_two = ldexp(power_two, 2);
const bool b_neg = i % 2 == 0;
bn[static_cast<typename container_type::size_type>(i)] = ((!b_neg) ? b : T(-b));
}
}
template <class OutputIterator>
OutputIterator copy_bernoulli_numbers(OutputIterator out, std::size_t start, std::size_t n, const Policy& pol)
{
//
// There are basically 3 thread safety options:
//
// 1) There are no threads (BOOST_HAS_THREADS is not defined).
// 2) There are threads, but we do not have a true atomic integer type,
// in this case we just use a mutex to guard against race conditions.
// 3) There are threads, and we have an atomic integer: in this case we can
// use the double-checked locking pattern to avoid thread synchronisation
// when accessing values already in the cache.
//
// First off handle the common case for overflow and/or asymptotic expansion:
//
if(start + n > bn.capacity())
{
if(start < bn.capacity())
{
out = copy_bernoulli_numbers(out, start, bn.capacity() - start, pol);
n -= bn.capacity() - start;
start = static_cast<std::size_t>(bn.capacity());
}
if(start < b2n_overflow_limit<T, Policy>() + 2u)
{
for(; n; ++start, --n)
{
*out = b2n_asymptotic<T, Policy>(static_cast<typename container_type::size_type>(start * 2U));
++out;
}
}
for(; n; ++start, --n)
{
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(start), pol);
++out;
}
return out;
}
#if !defined(BOOST_HAS_THREADS)
//
// Single threaded code, very simple:
//
if(m_current_precision < boost::math::tools::digits<T>())
{
bn.clear();
tn.clear();
m_intermediates.clear();
m_current_precision = boost::math::tools::digits<T>();
}
if(start + n >= bn.size())
{
std::size_t new_size = (std::min)((std::max)((std::max)(std::size_t(start + n), std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
tangent_numbers_series(new_size);
}
for(std::size_t i = (std::max)(std::size_t(max_bernoulli_b2n<T>::value + 1), start); i < start + n; ++i)
{
*out = (i >= m_overflow_limit) ? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol) : bn[i];
++out;
}
#elif defined(BOOST_MATH_NO_ATOMIC_INT)
//
// We need to grab a mutex every time we get here, for both readers and writers:
//
boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
if(m_current_precision < boost::math::tools::digits<T>())
{
bn.clear();
tn.clear();
m_intermediates.clear();
m_current_precision = boost::math::tools::digits<T>();
}
if(start + n >= bn.size())
{
std::size_t new_size = (std::min)((std::max)((std::max)(std::size_t(start + n), std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
tangent_numbers_series(new_size);
}
for(std::size_t i = (std::max)(std::size_t(max_bernoulli_b2n<T>::value + 1), start); i < start + n; ++i)
{
*out = (i >= m_overflow_limit) ? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol) : bn[i];
++out;
}
#else
//
// Double-checked locking pattern, lets us access cached already cached values
// without locking:
//
// Get the counter and see if we need to calculate more constants:
//
if((static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|| (static_cast<int>(m_current_precision.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < boost::math::tools::digits<T>()))
{
boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
if((static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|| (static_cast<int>(m_current_precision.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < boost::math::tools::digits<T>()))
{
if(static_cast<int>(m_current_precision.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < boost::math::tools::digits<T>())
{
bn.clear();
tn.clear();
m_intermediates.clear();
m_counter.store(0, BOOST_MATH_ATOMIC_NS::memory_order_release);
m_current_precision = boost::math::tools::digits<T>();
}
if(start + n >= bn.size())
{
std::size_t new_size = (std::min)((std::max)((std::max)(std::size_t(start + n), std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
tangent_numbers_series(new_size);
}
m_counter.store(static_cast<atomic_integer_type>(bn.size()), BOOST_MATH_ATOMIC_NS::memory_order_release);
}
}
for(std::size_t i = (std::max)(static_cast<std::size_t>(max_bernoulli_b2n<T>::value + 1), start); i < start + n; ++i)
{
*out = (i >= m_overflow_limit) ? policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol) : bn[static_cast<typename container_type::size_type>(i)];
++out;
}
#endif
return out;
}
template <class OutputIterator>
OutputIterator copy_tangent_numbers(OutputIterator out, std::size_t start, std::size_t n, const Policy& pol)
{
//
// There are basically 3 thread safety options:
//
// 1) There are no threads (BOOST_HAS_THREADS is not defined).
// 2) There are threads, but we do not have a true atomic integer type,
// in this case we just use a mutex to guard against race conditions.
// 3) There are threads, and we have an atomic integer: in this case we can
// use the double-checked locking pattern to avoid thread synchronisation
// when accessing values already in the cache.
//
//
// First off handle the common case for overflow and/or asymptotic expansion:
//
if(start + n > bn.capacity())
{
if(start < bn.capacity())
{
out = copy_tangent_numbers(out, start, bn.capacity() - start, pol);
n -= bn.capacity() - start;
start = static_cast<std::size_t>(bn.capacity());
}
if(start < b2n_overflow_limit<T, Policy>() + 2u)
{
for(; n; ++start, --n)
{
*out = t2n_asymptotic<T, Policy>(static_cast<typename container_type::size_type>(start));
++out;
}
}
for(; n; ++start, --n)
{
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(start), pol);
++out;
}
return out;
}
#if !defined(BOOST_HAS_THREADS)
//
// Single threaded code, very simple:
//
if(m_current_precision < boost::math::tools::digits<T>())
{
bn.clear();
tn.clear();
m_intermediates.clear();
m_current_precision = boost::math::tools::digits<T>();
}
if(start + n >= bn.size())
{
std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
tangent_numbers_series(new_size);
}
for(std::size_t i = start; i < start + n; ++i)
{
if(i >= m_overflow_limit)
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
else
{
if(tools::max_value<T>() * tangent_scale_factor<T>() < tn[static_cast<typename container_type::size_type>(i)])
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
else
*out = tn[static_cast<typename container_type::size_type>(i)] / tangent_scale_factor<T>();
}
++out;
}
#elif defined(BOOST_MATH_NO_ATOMIC_INT)
//
// We need to grab a mutex every time we get here, for both readers and writers:
//
boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
if(m_current_precision < boost::math::tools::digits<T>())
{
bn.clear();
tn.clear();
m_intermediates.clear();
m_current_precision = boost::math::tools::digits<T>();
}
if(start + n >= bn.size())
{
std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
tangent_numbers_series(new_size);
}
for(std::size_t i = start; i < start + n; ++i)
{
if(i >= m_overflow_limit)
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
else
{
if(tools::max_value<T>() * tangent_scale_factor<T>() < tn[static_cast<typename container_type::size_type>(i)])
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
else
*out = tn[static_cast<typename container_type::size_type>(i)] / tangent_scale_factor<T>();
}
++out;
}
#else
//
// Double-checked locking pattern, lets us access cached already cached values
// without locking:
//
// Get the counter and see if we need to calculate more constants:
//
if((static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|| (static_cast<int>(m_current_precision.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < boost::math::tools::digits<T>()))
{
boost::detail::lightweight_mutex::scoped_lock l(m_mutex);
if((static_cast<std::size_t>(m_counter.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < start + n)
|| (static_cast<int>(m_current_precision.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < boost::math::tools::digits<T>()))
{
if(static_cast<int>(m_current_precision.load(BOOST_MATH_ATOMIC_NS::memory_order_consume)) < boost::math::tools::digits<T>())
{
bn.clear();
tn.clear();
m_intermediates.clear();
m_counter.store(0, BOOST_MATH_ATOMIC_NS::memory_order_release);
m_current_precision = boost::math::tools::digits<T>();
}
if(start + n >= bn.size())
{
std::size_t new_size = (std::min)((std::max)((std::max)(start + n, std::size_t(bn.size() + 20)), std::size_t(50)), std::size_t(bn.capacity()));
tangent_numbers_series(new_size);
}
m_counter.store(static_cast<atomic_integer_type>(bn.size()), BOOST_MATH_ATOMIC_NS::memory_order_release);
}
}
for(std::size_t i = start; i < start + n; ++i)
{
if(i >= m_overflow_limit)
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
else
{
if(tools::max_value<T>() * tangent_scale_factor<T>() < tn[static_cast<typename container_type::size_type>(i)])
*out = policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(std::size_t)", 0, T(i), pol);
else
*out = tn[static_cast<typename container_type::size_type>(i)] / tangent_scale_factor<T>();
}
++out;
}
#endif
return out;
}
private:
//
// The caches for Bernoulli and tangent numbers, once allocated,
// these must NEVER EVER reallocate as it breaks our thread
// safety guarantees:
//
fixed_vector<T> bn, tn;
std::vector<T> m_intermediates;
// The value at which we know overflow has already occurred for the Bn:
std::size_t m_overflow_limit;
#if !defined(BOOST_HAS_THREADS)
int m_current_precision;
#elif defined(BOOST_MATH_NO_ATOMIC_INT)
boost::detail::lightweight_mutex m_mutex;
int m_current_precision;
#else
boost::detail::lightweight_mutex m_mutex;
atomic_counter_type m_counter, m_current_precision;
#endif
};
template <class T, class Policy>
inline bernoulli_numbers_cache<T, Policy>& get_bernoulli_numbers_cache()
{
//
// Force this function to be called at program startup so all the static variables
// get initailzed then (thread safety).
//
bernoulli_initializer<T, Policy>::force_instantiate();
static bernoulli_numbers_cache<T, Policy> data;
return data;
}
}}}
#endif // BOOST_MATH_BERNOULLI_DETAIL_HPP

View File

@@ -0,0 +1,87 @@
// Copyright (c) 2013 Anton Bikineev
// Use, modification and distribution are subject to 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)
//
// This is a partial header, do not include on it's own!!!
//
// Linear combination for bessel derivatives are defined here
#ifndef BOOST_MATH_SF_DETAIL_BESSEL_DERIVATIVES_LINEAR_HPP
#define BOOST_MATH_SF_DETAIL_BESSEL_DERIVATIVES_LINEAR_HPP
#ifdef _MSC_VER
#pragma once
#endif
namespace boost{ namespace math{ namespace detail{
template <class T, class Tag, class Policy>
inline T bessel_j_derivative_linear(T v, T x, Tag tag, Policy pol)
{
return (boost::math::detail::cyl_bessel_j_imp<T>(v-1, x, tag, pol) - boost::math::detail::cyl_bessel_j_imp<T>(v+1, x, tag, pol)) / 2;
}
template <class T, class Policy>
inline T bessel_j_derivative_linear(T v, T x, const bessel_int_tag& tag, Policy pol)
{
return (boost::math::detail::cyl_bessel_j_imp<T>(itrunc(v-1), x, tag, pol) - boost::math::detail::cyl_bessel_j_imp<T>(itrunc(v+1), x, tag, pol)) / 2;
}
template <class T, class Policy>
inline T sph_bessel_j_derivative_linear(unsigned v, T x, Policy pol)
{
return (v / x) * boost::math::detail::sph_bessel_j_imp<T>(v, x, pol) - boost::math::detail::sph_bessel_j_imp<T>(v+1, x, pol);
}
template <class T, class Policy>
inline T bessel_i_derivative_linear(T v, T x, Policy pol)
{
T result = boost::math::detail::cyl_bessel_i_imp<T>(v - 1, x, pol);
if(result >= tools::max_value<T>())
return result; // result is infinite
T result2 = boost::math::detail::cyl_bessel_i_imp<T>(v + 1, x, pol);
if(result2 >= tools::max_value<T>() - result)
return result2; // result is infinite
return (result + result2) / 2;
}
template <class T, class Tag, class Policy>
inline T bessel_k_derivative_linear(T v, T x, Tag tag, Policy pol)
{
T result = boost::math::detail::cyl_bessel_k_imp<T>(v - 1, x, tag, pol);
if(result >= tools::max_value<T>())
return -result; // result is infinite
T result2 = boost::math::detail::cyl_bessel_k_imp<T>(v + 1, x, tag, pol);
if(result2 >= tools::max_value<T>() - result)
return -result2; // result is infinite
return (result + result2) / -2;
}
template <class T, class Policy>
inline T bessel_k_derivative_linear(T v, T x, const bessel_int_tag& tag, Policy pol)
{
return (boost::math::detail::cyl_bessel_k_imp<T>(itrunc(v-1), x, tag, pol) + boost::math::detail::cyl_bessel_k_imp<T>(itrunc(v+1), x, tag, pol)) / -2;
}
template <class T, class Tag, class Policy>
inline T bessel_y_derivative_linear(T v, T x, Tag tag, Policy pol)
{
return (boost::math::detail::cyl_neumann_imp<T>(v-1, x, tag, pol) - boost::math::detail::cyl_neumann_imp<T>(v+1, x, tag, pol)) / 2;
}
template <class T, class Policy>
inline T bessel_y_derivative_linear(T v, T x, const bessel_int_tag& tag, Policy pol)
{
return (boost::math::detail::cyl_neumann_imp<T>(itrunc(v-1), x, tag, pol) - boost::math::detail::cyl_neumann_imp<T>(itrunc(v+1), x, tag, pol)) / 2;
}
template <class T, class Policy>
inline T sph_neumann_derivative_linear(unsigned v, T x, Policy pol)
{
return (v / x) * boost::math::detail::sph_neumann_imp<T>(v, x, pol) - boost::math::detail::sph_neumann_imp<T>(v+1, x, pol);
}
}}} // namespaces
#endif // BOOST_MATH_SF_DETAIL_BESSEL_DERIVATIVES_LINEAR_HPP

View File

@@ -0,0 +1,554 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2017 John Maddock
// Use, modification and distribution are subject to 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_BESSEL_I0_HPP
#define BOOST_MATH_BESSEL_I0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/assert.hpp>
// Modified Bessel function of the first kind of order zero
// we use the approximating forms derived in:
// "Rational Approximations for the Modified Bessel Function of the First Kind - I0(x) for Computations with Double Precision"
// by Pavel Holoborodko,
// see http://www.advanpix.com/2015/11/11/rational-approximations-for-the-modified-bessel-function-of-the-first-kind-i0-computations-double-precision
// The actual coefficients used are our own, and extend Pavel's work to precision's other than double.
namespace boost { namespace math { namespace detail{
template <typename T>
T bessel_i0(const T& x);
template <class T, class tag>
struct bessel_i0_initializer
{
struct init
{
init()
{
do_init(tag());
}
static void do_init(const mpl::int_<64>&)
{
bessel_i0(T(1));
bessel_i0(T(8));
bessel_i0(T(12));
bessel_i0(T(40));
bessel_i0(T(101));
}
static void do_init(const mpl::int_<113>&)
{
bessel_i0(T(1));
bessel_i0(T(10));
bessel_i0(T(20));
bessel_i0(T(40));
bessel_i0(T(101));
}
template <class U>
static void do_init(const U&) {}
void force_instantiate()const {}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class tag>
const typename bessel_i0_initializer<T, tag>::init bessel_i0_initializer<T, tag>::initializer;
template <typename T, int N>
T bessel_i0_imp(const T&, const mpl::int_<N>&)
{
BOOST_ASSERT(0);
return 0;
}
template <typename T>
T bessel_i0_imp(const T& x, const mpl::int_<24>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
// Max error in interpolated form: 3.929e-08
// Max Error found at float precision = Poly: 1.991226e-07
static const float P[] = {
1.00000003928615375e+00f,
2.49999576572179639e-01f,
2.77785268558399407e-02f,
1.73560257755821695e-03f,
6.96166518788906424e-05f,
1.89645733877137904e-06f,
4.29455004657565361e-08f,
3.90565476357034480e-10f,
1.48095934745267240e-11f
};
T a = x * x / 4;
return a * boost::math::tools::evaluate_polynomial(P, a) + 1;
}
else if(x < 50)
{
// Max error in interpolated form: 5.195e-08
// Max Error found at float precision = Poly: 8.502534e-08
static const float P[] = {
3.98942651588301770e-01f,
4.98327234176892844e-02f,
2.91866904423115499e-02f,
1.35614940793742178e-02f,
1.31409251787866793e-01f
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else
{
// Max error in interpolated form: 1.782e-09
// Max Error found at float precision = Poly: 6.473568e-08
static const float P[] = {
3.98942391532752700e-01f,
4.98455950638200020e-02f,
2.94835666900682535e-02f
};
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i0_imp(const T& x, const mpl::int_<53>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
// Bessel I0 over[10 ^ -16, 7.75]
// Max error in interpolated form : 3.042e-18
// Max Error found at double precision = Poly : 5.106609e-16 Cheb : 5.239199e-16
static const double P[] = {
1.00000000000000000e+00,
2.49999999999999909e-01,
2.77777777777782257e-02,
1.73611111111023792e-03,
6.94444444453352521e-05,
1.92901234513219920e-06,
3.93675991102510739e-08,
6.15118672704439289e-10,
7.59407002058973446e-12,
7.59389793369836367e-14,
6.27767773636292611e-16,
4.34709704153272287e-18,
2.63417742690109154e-20,
1.13943037744822825e-22,
9.07926920085624812e-25
};
T a = x * x / 4;
return a * boost::math::tools::evaluate_polynomial(P, a) + 1;
}
else if(x < 500)
{
// Max error in interpolated form : 1.685e-16
// Max Error found at double precision = Poly : 2.575063e-16 Cheb : 2.247615e+00
static const double P[] = {
3.98942280401425088e-01,
4.98677850604961985e-02,
2.80506233928312623e-02,
2.92211225166047873e-02,
4.44207299493659561e-02,
1.30970574605856719e-01,
-3.35052280231727022e+00,
2.33025711583514727e+02,
-1.13366350697172355e+04,
4.24057674317867331e+05,
-1.23157028595698731e+07,
2.80231938155267516e+08,
-5.01883999713777929e+09,
7.08029243015109113e+10,
-7.84261082124811106e+11,
6.76825737854096565e+12,
-4.49034849696138065e+13,
2.24155239966958995e+14,
-8.13426467865659318e+14,
2.02391097391687777e+15,
-3.08675715295370878e+15,
2.17587543863819074e+15
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else
{
// Max error in interpolated form : 2.437e-18
// Max Error found at double precision = Poly : 1.216719e-16
static const double P[] = {
3.98942280401432905e-01,
4.98677850491434560e-02,
2.80506308916506102e-02,
2.92179096853915176e-02,
4.53371208762579442e-02
};
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i0_imp(const T& x, const mpl::int_<64>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
// Bessel I0 over[10 ^ -16, 7.75]
// Max error in interpolated form : 3.899e-20
// Max Error found at float80 precision = Poly : 1.770840e-19
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 9.99999999999999999961011629e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.50000000000000001321873912e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.77777777777777703400424216e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.73611111111112764793802701e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.94444444444251461247253525e-05),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.92901234569262206386118739e-06),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.93675988851131457141005209e-08),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.15118734688297476454205352e-10),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.59405797058091016449222685e-12),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.59406599631719800679835140e-14),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.27598961062070013516660425e-16),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.35920318970387940278362992e-18),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.57372492687715452949437981e-20),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.33908663475949906992942204e-22),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.15976668870980234582896010e-25),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.46240478946376069211156548e-27)
};
T a = x * x / 4;
return a * boost::math::tools::evaluate_polynomial(P, a) + 1;
}
else if(x < 10)
{
// Maximum Deviation Found: 6.906e-21
// Expected Error Term : -6.903e-21
// Maximum Relative Change in Control Points : 1.631e-04
// Max Error found at float80 precision = Poly : 7.811948e-21
static const T Y = 4.051098823547363281250e-01f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -6.158081780620616479492e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.883635969834048766148e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.892782002476195771920e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.478784996478070170327e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.988611837308006851257e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.140133766747436806179e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.117316447921276453271e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.942353667455141676001e+04),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.493482682461387081534e+05),
BOOST_MATH_BIG_CONSTANT(T, 64, -5.228100538921466124653e+05),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.195279248600467989454e+06),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.601530760654337045917e+06),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.504921137873298402679e+05)
};
return exp(x) * (boost::math::tools::evaluate_polynomial(P, T(1 / x)) + Y) / sqrt(x);
}
else if(x < 15)
{
// Maximum Deviation Found: 4.083e-21
// Expected Error Term : -4.025e-21
// Maximum Relative Change in Control Points : 1.304e-03
// Max Error found at float80 precision = Poly : 2.303527e-20
static const T Y = 4.033188819885253906250e-01f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -4.376373876116109401062e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.982899138682911273321e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.109477529533515397644e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.163760580110576407673e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.776501832837367371883e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.101478069227776656318e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.892071912448960299773e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.417739279982328117483e+04),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.296963447724067390552e+05),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.598589306710589358747e+06),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.903662411851774878322e+06),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.622677059040339516093e+07),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.227776578828667629347e+07),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.727797957441040896878e+07)
};
return exp(x) * (boost::math::tools::evaluate_polynomial(P, T(1 / x)) + Y) / sqrt(x);
}
else if(x < 50)
{
// Max error in interpolated form: 1.035e-21
// Max Error found at float80 precision = Poly: 1.885872e-21
static const T Y = 4.011702537536621093750e-01f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -2.227973351806078464328e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.986778486088017419036e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.805066823812285310011e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.921443721160964964623e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.517504941996594744052e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.316922639868793684401e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.535891099168810015433e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.706078229522448308087e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.351015763079160914632e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.948809013999277355098e+04),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.967598958582595361757e+05),
BOOST_MATH_BIG_CONSTANT(T, 64, -6.346924657995383019558e+06),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.998794574259956613472e+07),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.016371355801690142095e+08),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.768791455631826490838e+09),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.441995678177349895640e+09),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.482292669974971387738e+09)
};
return exp(x) * (boost::math::tools::evaluate_polynomial(P, T(1 / x)) + Y) / sqrt(x);
}
else
{
// Bessel I0 over[50, INF]
// Max error in interpolated form : 5.587e-20
// Max Error found at float80 precision = Poly : 8.776852e-20
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98942280401432677955074061e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.98677850501789875615574058e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.80506290908675604202206833e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.92194052159035901631494784e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.47422430732256364094681137e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.05971614435738691235525172e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.29180522595459823234266708e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.15122547776140254569073131e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.48491812136365376477357324e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.45569740166506688169730713e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.66857566379480730407063170e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.71924083955641197750323901e+05),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.74276685704579268845870586e+06),
BOOST_MATH_BIG_CONSTANT(T, 64, -8.89753803265734681907148778e+07),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.82590905134996782086242180e+08),
BOOST_MATH_BIG_CONSTANT(T, 64, -7.30623197145529889358596301e+09),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.27310000726207055200805893e+10),
BOOST_MATH_BIG_CONSTANT(T, 64, -6.64365417189215599168817064e+10)
};
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i0_imp(const T& x, const mpl::int_<113>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
// Bessel I0 over[10 ^ -34, 7.75]
// Max error in interpolated form : 1.274e-34
// Max Error found at float128 precision = Poly : 3.096091e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0000000000000000000000000000000001273856e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.4999999999999999999999999999999107477496e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.7777777777777777777777777777881795230918e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.7361111111111111111111111106290091648808e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.9444444444444444444444445629960334523101e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.9290123456790123456790105563456483249753e-06),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.9367598891408415217940836339080514004844e-08),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.1511873267825648777900014857992724731476e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.5940584281266233066162999610732449709209e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.5940584281266232783124723601470051895304e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.2760813455591936763439337059117957836078e-16),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.3583898233049738471136482147779094353096e-18),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.5789288895299965395422423848480340736308e-20),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.3157800456718804437960453545507623434606e-22),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.8479113149412360748032684260932041506493e-25),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.2843403488398038539283241944594140493394e-27),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.9042925594356556196790242908697582021825e-30),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.4395919891312152120710245152115597111101e-32),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.7580986145276689333214547502373003196707e-35),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.6886514018062348877723837017198859723889e-37),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.8540558465757554512570197585002702777999e-40),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.4684706070226893763741850944911705726436e-43),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.0210715309399646335858150349406935414314e-45)
};
T a = x * x / 4;
return a * boost::math::tools::evaluate_polynomial(P, a) + 1;
}
else if(x < 15)
{
// Bessel I0 over[7.75, 15]
// Max error in interpolated form : 7.534e-35
// Max Error found at float128 precision = Poly : 6.123912e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 9.9999999999999999992388573069504617493518e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.5000000000000000007304739268173096975340e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.7777777777777777744261405400543564492074e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.7361111111111111209006987259719750726867e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.9444444444444442399703186871329381908321e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.9290123456790126709286741580242189785431e-06),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.9367598891408374246503061422528266924389e-08),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.1511873267826068395343047827801353170966e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.5940584281262673459688011737168286944521e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.5940584281291583769928563167645746144508e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.2760813455438840231126529638737436950274e-16),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.3583898233839583885132809584770578894948e-18),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.5789288891798658971960571838369339742994e-20),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.3157800470129311623308216856009970266088e-22),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.8479112701534604520063520412207286692581e-25),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.2843404822552330714586265081801727491890e-27),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.9042888166225242675881424439818162458179e-30),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.4396027771820721384198604723320045236973e-32),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.7577659910606076328136207973456511895030e-35),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.6896548123724136624716224328803899914646e-37),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.8285850162160539150210466453921758781984e-40),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.9419071894227736216423562425429524883562e-43),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.4720374049498608905571855665134539425038e-45),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.7763533278527958112907118930154738930378e-48),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.1213839473168678646697528580511702663617e-51),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0648035313124146852372607519737686740964e-53),
-BOOST_MATH_BIG_CONSTANT(T, 113, 5.1255595184052024349371058585102280860878e-57),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.4652470895944157957727948355523715335882e-59)
};
T a = x * x / 4;
return a * boost::math::tools::evaluate_polynomial(P, a) + 1;
}
else if(x < 30)
{
// Max error in interpolated form : 1.808e-34
// Max Error found at float128 precision = Poly : 2.399403e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 3.9894228040870793650581242239624530714032e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.9867780576714783790784348982178607842250e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.8051948347934462928487999569249907599510e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.8971143420388958551176254291160976367263e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.8197359701715582763961322341827341098897e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.3430484862908317377522273217643346601271e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.7884507603213662610604413960838990199224e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.8304926482356755790062999202373909300514e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.8867173178574875515293357145875120137676e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.4261178812193528551544261731796888257644e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.6453010340778116475788083817762403540097e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.0432401330113978669454035365747869477960e+10),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.2462165331309799059332310595587606836357e+12),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.3299800389951335932792950236410844978273e+13),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.5748218240248714177527965706790413406639e+14),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.8330014378766930869945511450377736037385e+15),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.8494610073827453236940544799030787866218e+17),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.7244661371420647691301043350229977856476e+18),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.2386378807889388140099109087465781254321e+20),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.1104000573102013529518477353943384110982e+21),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.9426541092239879262282594572224300191016e+22),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.4061439136301913488512592402635688101020e+23),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.2836554760521986358980180942859101564671e+24),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.6270285589905206294944214795661236766988e+25),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.7278631455211972017740134341610659484259e+26),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.1971734473772196124736986948034978906801e+26),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.8669270707172568763908838463689093500098e+27),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.2368879358870281916900125550129211146626e+28),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.8296235063297831758204519071113999839858e+28),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.1253861666023020670144616019148954773662e+28),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.8809536950051955163648980306847791014734e+28) };
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else if(x < 100)
{
// Bessel I0 over[30, 100]
// Max error in interpolated form : 1.487e-34
// Max Error found at float128 precision = Poly : 1.929924e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 3.9894228040143267793996798658172135362278e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.9867785050179084714910130342157246539820e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.8050629090725751585266360464766768437048e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.9219405302833158254515212437025679637597e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.4742214371598631578107310396249912330627e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.0602983776478659136184969363625092585520e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.2839507231977478205885469900971893734770e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.8925739165733823730525449511456529001868e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.4238082222874015159424842335385854632223e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.6759648427182491050716309699208988458050e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.7292246491169360014875196108746167872215e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.1001411442786230340015781205680362993575e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.8277628835804873490331739499978938078848e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.1208326312801432038715638596517882759639e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.4813611580683862051838126076298945680803e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.1278197693321821164135890132925119054391e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.3190303792682886967459489059860595063574e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.1580767338646580750893606158043485767644e+10),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.0256008808415702780816006134784995506549e+11),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.9044186472918017896554580836514681614475e+13),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.2521078890073151875661384381880225635135e+14),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.3620352486836976842181057590770636605454e+15),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.0375525734060401555856465179734887312420e+16),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.6392664899881014534361728644608549445131e+16)
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else
{
// Bessel I0 over[100, INF]
// Max error in interpolated form : 5.459e-35
// Max Error found at float128 precision = Poly : 1.472240e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 3.9894228040143267793994605993438166526772e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.9867785050179084742493257495245185241487e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.8050629090725735167652437695397756897920e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.9219405302839307466358297347675795965363e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.4742214369972689474366968442268908028204e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.0602984099194778006610058410222616383078e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.2839502241666629677015839125593079416327e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.8926354981801627920292655818232972385750e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.4231921590621824187100989532173995000655e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.7264260959693775207585700654645245723497e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.3890136225398811195878046856373030127018e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.1999720924619285464910452647408431234369e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.2076909538525038580501368530598517194748e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.5684635141332367730007149159063086133399e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.5178192543258299267923025833141286569141e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.2966297919851965784482163987240461837728e+05) };
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i0_imp(const T& x, const mpl::int_<0>&)
{
if(boost::math::tools::digits<T>() <= 24)
return bessel_i0_imp(x, mpl::int_<24>());
else if(boost::math::tools::digits<T>() <= 53)
return bessel_i0_imp(x, mpl::int_<53>());
else if(boost::math::tools::digits<T>() <= 64)
return bessel_i0_imp(x, mpl::int_<64>());
else if(boost::math::tools::digits<T>() <= 113)
return bessel_i0_imp(x, mpl::int_<113>());
BOOST_ASSERT(0);
return 0;
}
template <typename T>
inline T bessel_i0(const T& x)
{
typedef mpl::int_<
((std::numeric_limits<T>::digits == 0) || (std::numeric_limits<T>::radix != 2)) ?
0 :
std::numeric_limits<T>::digits <= 24 ?
24 :
std::numeric_limits<T>::digits <= 53 ?
53 :
std::numeric_limits<T>::digits <= 64 ?
64 :
std::numeric_limits<T>::digits <= 113 ?
113 : -1
> tag_type;
bessel_i0_initializer<T, tag_type>::force_instantiate();
return bessel_i0_imp(x, tag_type());
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_I0_HPP

View File

@@ -0,0 +1,582 @@
// Copyright (c) 2017 John Maddock
// Use, modification and distribution are subject to 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)
// Modified Bessel function of the first kind of order zero
// we use the approximating forms derived in:
// "Rational Approximations for the Modified Bessel Function of the First Kind - I1(x) for Computations with Double Precision"
// by Pavel Holoborodko,
// see http://www.advanpix.com/2015/11/12/rational-approximations-for-the-modified-bessel-function-of-the-first-kind-i1-for-computations-with-double-precision/
// The actual coefficients used are our own, and extend Pavel's work to precision's other than double.
#ifndef BOOST_MATH_BESSEL_I1_HPP
#define BOOST_MATH_BESSEL_I1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/assert.hpp>
// Modified Bessel function of the first kind of order one
// minimax rational approximations on intervals, see
// Blair and Edwards, Chalk River Report AECL-4928, 1974
namespace boost { namespace math { namespace detail{
template <typename T>
T bessel_i1(const T& x);
template <class T, class tag>
struct bessel_i1_initializer
{
struct init
{
init()
{
do_init(tag());
}
static void do_init(const mpl::int_<64>&)
{
bessel_i1(T(1));
bessel_i1(T(15));
bessel_i1(T(80));
bessel_i1(T(101));
}
static void do_init(const mpl::int_<113>&)
{
bessel_i1(T(1));
bessel_i1(T(10));
bessel_i1(T(14));
bessel_i1(T(19));
bessel_i1(T(34));
bessel_i1(T(99));
bessel_i1(T(101));
}
template <class U>
static void do_init(const U&) {}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class tag>
const typename bessel_i1_initializer<T, tag>::init bessel_i1_initializer<T, tag>::initializer;
template <typename T, int N>
T bessel_i1_imp(const T&, const mpl::int_<N>&)
{
BOOST_ASSERT(0);
return 0;
}
template <typename T>
T bessel_i1_imp(const T& x, const mpl::int_<24>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
//Max error in interpolated form : 1.348e-08
// Max Error found at float precision = Poly : 1.469121e-07
static const float P[] = {
8.333333221e-02f,
6.944453712e-03f,
3.472097211e-04f,
1.158047174e-05f,
2.739745142e-07f,
5.135884609e-09f,
5.262251502e-11f,
1.331933703e-12f
};
T a = x * x / 4;
T Q[3] = { 1, 0.5f, boost::math::tools::evaluate_polynomial(P, a) };
return x * boost::math::tools::evaluate_polynomial(Q, a) / 2;
}
else
{
// Max error in interpolated form: 9.000e-08
// Max Error found at float precision = Poly: 1.044345e-07
static const float P[] = {
3.98942115977513013e-01f,
-1.49581264836620262e-01f,
-4.76475741878486795e-02f,
-2.65157315524784407e-02f,
-1.47148600683672014e-01f
};
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i1_imp(const T& x, const mpl::int_<53>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
// Bessel I0 over[10 ^ -16, 7.75]
// Max error in interpolated form: 5.639e-17
// Max Error found at double precision = Poly: 1.795559e-16
static const double P[] = {
8.333333333333333803e-02,
6.944444444444341983e-03,
3.472222222225921045e-04,
1.157407407354987232e-05,
2.755731926254790268e-07,
4.920949692800671435e-09,
6.834657311305621830e-11,
7.593969849687574339e-13,
6.904822652741917551e-15,
5.220157095351373194e-17,
3.410720494727771276e-19,
1.625212890947171108e-21,
1.332898928162290861e-23
};
T a = x * x / 4;
T Q[3] = { 1, 0.5f, boost::math::tools::evaluate_polynomial(P, a) };
return x * boost::math::tools::evaluate_polynomial(Q, a) / 2;
}
else if(x < 500)
{
// Max error in interpolated form: 1.796e-16
// Max Error found at double precision = Poly: 2.898731e-16
static const double P[] = {
3.989422804014406054e-01,
-1.496033551613111533e-01,
-4.675104253598537322e-02,
-4.090895951581637791e-02,
-5.719036414430205390e-02,
-1.528189554374492735e-01,
3.458284470977172076e+00,
-2.426181371595021021e+02,
1.178785865993440669e+04,
-4.404655582443487334e+05,
1.277677779341446497e+07,
-2.903390398236656519e+08,
5.192386898222206474e+09,
-7.313784438967834057e+10,
8.087824484994859552e+11,
-6.967602516005787001e+12,
4.614040809616582764e+13,
-2.298849639457172489e+14,
8.325554073334618015e+14,
-2.067285045778906105e+15,
3.146401654361325073e+15,
-2.213318202179221945e+15
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else
{
// Max error in interpolated form: 1.320e-19
// Max Error found at double precision = Poly: 7.065357e-17
static const double P[] = {
3.989422804014314820e-01,
-1.496033551467584157e-01,
-4.675105322571775911e-02,
-4.090421597376992892e-02,
-5.843630344778927582e-02
};
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i1_imp(const T& x, const mpl::int_<64>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
// Bessel I0 over[10 ^ -16, 7.75]
// Max error in interpolated form: 8.086e-21
// Max Error found at float80 precision = Poly: 7.225090e-20
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 8.33333333333333333340071817e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.94444444444444442462728070e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.47222222222222318886683883e-04),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.15740740740738880709555060e-05),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.75573192240046222242685145e-07),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.92094986131253986838697503e-09),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.83465258979924922633502182e-11),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.59405830675154933645967137e-13),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.90369179710633344508897178e-15),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.23003610041709452814262671e-17),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.35291901027762552549170038e-19),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.83991379419781823063672109e-21),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.87732714140192556332037815e-24),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.32120654663773147206454247e-26),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.95294659305369207813486871e-28)
};
T a = x * x / 4;
T Q[3] = { 1, 0.5f, boost::math::tools::evaluate_polynomial(P, a) };
return x * boost::math::tools::evaluate_polynomial(Q, a) / 2;
}
else if(x < 20)
{
// Max error in interpolated form: 4.258e-20
// Max Error found at float80 precision = Poly: 2.851105e-19
// Maximum Deviation Found : 3.887e-20
// Expected Error Term : 3.887e-20
// Maximum Relative Change in Control Points : 1.681e-04
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98942260530218897338680e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.49599542849073670179540e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.70492865454119188276875e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -3.12389893307392002405869e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.49696126385202602071197e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -3.84206507612717711565967e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.14748094784412558689584e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, -7.70652726663596993005669e+04),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.01659736164815617174439e+06),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.04740659606466305607544e+07),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.38383394696382837263656e+08),
BOOST_MATH_BIG_CONSTANT(T, 64, -8.00779638649147623107378e+09),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.02338237858684714480491e+10),
BOOST_MATH_BIG_CONSTANT(T, 64, -6.41198553664947312995879e+11),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.05915186909564986897554e+12),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.00907636964168581116181e+13),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.60855263982359981275199e+13),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.12901817219239205393806e+14),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.14861794397709807823575e+14),
BOOST_MATH_BIG_CONSTANT(T, 64, -5.02808138522587680348583e+14),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.85505477056514919387171e+14)
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else if(x < 100)
{
// Bessel I0 over [15, 50]
// Maximum Deviation Found: 2.444e-20
// Expected Error Term : 2.438e-20
// Maximum Relative Change in Control Points : 2.101e-03
// Max Error found at float80 precision = Poly : 6.029974e-20
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98942280401431675205845e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.49603355149968887210170e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.67510486284376330257260e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.09071458907089270559464e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -5.75278280327696940044714e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.10591299500956620739254e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.77061766699949309115618e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -5.42683771801837596371638e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -9.17021412070404158464316e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.04154379346763380543310e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.43462345357478348323006e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.98109660274422449523837e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, -3.74438822767781410362757e+04)
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else
{
// Bessel I0 over[100, INF]
// Max error in interpolated form: 2.456e-20
// Max Error found at float80 precision = Poly: 5.446356e-20
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98942280401432677958445e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.49603355150537411254359e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.67510484842456251368526e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.09071676503922479645155e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -5.75256179814881566010606e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.10754910257965227825040e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.67858639515616079840294e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -9.17266479586791298924367e-01)
};
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i1_imp(const T& x, const mpl::int_<113>&)
{
BOOST_MATH_STD_USING
if(x < 7.75)
{
// Bessel I0 over[10 ^ -34, 7.75]
// Max error in interpolated form: 1.835e-35
// Max Error found at float128 precision = Poly: 1.645036e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 8.3333333333333333333333333333333331804098e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.9444444444444444444444444444445418303082e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.4722222222222222222222222222119082346591e-04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.1574074074074074074074074078415867655987e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.7557319223985890652557318255143448192453e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.9209498614260519022423916850415000626427e-09),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.8346525853139609753354247043900442393686e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.5940584281266233060080535940234144302217e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.9036894801151120925605467963949641957095e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.2300677879659941472662086395055636394839e-17),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.3526075563884539394691458717439115962233e-19),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.8420920639497841692288943167036233338434e-21),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.7718669711748690065381181691546032291365e-24),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.6549445715236427401845636880769861424730e-26),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.3437296196812697924703896979250126739676e-28),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.3912734588619073883015937023564978854893e-31),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.2839967682792395867255384448052781306897e-33),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.3790094235693528861015312806394354114982e-36),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.0423861671932104308662362292359563970482e-39),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.7493858979396446292135661268130281652945e-41),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.2786079392547776769387921361408303035537e-44),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.2335693685833531118863552173880047183822e-47)
};
T a = x * x / 4;
T Q[3] = { 1, 0.5f, boost::math::tools::evaluate_polynomial(P, a) };
return x * boost::math::tools::evaluate_polynomial(Q, a) / 2;
}
else if(x < 11)
{
// Max error in interpolated form: 8.574e-36
// Maximum Deviation Found : 4.689e-36
// Expected Error Term : 3.760e-36
// Maximum Relative Change in Control Points : 5.204e-03
// Max Error found at float128 precision = Poly : 2.882561e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 8.333333333333333326889717360850080939e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.944444444444444511272790848815114507e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.472222222222221892451965054394153443e-04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.157407407407408437378868534321538798e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.755731922398566216824909767320161880e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.920949861426434829568192525456800388e-09),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.834652585308926245465686943255486934e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.594058428179852047689599244015979196e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.903689479655006062822949671528763738e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.230067791254403974475987777406992984e-17),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.352607536815161679702105115200693346e-19),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.842092161364672561828681848278567885e-21),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.771862912600611801856514076709932773e-24),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.654958704184380914803366733193713605e-26),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.343688672071130980471207297730607625e-28),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.392252844664709532905868749753463950e-31),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.282086786672692641959912811902298600e-33),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.408812012322547015191398229942864809e-36),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.681220437734066258673404589233009892e-39),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.072417451640733785626701738789290055e-41),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.352218520142636864158849446833681038e-44),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.407918492276267527897751358794783640e-46)
};
T a = x * x / 4;
T Q[3] = { 1, 0.5f, boost::math::tools::evaluate_polynomial(P, a) };
return x * boost::math::tools::evaluate_polynomial(Q, a) / 2;
}
else if(x < 15)
{
//Max error in interpolated form: 7.599e-36
// Maximum Deviation Found : 1.766e-35
// Expected Error Term : 1.021e-35
// Maximum Relative Change in Control Points : 6.228e-03
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 8.333333333333255774414858563409941233e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.944444444444897867884955912228700291e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.472222222220954970397343617150959467e-04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.157407407409660682751155024932538578e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.755731922369973706427272809014190998e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.920949861702265600960449699129258153e-09),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.834652583208361401197752793379677147e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.594058441128280500819776168239988143e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.903689413939268702265479276217647209e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.230068069012898202890718644753625569e-17),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.352606552027491657204243201021677257e-19),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.842095100698532984651921750204843362e-21),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.771789051329870174925649852681844169e-24),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.655114381199979536997025497438385062e-26),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.343415732516712339472538688374589373e-28),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.396177019032432392793591204647901390e-31),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.277563309255167951005939802771456315e-33),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.449201419305514579791370198046544736e-36),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.415430703400740634202379012388035255e-39),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.195458831864936225409005027914934499e-41),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.829726762743879793396637797534668039e-45),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.698302711685624490806751012380215488e-46),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.062520475425422618494185821587228317e-49),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.732372906742845717148185173723304360e-52)
};
T a = x * x / 4;
T Q[3] = { 1, 0.5f, boost::math::tools::evaluate_polynomial(P, a) };
return x * boost::math::tools::evaluate_polynomial(Q, a) / 2;
}
else if(x < 20)
{
// Max error in interpolated form: 8.864e-36
// Max Error found at float128 precision = Poly: 8.522841e-35
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 3.989422793693152031514179994954750043e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.496029423752889591425633234009799670e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.682975926820553021482820043377990241e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.138871171577224532369979905856458929e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -8.765350219426341341990447005798111212e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.321389275507714530941178258122955540e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.727748393898888756515271847678850411e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.123040820686242586086564998713862335e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.784112378374753535335272752884808068e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.054920416060932189433079126269416563e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.450129415468060676827180524327749553e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.758831882046487398739784498047935515e+10),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.736936520262204842199620784338052937e+11),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.051128683324042629513978256179115439e+13),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.188008285959794869092624343537262342e+14),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.108530004906954627420484180793165669e+15),
BOOST_MATH_BIG_CONSTANT(T, 113, -8.441516828490144766650287123765318484e+15),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.158251664797753450664499268756393535e+16),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.467314522709016832128790443932896401e+17),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.896222045367960462945885220710294075e+17),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.273382139594876997203657902425653079e+18),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.669871448568623680543943144842394531e+18),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.813923031370708069940575240509912588e+18)
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else if(x < 35)
{
// Max error in interpolated form: 6.028e-35
// Max Error found at float128 precision = Poly: 1.368313e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 3.989422804012941975429616956496046931e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.496033550576049830976679315420681402e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.675107835141866009896710750800622147e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.090104965125365961928716504473692957e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.842241652296980863361375208605487570e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.063604828033747303936724279018650633e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -9.113375972811586130949401996332817152e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.334748570425075872639817839399823709e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.759150758768733692594821032784124765e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.863672813448915255286274382558526321e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.798248643371718775489178767529282534e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.769963173932801026451013022000669267e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, -8.381780137198278741566746511015220011e+10),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.163891337116820832871382141011952931e+12),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.764325864671438675151635117936912390e+13),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.925668307403332887856809510525154955e+14),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.416692606589060039334938090985713641e+16),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.892398600219306424294729851605944429e+17),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.107232903741874160308537145391245060e+18),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.930223393531877588898224144054112045e+19),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.427759576167665663373350433236061007e+20),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.306019279465532835530812122374386654e+20),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.653753000392125229440044977239174472e+21),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.140760686989511568435076842569804906e+22),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.249149337812510200795436107962504749e+22),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.101619088427348382058085685849420866e+22)
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else if(x < 100)
{
// Max error in interpolated form: 5.494e-35
// Max Error found at float128 precision = Poly: 1.214651e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 3.989422804014326779399307367861631577e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.496033551505372542086590873271571919e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.675104848454290286276466276677172664e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.090716742397105403027549796269213215e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.752570419098513588311026680089351230e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.107369803696534592906420980901195808e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.699214194000085622941721628134575121e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.953006169077813678478720427604462133e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.746618809476524091493444128605380593e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.084446249943196826652788161656973391e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.020325182518980633783194648285500554e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.510195971266257573425196228564489134e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.241661863814900938075696173192225056e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.323374362891993686413568398575539777e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.112838452096066633754042734723911040e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.369270194978310081563767560113534023e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.704295412488936504389347368131134993e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.320829576277038198439987439508754886e+10),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.258818139077875493434420764260185306e+11),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.396791306321498426110315039064592443e+12),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.217617301585849875301440316301068439e+12)
};
return exp(x) * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
}
else
{
// Bessel I0 over[100, INF]
// Max error in interpolated form: 6.081e-35
// Max Error found at float128 precision = Poly: 1.407151e-34
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 3.9894228040143267793994605993438200208417e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.4960335515053725422747977247811372936584e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.6751048484542891946087411826356811991039e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.0907167423975030452875828826630006305665e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.7525704189964886494791082898669060345483e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.1073698056568248642163476807108190176386e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.6992139012879749064623499618582631684228e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.9530409594026597988098934027440110587905e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.7462844478733532517044536719240098183686e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.0870711340681926669381449306654104739256e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.8510175413216969245241059608553222505228e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.4094682286011573747064907919522894740063e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.3128845936764406865199641778959502795443e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, -8.1655901321962541203257516341266838487359e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.8019591025686295090160445920753823994556e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, -6.7008089049178178697338128837158732831105e+05)
};
T ex = exp(x / 2);
T result = ex * boost::math::tools::evaluate_polynomial(P, T(1 / x)) / sqrt(x);
result *= ex;
return result;
}
}
template <typename T>
T bessel_i1_imp(const T& x, const mpl::int_<0>&)
{
if(boost::math::tools::digits<T>() <= 24)
return bessel_i1_imp(x, mpl::int_<24>());
else if(boost::math::tools::digits<T>() <= 53)
return bessel_i1_imp(x, mpl::int_<53>());
else if(boost::math::tools::digits<T>() <= 64)
return bessel_i1_imp(x, mpl::int_<64>());
else if(boost::math::tools::digits<T>() <= 113)
return bessel_i1_imp(x, mpl::int_<113>());
BOOST_ASSERT(0);
return 0;
}
template <typename T>
inline T bessel_i1(const T& x)
{
typedef mpl::int_<
((std::numeric_limits<T>::digits == 0) || (std::numeric_limits<T>::radix != 2)) ?
0 :
std::numeric_limits<T>::digits <= 24 ?
24 :
std::numeric_limits<T>::digits <= 53 ?
53 :
std::numeric_limits<T>::digits <= 64 ?
64 :
std::numeric_limits<T>::digits <= 113 ?
113 : -1
> tag_type;
bessel_i1_initializer<T, tag_type>::force_instantiate();
return bessel_i1_imp(x, tag_type());
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_I1_HPP

View File

@@ -0,0 +1,451 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_IK_HPP
#define BOOST_MATH_BESSEL_IK_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/config.hpp>
// Modified Bessel functions of the first and second kind of fractional order
namespace boost { namespace math {
namespace detail {
template <class T, class Policy>
struct cyl_bessel_i_small_z
{
typedef T result_type;
cyl_bessel_i_small_z(T v_, T z_) : k(0), v(v_), mult(z_*z_/4)
{
BOOST_MATH_STD_USING
term = 1;
}
T operator()()
{
T result = term;
++k;
term *= mult / k;
term /= k + v;
return result;
}
private:
unsigned k;
T v;
T term;
T mult;
};
template <class T, class Policy>
inline T bessel_i_small_z_series(T v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
T prefix;
if(v < max_factorial<T>::value)
{
prefix = pow(x / 2, v) / boost::math::tgamma(v + 1, pol);
}
else
{
prefix = v * log(x / 2) - boost::math::lgamma(v + 1, pol);
prefix = exp(prefix);
}
if(prefix == 0)
return prefix;
cyl_bessel_i_small_z<T, Policy> s(v, x);
boost::uintmax_t max_iter = 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
policies::check_series_iterations<T>("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
return prefix * result;
}
// Calculate K(v, x) and K(v+1, x) by method analogous to
// Temme, Journal of Computational Physics, vol 21, 343 (1976)
template <typename T, typename Policy>
int temme_ik(T v, T x, T* K, T* K1, const Policy& pol)
{
T f, h, p, q, coef, sum, sum1, tolerance;
T a, b, c, d, sigma, gamma1, gamma2;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
// |x| <= 2, Temme series converge rapidly
// |x| > 2, the larger the |x|, the slower the convergence
BOOST_ASSERT(abs(x) <= 2);
BOOST_ASSERT(abs(v) <= 0.5f);
T gp = boost::math::tgamma1pm1(v, pol);
T gm = boost::math::tgamma1pm1(-v, pol);
a = log(x / 2);
b = exp(v * a);
sigma = -a * v;
c = abs(v) < tools::epsilon<T>() ?
T(1) : T(boost::math::sin_pi(v) / (v * pi<T>()));
d = abs(sigma) < tools::epsilon<T>() ?
T(1) : T(sinh(sigma) / sigma);
gamma1 = abs(v) < tools::epsilon<T>() ?
T(-euler<T>()) : T((0.5f / v) * (gp - gm) * c);
gamma2 = (2 + gp + gm) * c / 2;
// initial values
p = (gp + 1) / (2 * b);
q = (1 + gm) * b / 2;
f = (cosh(sigma) * gamma1 + d * (-a) * gamma2) / c;
h = p;
coef = 1;
sum = coef * f;
sum1 = coef * h;
BOOST_MATH_INSTRUMENT_VARIABLE(p);
BOOST_MATH_INSTRUMENT_VARIABLE(q);
BOOST_MATH_INSTRUMENT_VARIABLE(f);
BOOST_MATH_INSTRUMENT_VARIABLE(sigma);
BOOST_MATH_INSTRUMENT_CODE(sinh(sigma));
BOOST_MATH_INSTRUMENT_VARIABLE(gamma1);
BOOST_MATH_INSTRUMENT_VARIABLE(gamma2);
BOOST_MATH_INSTRUMENT_VARIABLE(c);
BOOST_MATH_INSTRUMENT_VARIABLE(d);
BOOST_MATH_INSTRUMENT_VARIABLE(a);
// series summation
tolerance = tools::epsilon<T>();
for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
{
f = (k * f + p + q) / (k*k - v*v);
p /= k - v;
q /= k + v;
h = p - k * f;
coef *= x * x / (4 * k);
sum += coef * f;
sum1 += coef * h;
if (abs(coef * f) < abs(sum) * tolerance)
{
break;
}
}
policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in temme_ik", k, pol);
*K = sum;
*K1 = 2 * sum1 / x;
return 0;
}
// Evaluate continued fraction fv = I_(v+1) / I_v, derived from
// Abramowitz and Stegun, Handbook of Mathematical Functions, 1972, 9.1.73
template <typename T, typename Policy>
int CF1_ik(T v, T x, T* fv, const Policy& pol)
{
T C, D, f, a, b, delta, tiny, tolerance;
unsigned long k;
BOOST_MATH_STD_USING
// |x| <= |v|, CF1_ik converges rapidly
// |x| > |v|, CF1_ik needs O(|x|) iterations to converge
// modified Lentz's method, see
// Lentz, Applied Optics, vol 15, 668 (1976)
tolerance = 2 * tools::epsilon<T>();
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
tiny = sqrt(tools::min_value<T>());
BOOST_MATH_INSTRUMENT_VARIABLE(tiny);
C = f = tiny; // b0 = 0, replace with tiny
D = 0;
for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
{
a = 1;
b = 2 * (v + k) / x;
C = b + a / C;
D = b + a * D;
if (C == 0) { C = tiny; }
if (D == 0) { D = tiny; }
D = 1 / D;
delta = C * D;
f *= delta;
BOOST_MATH_INSTRUMENT_VARIABLE(delta-1);
if (abs(delta - 1) <= tolerance)
{
break;
}
}
BOOST_MATH_INSTRUMENT_VARIABLE(k);
policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in CF1_ik", k, pol);
*fv = f;
return 0;
}
// Calculate K(v, x) and K(v+1, x) by evaluating continued fraction
// z1 / z0 = U(v+1.5, 2v+1, 2x) / U(v+0.5, 2v+1, 2x), see
// Thompson and Barnett, Computer Physics Communications, vol 47, 245 (1987)
template <typename T, typename Policy>
int CF2_ik(T v, T x, T* Kv, T* Kv1, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::constants;
T S, C, Q, D, f, a, b, q, delta, tolerance, current, prev;
unsigned long k;
// |x| >= |v|, CF2_ik converges rapidly
// |x| -> 0, CF2_ik fails to converge
BOOST_ASSERT(abs(x) > 1);
// Steed's algorithm, see Thompson and Barnett,
// Journal of Computational Physics, vol 64, 490 (1986)
tolerance = tools::epsilon<T>();
a = v * v - 0.25f;
b = 2 * (x + 1); // b1
D = 1 / b; // D1 = 1 / b1
f = delta = D; // f1 = delta1 = D1, coincidence
prev = 0; // q0
current = 1; // q1
Q = C = -a; // Q1 = C1 because q1 = 1
S = 1 + Q * delta; // S1
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
BOOST_MATH_INSTRUMENT_VARIABLE(a);
BOOST_MATH_INSTRUMENT_VARIABLE(b);
BOOST_MATH_INSTRUMENT_VARIABLE(D);
BOOST_MATH_INSTRUMENT_VARIABLE(f);
for (k = 2; k < policies::get_max_series_iterations<Policy>(); k++) // starting from 2
{
// continued fraction f = z1 / z0
a -= 2 * (k - 1);
b += 2;
D = 1 / (b + a * D);
delta *= b * D - 1;
f += delta;
// series summation S = 1 + \sum_{n=1}^{\infty} C_n * z_n / z_0
q = (prev - (b - 2) * current) / a;
prev = current;
current = q; // forward recurrence for q
C *= -a / k;
Q += C * q;
S += Q * delta;
//
// Under some circumstances q can grow very small and C very
// large, leading to under/overflow. This is particularly an
// issue for types which have many digits precision but a narrow
// exponent range. A typical example being a "double double" type.
// To avoid this situation we can normalise q (and related prev/current)
// and C. All other variables remain unchanged in value. A typical
// test case occurs when x is close to 2, for example cyl_bessel_k(9.125, 2.125).
//
if(q < tools::epsilon<T>())
{
C *= q;
prev /= q;
current /= q;
q = 1;
}
// S converges slower than f
BOOST_MATH_INSTRUMENT_VARIABLE(Q * delta);
BOOST_MATH_INSTRUMENT_VARIABLE(abs(S) * tolerance);
BOOST_MATH_INSTRUMENT_VARIABLE(S);
if (abs(Q * delta) < abs(S) * tolerance)
{
break;
}
}
policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in CF2_ik", k, pol);
if(x >= tools::log_max_value<T>())
*Kv = exp(0.5f * log(pi<T>() / (2 * x)) - x - log(S));
else
*Kv = sqrt(pi<T>() / (2 * x)) * exp(-x) / S;
*Kv1 = *Kv * (0.5f + v + x + (v * v - 0.25f) * f) / x;
BOOST_MATH_INSTRUMENT_VARIABLE(*Kv);
BOOST_MATH_INSTRUMENT_VARIABLE(*Kv1);
return 0;
}
enum{
need_i = 1,
need_k = 2
};
// Compute I(v, x) and K(v, x) simultaneously by Temme's method, see
// Temme, Journal of Computational Physics, vol 19, 324 (1975)
template <typename T, typename Policy>
int bessel_ik(T v, T x, T* I, T* K, int kind, const Policy& pol)
{
// Kv1 = K_(v+1), fv = I_(v+1) / I_v
// Ku1 = K_(u+1), fu = I_(u+1) / I_u
T u, Iv, Kv, Kv1, Ku, Ku1, fv;
T W, current, prev, next;
bool reflect = false;
unsigned n, k;
int org_kind = kind;
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
BOOST_MATH_INSTRUMENT_VARIABLE(kind);
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
static const char* function = "boost::math::bessel_ik<%1%>(%1%,%1%)";
if (v < 0)
{
reflect = true;
v = -v; // v is non-negative from here
kind |= need_k;
}
n = iround(v, pol);
u = v - n; // -1/2 <= u < 1/2
BOOST_MATH_INSTRUMENT_VARIABLE(n);
BOOST_MATH_INSTRUMENT_VARIABLE(u);
if (x < 0)
{
*I = *K = policies::raise_domain_error<T>(function,
"Got x = %1% but real argument x must be non-negative, complex number result not supported.", x, pol);
return 1;
}
if (x == 0)
{
Iv = (v == 0) ? static_cast<T>(1) : static_cast<T>(0);
if(kind & need_k)
{
Kv = policies::raise_overflow_error<T>(function, 0, pol);
}
else
{
Kv = std::numeric_limits<T>::quiet_NaN(); // any value will do
}
if(reflect && (kind & need_i))
{
T z = (u + n % 2);
Iv = boost::math::sin_pi(z, pol) == 0 ?
Iv :
policies::raise_overflow_error<T>(function, 0, pol); // reflection formula
}
*I = Iv;
*K = Kv;
return 0;
}
// x is positive until reflection
W = 1 / x; // Wronskian
if (x <= 2) // x in (0, 2]
{
temme_ik(u, x, &Ku, &Ku1, pol); // Temme series
}
else // x in (2, \infty)
{
CF2_ik(u, x, &Ku, &Ku1, pol); // continued fraction CF2_ik
}
BOOST_MATH_INSTRUMENT_VARIABLE(Ku);
BOOST_MATH_INSTRUMENT_VARIABLE(Ku1);
prev = Ku;
current = Ku1;
T scale = 1;
T scale_sign = 1;
for (k = 1; k <= n; k++) // forward recurrence for K
{
T fact = 2 * (u + k) / x;
if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
{
prev /= current;
scale /= current;
scale_sign *= boost::math::sign(current);
current = 1;
}
next = fact * current + prev;
prev = current;
current = next;
}
Kv = prev;
Kv1 = current;
BOOST_MATH_INSTRUMENT_VARIABLE(Kv);
BOOST_MATH_INSTRUMENT_VARIABLE(Kv1);
if(kind & need_i)
{
T lim = (4 * v * v + 10) / (8 * x);
lim *= lim;
lim *= lim;
lim /= 24;
if((lim < tools::epsilon<T>() * 10) && (x > 100))
{
// x is huge compared to v, CF1 may be very slow
// to converge so use asymptotic expansion for large
// x case instead. Note that the asymptotic expansion
// isn't very accurate - so it's deliberately very hard
// to get here - probably we're going to overflow:
Iv = asymptotic_bessel_i_large_x(v, x, pol);
}
else if((v > 0) && (x / v < 0.25))
{
Iv = bessel_i_small_z_series(v, x, pol);
}
else
{
CF1_ik(v, x, &fv, pol); // continued fraction CF1_ik
Iv = scale * W / (Kv * fv + Kv1); // Wronskian relation
}
}
else
Iv = std::numeric_limits<T>::quiet_NaN(); // any value will do
if (reflect)
{
T z = (u + n % 2);
T fact = (2 / pi<T>()) * (boost::math::sin_pi(z) * Kv);
if(fact == 0)
*I = Iv;
else if(tools::max_value<T>() * scale < fact)
*I = (org_kind & need_i) ? T(sign(fact) * scale_sign * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
else
*I = Iv + fact / scale; // reflection formula
}
else
{
*I = Iv;
}
if(tools::max_value<T>() * scale < Kv)
*K = (org_kind & need_k) ? T(sign(Kv) * scale_sign * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
else
*K = Kv / scale;
BOOST_MATH_INSTRUMENT_VARIABLE(*I);
BOOST_MATH_INSTRUMENT_VARIABLE(*K);
return 0;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_IK_HPP

View File

@@ -0,0 +1,193 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_J0_HPP
#define BOOST_MATH_BESSEL_J0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/assert.hpp>
// Bessel function of the first kind of order zero
// x <= 8, minimax rational approximations on root-bracketing intervals
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
namespace boost { namespace math { namespace detail{
template <typename T>
T bessel_j0(T x);
template <class T>
struct bessel_j0_initializer
{
struct init
{
init()
{
do_init();
}
static void do_init()
{
bessel_j0(T(1));
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T>
const typename bessel_j0_initializer<T>::init bessel_j0_initializer<T>::initializer;
template <typename T>
T bessel_j0(T x)
{
bessel_j0_initializer<T>::force_instantiate();
static const T P1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.1298668500990866786e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.7282507878605942706e+10)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.2140700423540120665e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.6302997904833794242e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.6629814655107086448e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0344222815443188943e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.2117036164593528341e-01))
};
static const T Q1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.3883787996332290397e+12)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.6328198300859648632e+10)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3985097372263433271e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.5612696224219938200e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.3614022392337710626e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.0))
};
static const T P2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.8319397969392084011e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.2254078161378989535e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -7.2879702464464618998e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0341910641583726701e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1725046279757103576e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.4176707025325087628e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.4321196680624245801e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.8591703355916499363e+01))
};
static const T Q2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.5783478026152301072e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.4599102262586308984e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.4055062591169562211e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8680990008359188352e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.9458766545509337327e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.3307310774649071172e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.5258076240801555057e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
};
static const T PC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.2779090197304684302e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.1345386639580765797e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1170523380864944322e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.4806486443249270347e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.5376201909008354296e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.8961548424210455236e-01))
};
static const T QC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.2779090197304684318e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.1370412495510416640e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1215350561880115730e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.5028735138235608207e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.5711159858080893649e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
};
static const T PS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.9226600200800094098e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.8591953644342993800e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.1183429920482737611e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2300261666214198472e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.2441026745835638459e+00)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.8033303048680751817e-03))
};
static const T QS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.7105024128512061905e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1951131543434613647e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.2642780169211018836e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.4887231232283756582e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.0593769594993125859e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
};
static const T x1 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.4048255576957727686e+00)),
x2 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.5200781102863106496e+00)),
x11 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.160e+02)),
x12 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.42444230422723137837e-03)),
x21 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.4130e+03)),
x22 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.46860286310649596604e-04));
T value, factor, r, rc, rs;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
if (x < 0)
{
x = -x; // even function
}
if (x == 0)
{
return static_cast<T>(1);
}
if (x <= 4) // x in (0, 4]
{
T y = x * x;
BOOST_ASSERT(sizeof(P1) == sizeof(Q1));
r = evaluate_rational(P1, Q1, y);
factor = (x + x1) * ((x - x11/256) - x12);
value = factor * r;
}
else if (x <= 8.0) // x in (4, 8]
{
T y = 1 - (x * x)/64;
BOOST_ASSERT(sizeof(P2) == sizeof(Q2));
r = evaluate_rational(P2, Q2, y);
factor = (x + x2) * ((x - x21/256) - x22);
value = factor * r;
}
else // x in (8, \infty)
{
T y = 8 / x;
T y2 = y * y;
BOOST_ASSERT(sizeof(PC) == sizeof(QC));
BOOST_ASSERT(sizeof(PS) == sizeof(QS));
rc = evaluate_rational(PC, QC, y2);
rs = evaluate_rational(PS, QS, y2);
factor = constants::one_div_root_pi<T>() / sqrt(x);
//
// What follows is really just:
//
// T z = x - pi/4;
// value = factor * (rc * cos(z) - y * rs * sin(z));
//
// But using the addition formulae for sin and cos, plus
// the special values for sin/cos of pi/4.
//
T sx = sin(x);
T cx = cos(x);
value = factor * (rc * (cx + sx) - y * rs * (sx - cx));
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_J0_HPP

View File

@@ -0,0 +1,199 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_J1_HPP
#define BOOST_MATH_BESSEL_J1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/assert.hpp>
// Bessel function of the first kind of order one
// x <= 8, minimax rational approximations on root-bracketing intervals
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
namespace boost { namespace math{ namespace detail{
template <typename T>
T bessel_j1(T x);
template <class T>
struct bessel_j1_initializer
{
struct init
{
init()
{
do_init();
}
static void do_init()
{
bessel_j1(T(1));
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T>
const typename bessel_j1_initializer<T>::init bessel_j1_initializer<T>::initializer;
template <typename T>
T bessel_j1(T x)
{
bessel_j1_initializer<T>::force_instantiate();
static const T P1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4258509801366645672e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.6781041261492395835e+09)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.1548696764841276794e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.8062904098958257677e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.4615792982775076130e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0650724020080236441e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0767857011487300348e-02))
};
static const T Q1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.1868604460820175290e+12)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.2091902282580133541e+10)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.0228375140097033958e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.9117614494174794095e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0742272239517380498e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.0))
};
static const T P2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.7527881995806511112e+16)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.6608531731299018674e+15)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.6658018905416665164e+13)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.5580665670910619166e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.8113931269860667829e+09)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.0793266148011179143e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -7.5023342220781607561e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.6179191852758252278e+00))
};
static const T Q2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7253905888447681194e+18)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7128800897135812012e+16)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.4899346165481429307e+13)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.7622777286244082666e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.4872502899596389593e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1267125065029138050e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3886978985861357615e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
};
static const T PC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.4357578167941278571e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -9.9422465050776411957e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.6033732483649391093e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.5235293511811373833e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0982405543459346727e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.6116166443246101165e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.0))
};
static const T QC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.4357578167941278568e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -9.9341243899345856590e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.5853394797230870728e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.5118095066341608816e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0726385991103820119e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4550094401904961825e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
};
static const T PS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.3220913409857223519e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.5145160675335701966e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.6178836581270835179e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8494262873223866797e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7063754290207680021e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.5265133846636032186e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.0))
};
static const T QS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.0871281941028743574e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8194580422439972989e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.4194606696037208929e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.0029443582266975117e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.7890229745772202641e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.6383677696049909675e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
};
static const T x1 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.8317059702075123156e+00)),
x2 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.0155866698156187535e+00)),
x11 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.810e+02)),
x12 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.2527979248768438556e-04)),
x21 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7960e+03)),
x22 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.8330184381246462950e-05));
T value, factor, r, rc, rs, w;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
w = abs(x);
if (x == 0)
{
return static_cast<T>(0);
}
if (w <= 4) // w in (0, 4]
{
T y = x * x;
BOOST_ASSERT(sizeof(P1) == sizeof(Q1));
r = evaluate_rational(P1, Q1, y);
factor = w * (w + x1) * ((w - x11/256) - x12);
value = factor * r;
}
else if (w <= 8) // w in (4, 8]
{
T y = x * x;
BOOST_ASSERT(sizeof(P2) == sizeof(Q2));
r = evaluate_rational(P2, Q2, y);
factor = w * (w + x2) * ((w - x21/256) - x22);
value = factor * r;
}
else // w in (8, \infty)
{
T y = 8 / w;
T y2 = y * y;
BOOST_ASSERT(sizeof(PC) == sizeof(QC));
BOOST_ASSERT(sizeof(PS) == sizeof(QS));
rc = evaluate_rational(PC, QC, y2);
rs = evaluate_rational(PS, QS, y2);
factor = 1 / (sqrt(w) * constants::root_pi<T>());
//
// What follows is really just:
//
// T z = w - 0.75f * pi<T>();
// value = factor * (rc * cos(z) - y * rs * sin(z));
//
// but using the sin/cos addition rules plus constants
// for the values of sin/cos of 3PI/4 which then cancel
// out with corresponding terms in "factor".
//
T sx = sin(x);
T cx = cos(x);
value = factor * (rc * (sx - cx) + y * rs * (sx + cx));
}
if (x < 0)
{
value *= -1; // odd function
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_J1_HPP

View File

@@ -0,0 +1,133 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_JN_HPP
#define BOOST_MATH_BESSEL_JN_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_j0.hpp>
#include <boost/math/special_functions/detail/bessel_j1.hpp>
#include <boost/math/special_functions/detail/bessel_jy.hpp>
#include <boost/math/special_functions/detail/bessel_jy_asym.hpp>
#include <boost/math/special_functions/detail/bessel_jy_series.hpp>
// Bessel function of the first kind of integer order
// J_n(z) is the minimal solution
// n < abs(z), forward recurrence stable and usable
// n >= abs(z), forward recurrence unstable, use Miller's algorithm
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T bessel_jn(int n, T x, const Policy& pol)
{
T value(0), factor, current, prev, next;
BOOST_MATH_STD_USING
//
// Reflection has to come first:
//
if (n < 0)
{
factor = static_cast<T>((n & 0x1) ? -1 : 1); // J_{-n}(z) = (-1)^n J_n(z)
n = -n;
}
else
{
factor = 1;
}
if(x < 0)
{
factor *= (n & 0x1) ? -1 : 1; // J_{n}(-z) = (-1)^n J_n(z)
x = -x;
}
//
// Special cases:
//
if(asymptotic_bessel_large_x_limit(T(n), x))
return factor * asymptotic_bessel_j_large_x_2<T>(T(n), x);
if (n == 0)
{
return factor * bessel_j0(x);
}
if (n == 1)
{
return factor * bessel_j1(x);
}
if (x == 0) // n >= 2
{
return static_cast<T>(0);
}
BOOST_ASSERT(n > 1);
T scale = 1;
if (n < abs(x)) // forward recurrence
{
prev = bessel_j0(x);
current = bessel_j1(x);
policies::check_series_iterations<T>("boost::math::bessel_j_n<%1%>(%1%,%1%)", n, pol);
for (int k = 1; k < n; k++)
{
T fact = 2 * k / x;
//
// rescale if we would overflow or underflow:
//
if((fabs(fact) > 1) && ((tools::max_value<T>() - fabs(prev)) / fabs(fact) < fabs(current)))
{
scale /= current;
prev /= current;
current = 1;
}
value = fact * current - prev;
prev = current;
current = value;
}
}
else if((x < 1) || (n > x * x / 4) || (x < 5))
{
return factor * bessel_j_small_z_series(T(n), x, pol);
}
else // backward recurrence
{
T fn; int s; // fn = J_(n+1) / J_n
// |x| <= n, fast convergence for continued fraction CF1
boost::math::detail::CF1_jy(static_cast<T>(n), x, &fn, &s, pol);
prev = fn;
current = 1;
// Check recursion won't go on too far:
policies::check_series_iterations<T>("boost::math::bessel_j_n<%1%>(%1%,%1%)", n, pol);
for (int k = n; k > 0; k--)
{
T fact = 2 * k / x;
if((fabs(fact) > 1) && ((tools::max_value<T>() - fabs(prev)) / fabs(fact) < fabs(current)))
{
prev /= current;
scale /= current;
current = 1;
}
next = fact * current - prev;
prev = current;
current = next;
}
value = bessel_j0(x) / current; // normalization
scale = 1 / scale;
}
value *= factor;
if(tools::max_value<T>() * scale < fabs(value))
return policies::raise_overflow_error<T>("boost::math::bessel_jn<%1%>(%1%,%1%)", 0, pol);
return value / scale;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_JN_HPP

View File

@@ -0,0 +1,589 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_JY_HPP
#define BOOST_MATH_BESSEL_JY_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <boost/math/special_functions/hypot.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
#include <boost/math/special_functions/detail/bessel_jy_asym.hpp>
#include <boost/math/special_functions/detail/bessel_jy_series.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <complex>
// Bessel functions of the first and second kind of fractional order
namespace boost { namespace math {
namespace detail {
//
// Simultaneous calculation of A&S 9.2.9 and 9.2.10
// for use in A&S 9.2.5 and 9.2.6.
// This series is quick to evaluate, but divergent unless
// x is very large, in fact it's pretty hard to figure out
// with any degree of precision when this series actually
// *will* converge!! Consequently, we may just have to
// try it and see...
//
template <class T, class Policy>
bool hankel_PQ(T v, T x, T* p, T* q, const Policy& )
{
BOOST_MATH_STD_USING
T tolerance = 2 * policies::get_epsilon<T, Policy>();
*p = 1;
*q = 0;
T k = 1;
T z8 = 8 * x;
T sq = 1;
T mu = 4 * v * v;
T term = 1;
bool ok = true;
do
{
term *= (mu - sq * sq) / (k * z8);
*q += term;
k += 1;
sq += 2;
T mult = (sq * sq - mu) / (k * z8);
ok = fabs(mult) < 0.5f;
term *= mult;
*p += term;
k += 1;
sq += 2;
}
while((fabs(term) > tolerance * *p) && ok);
return ok;
}
// Calculate Y(v, x) and Y(v+1, x) by Temme's method, see
// Temme, Journal of Computational Physics, vol 21, 343 (1976)
template <typename T, typename Policy>
int temme_jy(T v, T x, T* Y, T* Y1, const Policy& pol)
{
T g, h, p, q, f, coef, sum, sum1, tolerance;
T a, d, e, sigma;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
BOOST_ASSERT(fabs(v) <= 0.5f); // precondition for using this routine
T gp = boost::math::tgamma1pm1(v, pol);
T gm = boost::math::tgamma1pm1(-v, pol);
T spv = boost::math::sin_pi(v, pol);
T spv2 = boost::math::sin_pi(v/2, pol);
T xp = pow(x/2, v);
a = log(x / 2);
sigma = -a * v;
d = abs(sigma) < tools::epsilon<T>() ?
T(1) : sinh(sigma) / sigma;
e = abs(v) < tools::epsilon<T>() ? T(v*pi<T>()*pi<T>() / 2)
: T(2 * spv2 * spv2 / v);
T g1 = (v == 0) ? T(-euler<T>()) : T((gp - gm) / ((1 + gp) * (1 + gm) * 2 * v));
T g2 = (2 + gp + gm) / ((1 + gp) * (1 + gm) * 2);
T vspv = (fabs(v) < tools::epsilon<T>()) ? T(1/constants::pi<T>()) : T(v / spv);
f = (g1 * cosh(sigma) - g2 * a * d) * 2 * vspv;
p = vspv / (xp * (1 + gm));
q = vspv * xp / (1 + gp);
g = f + e * q;
h = p;
coef = 1;
sum = coef * g;
sum1 = coef * h;
T v2 = v * v;
T coef_mult = -x * x / 4;
// series summation
tolerance = policies::get_epsilon<T, Policy>();
for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
{
f = (k * f + p + q) / (k*k - v2);
p /= k - v;
q /= k + v;
g = f + e * q;
h = p - k * g;
coef *= coef_mult / k;
sum += coef * g;
sum1 += coef * h;
if (abs(coef * g) < abs(sum) * tolerance)
{
break;
}
}
policies::check_series_iterations<T>("boost::math::bessel_jy<%1%>(%1%,%1%) in temme_jy", k, pol);
*Y = -sum;
*Y1 = -2 * sum1 / x;
return 0;
}
// Evaluate continued fraction fv = J_(v+1) / J_v, see
// Abramowitz and Stegun, Handbook of Mathematical Functions, 1972, 9.1.73
template <typename T, typename Policy>
int CF1_jy(T v, T x, T* fv, int* sign, const Policy& pol)
{
T C, D, f, a, b, delta, tiny, tolerance;
unsigned long k;
int s = 1;
BOOST_MATH_STD_USING
// |x| <= |v|, CF1_jy converges rapidly
// |x| > |v|, CF1_jy needs O(|x|) iterations to converge
// modified Lentz's method, see
// Lentz, Applied Optics, vol 15, 668 (1976)
tolerance = 2 * policies::get_epsilon<T, Policy>();;
tiny = sqrt(tools::min_value<T>());
C = f = tiny; // b0 = 0, replace with tiny
D = 0;
for (k = 1; k < policies::get_max_series_iterations<Policy>() * 100; k++)
{
a = -1;
b = 2 * (v + k) / x;
C = b + a / C;
D = b + a * D;
if (C == 0) { C = tiny; }
if (D == 0) { D = tiny; }
D = 1 / D;
delta = C * D;
f *= delta;
if (D < 0) { s = -s; }
if (abs(delta - 1) < tolerance)
{ break; }
}
policies::check_series_iterations<T>("boost::math::bessel_jy<%1%>(%1%,%1%) in CF1_jy", k / 100, pol);
*fv = -f;
*sign = s; // sign of denominator
return 0;
}
//
// This algorithm was originally written by Xiaogang Zhang
// using std::complex to perform the complex arithmetic.
// However, that turns out to 10x or more slower than using
// all real-valued arithmetic, so it's been rewritten using
// real values only.
//
template <typename T, typename Policy>
int CF2_jy(T v, T x, T* p, T* q, const Policy& pol)
{
BOOST_MATH_STD_USING
T Cr, Ci, Dr, Di, fr, fi, a, br, bi, delta_r, delta_i, temp;
T tiny;
unsigned long k;
// |x| >= |v|, CF2_jy converges rapidly
// |x| -> 0, CF2_jy fails to converge
BOOST_ASSERT(fabs(x) > 1);
// modified Lentz's method, complex numbers involved, see
// Lentz, Applied Optics, vol 15, 668 (1976)
T tolerance = 2 * policies::get_epsilon<T, Policy>();
tiny = sqrt(tools::min_value<T>());
Cr = fr = -0.5f / x;
Ci = fi = 1;
//Dr = Di = 0;
T v2 = v * v;
a = (0.25f - v2) / x; // Note complex this one time only!
br = 2 * x;
bi = 2;
temp = Cr * Cr + 1;
Ci = bi + a * Cr / temp;
Cr = br + a / temp;
Dr = br;
Di = bi;
if (fabs(Cr) + fabs(Ci) < tiny) { Cr = tiny; }
if (fabs(Dr) + fabs(Di) < tiny) { Dr = tiny; }
temp = Dr * Dr + Di * Di;
Dr = Dr / temp;
Di = -Di / temp;
delta_r = Cr * Dr - Ci * Di;
delta_i = Ci * Dr + Cr * Di;
temp = fr;
fr = temp * delta_r - fi * delta_i;
fi = temp * delta_i + fi * delta_r;
for (k = 2; k < policies::get_max_series_iterations<Policy>(); k++)
{
a = k - 0.5f;
a *= a;
a -= v2;
bi += 2;
temp = Cr * Cr + Ci * Ci;
Cr = br + a * Cr / temp;
Ci = bi - a * Ci / temp;
Dr = br + a * Dr;
Di = bi + a * Di;
if (fabs(Cr) + fabs(Ci) < tiny) { Cr = tiny; }
if (fabs(Dr) + fabs(Di) < tiny) { Dr = tiny; }
temp = Dr * Dr + Di * Di;
Dr = Dr / temp;
Di = -Di / temp;
delta_r = Cr * Dr - Ci * Di;
delta_i = Ci * Dr + Cr * Di;
temp = fr;
fr = temp * delta_r - fi * delta_i;
fi = temp * delta_i + fi * delta_r;
if (fabs(delta_r - 1) + fabs(delta_i) < tolerance)
break;
}
policies::check_series_iterations<T>("boost::math::bessel_jy<%1%>(%1%,%1%) in CF2_jy", k, pol);
*p = fr;
*q = fi;
return 0;
}
static const int need_j = 1;
static const int need_y = 2;
// Compute J(v, x) and Y(v, x) simultaneously by Steed's method, see
// Barnett et al, Computer Physics Communications, vol 8, 377 (1974)
template <typename T, typename Policy>
int bessel_jy(T v, T x, T* J, T* Y, int kind, const Policy& pol)
{
BOOST_ASSERT(x >= 0);
T u, Jv, Ju, Yv, Yv1, Yu, Yu1(0), fv, fu;
T W, p, q, gamma, current, prev, next;
bool reflect = false;
unsigned n, k;
int s;
int org_kind = kind;
T cp = 0;
T sp = 0;
static const char* function = "boost::math::bessel_jy<%1%>(%1%,%1%)";
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
if (v < 0)
{
reflect = true;
v = -v; // v is non-negative from here
}
if (v > static_cast<T>((std::numeric_limits<int>::max)()))
{
*J = *Y = policies::raise_evaluation_error<T>(function, "Order of Bessel function is too large to evaluate: got %1%", v, pol);
return 1;
}
n = iround(v, pol);
u = v - n; // -1/2 <= u < 1/2
if(reflect)
{
T z = (u + n % 2);
cp = boost::math::cos_pi(z, pol);
sp = boost::math::sin_pi(z, pol);
if(u != 0)
kind = need_j|need_y; // need both for reflection formula
}
if(x == 0)
{
if(v == 0)
*J = 1;
else if((u == 0) || !reflect)
*J = 0;
else if(kind & need_j)
*J = policies::raise_domain_error<T>(function, "Value of Bessel J_v(x) is complex-infinity at %1%", x, pol); // complex infinity
else
*J = std::numeric_limits<T>::quiet_NaN(); // any value will do, not using J.
if((kind & need_y) == 0)
*Y = std::numeric_limits<T>::quiet_NaN(); // any value will do, not using Y.
else if(v == 0)
*Y = -policies::raise_overflow_error<T>(function, 0, pol);
else
*Y = policies::raise_domain_error<T>(function, "Value of Bessel Y_v(x) is complex-infinity at %1%", x, pol); // complex infinity
return 1;
}
// x is positive until reflection
W = T(2) / (x * pi<T>()); // Wronskian
T Yv_scale = 1;
if(((kind & need_y) == 0) && ((x < 1) || (v > x * x / 4) || (x < 5)))
{
//
// This series will actually converge rapidly for all small
// x - say up to x < 20 - but the first few terms are large
// and divergent which leads to large errors :-(
//
Jv = bessel_j_small_z_series(v, x, pol);
Yv = std::numeric_limits<T>::quiet_NaN();
}
else if((x < 1) && (u != 0) && (log(policies::get_epsilon<T, Policy>() / 2) > v * log((x/2) * (x/2) / v)))
{
// Evaluate using series representations.
// This is particularly important for x << v as in this
// area temme_jy may be slow to converge, if it converges at all.
// Requires x is not an integer.
if(kind&need_j)
Jv = bessel_j_small_z_series(v, x, pol);
else
Jv = std::numeric_limits<T>::quiet_NaN();
if((org_kind&need_y && (!reflect || (cp != 0)))
|| (org_kind & need_j && (reflect && (sp != 0))))
{
// Only calculate if we need it, and if the reflection formula will actually use it:
Yv = bessel_y_small_z_series(v, x, &Yv_scale, pol);
}
else
Yv = std::numeric_limits<T>::quiet_NaN();
}
else if((u == 0) && (x < policies::get_epsilon<T, Policy>()))
{
// Truncated series evaluation for small x and v an integer,
// much quicker in this area than temme_jy below.
if(kind&need_j)
Jv = bessel_j_small_z_series(v, x, pol);
else
Jv = std::numeric_limits<T>::quiet_NaN();
if((org_kind&need_y && (!reflect || (cp != 0)))
|| (org_kind & need_j && (reflect && (sp != 0))))
{
// Only calculate if we need it, and if the reflection formula will actually use it:
Yv = bessel_yn_small_z(n, x, &Yv_scale, pol);
}
else
Yv = std::numeric_limits<T>::quiet_NaN();
}
else if(asymptotic_bessel_large_x_limit(v, x))
{
if(kind&need_y)
{
Yv = asymptotic_bessel_y_large_x_2(v, x);
}
else
Yv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
if(kind&need_j)
{
Jv = asymptotic_bessel_j_large_x_2(v, x);
}
else
Jv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
}
else if((x > 8) && hankel_PQ(v, x, &p, &q, pol))
{
//
// Hankel approximation: note that this method works best when x
// is large, but in that case we end up calculating sines and cosines
// of large values, with horrendous resulting accuracy. It is fast though
// when it works....
//
// Normally we calculate sin/cos(chi) where:
//
// chi = x - fmod(T(v / 2 + 0.25f), T(2)) * boost::math::constants::pi<T>();
//
// But this introduces large errors, so use sin/cos addition formulae to
// improve accuracy:
//
T mod_v = fmod(T(v / 2 + 0.25f), T(2));
T sx = sin(x);
T cx = cos(x);
T sv = sin_pi(mod_v);
T cv = cos_pi(mod_v);
T sc = sx * cv - sv * cx; // == sin(chi);
T cc = cx * cv + sx * sv; // == cos(chi);
T chi = boost::math::constants::root_two<T>() / (boost::math::constants::root_pi<T>() * sqrt(x)); //sqrt(2 / (boost::math::constants::pi<T>() * x));
Yv = chi * (p * sc + q * cc);
Jv = chi * (p * cc - q * sc);
}
else if (x <= 2) // x in (0, 2]
{
if(temme_jy(u, x, &Yu, &Yu1, pol)) // Temme series
{
// domain error:
*J = *Y = Yu;
return 1;
}
prev = Yu;
current = Yu1;
T scale = 1;
policies::check_series_iterations<T>(function, n, pol);
for (k = 1; k <= n; k++) // forward recurrence for Y
{
T fact = 2 * (u + k) / x;
if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
{
scale /= current;
prev /= current;
current = 1;
}
next = fact * current - prev;
prev = current;
current = next;
}
Yv = prev;
Yv1 = current;
if(kind&need_j)
{
CF1_jy(v, x, &fv, &s, pol); // continued fraction CF1_jy
Jv = scale * W / (Yv * fv - Yv1); // Wronskian relation
}
else
Jv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
Yv_scale = scale;
}
else // x in (2, \infty)
{
// Get Y(u, x):
T ratio;
CF1_jy(v, x, &fv, &s, pol);
// tiny initial value to prevent overflow
T init = sqrt(tools::min_value<T>());
BOOST_MATH_INSTRUMENT_VARIABLE(init);
prev = fv * s * init;
current = s * init;
if(v < max_factorial<T>::value)
{
policies::check_series_iterations<T>(function, n, pol);
for (k = n; k > 0; k--) // backward recurrence for J
{
next = 2 * (u + k) * current / x - prev;
prev = current;
current = next;
}
ratio = (s * init) / current; // scaling ratio
// can also call CF1_jy() to get fu, not much difference in precision
fu = prev / current;
}
else
{
//
// When v is large we may get overflow in this calculation
// leading to NaN's and other nasty surprises:
//
policies::check_series_iterations<T>(function, n, pol);
bool over = false;
for (k = n; k > 0; k--) // backward recurrence for J
{
T t = 2 * (u + k) / x;
if((t > 1) && (tools::max_value<T>() / t < current))
{
over = true;
break;
}
next = t * current - prev;
prev = current;
current = next;
}
if(!over)
{
ratio = (s * init) / current; // scaling ratio
// can also call CF1_jy() to get fu, not much difference in precision
fu = prev / current;
}
else
{
ratio = 0;
fu = 1;
}
}
CF2_jy(u, x, &p, &q, pol); // continued fraction CF2_jy
T t = u / x - fu; // t = J'/J
gamma = (p - t) / q;
//
// We can't allow gamma to cancel out to zero competely as it messes up
// the subsequent logic. So pretend that one bit didn't cancel out
// and set to a suitably small value. The only test case we've been able to
// find for this, is when v = 8.5 and x = 4*PI.
//
if(gamma == 0)
{
gamma = u * tools::epsilon<T>() / x;
}
BOOST_MATH_INSTRUMENT_VARIABLE(current);
BOOST_MATH_INSTRUMENT_VARIABLE(W);
BOOST_MATH_INSTRUMENT_VARIABLE(q);
BOOST_MATH_INSTRUMENT_VARIABLE(gamma);
BOOST_MATH_INSTRUMENT_VARIABLE(p);
BOOST_MATH_INSTRUMENT_VARIABLE(t);
Ju = sign(current) * sqrt(W / (q + gamma * (p - t)));
BOOST_MATH_INSTRUMENT_VARIABLE(Ju);
Jv = Ju * ratio; // normalization
Yu = gamma * Ju;
Yu1 = Yu * (u/x - p - q/gamma);
if(kind&need_y)
{
// compute Y:
prev = Yu;
current = Yu1;
policies::check_series_iterations<T>(function, n, pol);
for (k = 1; k <= n; k++) // forward recurrence for Y
{
T fact = 2 * (u + k) / x;
if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
{
prev /= current;
Yv_scale /= current;
current = 1;
}
next = fact * current - prev;
prev = current;
current = next;
}
Yv = prev;
}
else
Yv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
}
if (reflect)
{
if((sp != 0) && (tools::max_value<T>() * fabs(Yv_scale) < fabs(sp * Yv)))
*J = org_kind & need_j ? T(-sign(sp) * sign(Yv) * sign(Yv_scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
else
*J = cp * Jv - (sp == 0 ? T(0) : T((sp * Yv) / Yv_scale)); // reflection formula
if((cp != 0) && (tools::max_value<T>() * fabs(Yv_scale) < fabs(cp * Yv)))
*Y = org_kind & need_y ? T(-sign(cp) * sign(Yv) * sign(Yv_scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
else
*Y = (sp != 0 ? sp * Jv : T(0)) + (cp == 0 ? T(0) : T((cp * Yv) / Yv_scale));
}
else
{
*J = Jv;
if(tools::max_value<T>() * fabs(Yv_scale) < fabs(Yv))
*Y = org_kind & need_y ? T(sign(Yv) * sign(Yv_scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
else
*Y = Yv / Yv_scale;
}
return 0;
}
} // namespace detail
}} // namespaces
#endif // BOOST_MATH_BESSEL_JY_HPP

View File

@@ -0,0 +1,223 @@
// Copyright (c) 2007 John Maddock
// Use, modification and distribution are subject to 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)
//
// This is a partial header, do not include on it's own!!!
//
// Contains asymptotic expansions for Bessel J(v,x) and Y(v,x)
// functions, as x -> INF.
//
#ifndef BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
#define BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/factorials.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T>
inline T asymptotic_bessel_amplitude(T v, T x)
{
// Calculate the amplitude of J(v, x) and Y(v, x) for large
// x: see A&S 9.2.28.
BOOST_MATH_STD_USING
T s = 1;
T mu = 4 * v * v;
T txq = 2 * x;
txq *= txq;
s += (mu - 1) / (2 * txq);
s += 3 * (mu - 1) * (mu - 9) / (txq * txq * 8);
s += 15 * (mu - 1) * (mu - 9) * (mu - 25) / (txq * txq * txq * 8 * 6);
return sqrt(s * 2 / (constants::pi<T>() * x));
}
template <class T>
T asymptotic_bessel_phase_mx(T v, T x)
{
//
// Calculate the phase of J(v, x) and Y(v, x) for large x.
// See A&S 9.2.29.
// Note that the result returned is the phase less (x - PI(v/2 + 1/4))
// which we'll factor in later when we calculate the sines/cosines of the result:
//
T mu = 4 * v * v;
T denom = 4 * x;
T denom_mult = denom * denom;
T s = 0;
s += (mu - 1) / (2 * denom);
denom *= denom_mult;
s += (mu - 1) * (mu - 25) / (6 * denom);
denom *= denom_mult;
s += (mu - 1) * (mu * mu - 114 * mu + 1073) / (5 * denom);
denom *= denom_mult;
s += (mu - 1) * (5 * mu * mu * mu - 1535 * mu * mu + 54703 * mu - 375733) / (14 * denom);
return s;
}
template <class T>
inline T asymptotic_bessel_y_large_x_2(T v, T x)
{
// See A&S 9.2.19.
BOOST_MATH_STD_USING
// Get the phase and amplitude:
T ampl = asymptotic_bessel_amplitude(v, x);
T phase = asymptotic_bessel_phase_mx(v, x);
BOOST_MATH_INSTRUMENT_VARIABLE(ampl);
BOOST_MATH_INSTRUMENT_VARIABLE(phase);
//
// Calculate the sine of the phase, using
// sine/cosine addition rules to factor in
// the x - PI(v/2 + 1/4) term not added to the
// phase when we calculated it.
//
T cx = cos(x);
T sx = sin(x);
T ci = cos_pi(v / 2 + 0.25f);
T si = sin_pi(v / 2 + 0.25f);
T sin_phase = sin(phase) * (cx * ci + sx * si) + cos(phase) * (sx * ci - cx * si);
BOOST_MATH_INSTRUMENT_CODE(sin(phase));
BOOST_MATH_INSTRUMENT_CODE(cos(x));
BOOST_MATH_INSTRUMENT_CODE(cos(phase));
BOOST_MATH_INSTRUMENT_CODE(sin(x));
return sin_phase * ampl;
}
template <class T>
inline T asymptotic_bessel_j_large_x_2(T v, T x)
{
// See A&S 9.2.19.
BOOST_MATH_STD_USING
// Get the phase and amplitude:
T ampl = asymptotic_bessel_amplitude(v, x);
T phase = asymptotic_bessel_phase_mx(v, x);
BOOST_MATH_INSTRUMENT_VARIABLE(ampl);
BOOST_MATH_INSTRUMENT_VARIABLE(phase);
//
// Calculate the sine of the phase, using
// sine/cosine addition rules to factor in
// the x - PI(v/2 + 1/4) term not added to the
// phase when we calculated it.
//
BOOST_MATH_INSTRUMENT_CODE(cos(phase));
BOOST_MATH_INSTRUMENT_CODE(cos(x));
BOOST_MATH_INSTRUMENT_CODE(sin(phase));
BOOST_MATH_INSTRUMENT_CODE(sin(x));
T cx = cos(x);
T sx = sin(x);
T ci = cos_pi(v / 2 + 0.25f);
T si = sin_pi(v / 2 + 0.25f);
T sin_phase = cos(phase) * (cx * ci + sx * si) - sin(phase) * (sx * ci - cx * si);
BOOST_MATH_INSTRUMENT_VARIABLE(sin_phase);
return sin_phase * ampl;
}
template <class T>
inline bool asymptotic_bessel_large_x_limit(int v, const T& x)
{
BOOST_MATH_STD_USING
//
// Determines if x is large enough compared to v to take the asymptotic
// forms above. From A&S 9.2.28 we require:
// v < x * eps^1/8
// and from A&S 9.2.29 we require:
// v^12/10 < 1.5 * x * eps^1/10
// using the former seems to work OK in practice with broadly similar
// error rates either side of the divide for v < 10000.
// At double precision eps^1/8 ~= 0.01.
//
BOOST_ASSERT(v >= 0);
return (v ? v : 1) < x * 0.004f;
}
template <class T>
inline bool asymptotic_bessel_large_x_limit(const T& v, const T& x)
{
BOOST_MATH_STD_USING
//
// Determines if x is large enough compared to v to take the asymptotic
// forms above. From A&S 9.2.28 we require:
// v < x * eps^1/8
// and from A&S 9.2.29 we require:
// v^12/10 < 1.5 * x * eps^1/10
// using the former seems to work OK in practice with broadly similar
// error rates either side of the divide for v < 10000.
// At double precision eps^1/8 ~= 0.01.
//
return (std::max)(T(fabs(v)), T(1)) < x * sqrt(tools::forth_root_epsilon<T>());
}
template <class T, class Policy>
void temme_asyptotic_y_small_x(T v, T x, T* Y, T* Y1, const Policy& pol)
{
T c = 1;
T p = (v / boost::math::sin_pi(v, pol)) * pow(x / 2, -v) / boost::math::tgamma(1 - v, pol);
T q = (v / boost::math::sin_pi(v, pol)) * pow(x / 2, v) / boost::math::tgamma(1 + v, pol);
T f = (p - q) / v;
T g_prefix = boost::math::sin_pi(v / 2, pol);
g_prefix *= g_prefix * 2 / v;
T g = f + g_prefix * q;
T h = p;
T c_mult = -x * x / 4;
T y(c * g), y1(c * h);
for(int k = 1; k < policies::get_max_series_iterations<Policy>(); ++k)
{
f = (k * f + p + q) / (k*k - v*v);
p /= k - v;
q /= k + v;
c *= c_mult / k;
T c1 = pow(-x * x / 4, k) / factorial<T>(k, pol);
g = f + g_prefix * q;
h = -k * g + p;
y += c * g;
y1 += c * h;
if(c * g / tools::epsilon<T>() < y)
break;
}
*Y = -y;
*Y1 = (-2 / x) * y1;
}
template <class T, class Policy>
T asymptotic_bessel_i_large_x(T v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
T s = 1;
T mu = 4 * v * v;
T ex = 8 * x;
T num = mu - 1;
T denom = ex;
s -= num / denom;
num *= mu - 9;
denom *= ex * 2;
s += num / denom;
num *= mu - 25;
denom *= ex * 3;
s -= num / denom;
// Try and avoid overflow to the last minute:
T e = exp(x/2);
s = e * (e * s / sqrt(2 * x * constants::pi<T>()));
return (boost::math::isfinite)(s) ?
s : policies::raise_overflow_error<T>("boost::math::asymptotic_bessel_i_large_x<%1%>(%1%,%1%)", 0, pol);
}
}}} // namespaces
#endif

View File

@@ -0,0 +1,141 @@
// Copyright (c) 2013 Anton Bikineev
// Use, modification and distribution are subject to 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)
//
// This is a partial header, do not include on it's own!!!
//
// Contains asymptotic expansions for derivatives of Bessel J(v,x) and Y(v,x)
// functions, as x -> INF.
#ifndef BOOST_MATH_SF_DETAIL_BESSEL_JY_DERIVATIVES_ASYM_HPP
#define BOOST_MATH_SF_DETAIL_BESSEL_JY_DERIVATIVES_ASYM_HPP
#ifdef _MSC_VER
#pragma once
#endif
namespace boost{ namespace math{ namespace detail{
template <class T>
inline T asymptotic_bessel_derivative_amplitude(T v, T x)
{
// Calculate the amplitude for J'(v,x) and I'(v,x)
// for large x: see A&S 9.2.30.
BOOST_MATH_STD_USING
T s = 1;
const T mu = 4 * v * v;
T txq = 2 * x;
txq *= txq;
s -= (mu - 3) / (2 * txq);
s -= ((mu - 1) * (mu - 45)) / (txq * txq * 8);
return sqrt(s * 2 / (boost::math::constants::pi<T>() * x));
}
template <class T>
inline T asymptotic_bessel_derivative_phase_mx(T v, T x)
{
// Calculate the phase of J'(v, x) and Y'(v, x) for large x.
// See A&S 9.2.31.
// Note that the result returned is the phase less (x - PI(v/2 - 1/4))
// which we'll factor in later when we calculate the sines/cosines of the result:
const T mu = 4 * v * v;
const T mu2 = mu * mu;
const T mu3 = mu2 * mu;
T denom = 4 * x;
T denom_mult = denom * denom;
T s = 0;
s += (mu + 3) / (2 * denom);
denom *= denom_mult;
s += (mu2 + (46 * mu) - 63) / (6 * denom);
denom *= denom_mult;
s += (mu3 + (185 * mu2) - (2053 * mu) + 1899) / (5 * denom);
return s;
}
template <class T>
inline T asymptotic_bessel_y_derivative_large_x_2(T v, T x)
{
// See A&S 9.2.20.
BOOST_MATH_STD_USING
// Get the phase and amplitude:
const T ampl = asymptotic_bessel_derivative_amplitude(v, x);
const T phase = asymptotic_bessel_derivative_phase_mx(v, x);
BOOST_MATH_INSTRUMENT_VARIABLE(ampl);
BOOST_MATH_INSTRUMENT_VARIABLE(phase);
//
// Calculate the sine of the phase, using
// sine/cosine addition rules to factor in
// the x - PI(v/2 - 1/4) term not added to the
// phase when we calculated it.
//
const T cx = cos(x);
const T sx = sin(x);
const T vd2shifted = (v / 2) - 0.25f;
const T ci = cos_pi(vd2shifted);
const T si = sin_pi(vd2shifted);
const T sin_phase = sin(phase) * (cx * ci + sx * si) + cos(phase) * (sx * ci - cx * si);
BOOST_MATH_INSTRUMENT_CODE(sin(phase));
BOOST_MATH_INSTRUMENT_CODE(cos(x));
BOOST_MATH_INSTRUMENT_CODE(cos(phase));
BOOST_MATH_INSTRUMENT_CODE(sin(x));
return sin_phase * ampl;
}
template <class T>
inline T asymptotic_bessel_j_derivative_large_x_2(T v, T x)
{
// See A&S 9.2.20.
BOOST_MATH_STD_USING
// Get the phase and amplitude:
const T ampl = asymptotic_bessel_derivative_amplitude(v, x);
const T phase = asymptotic_bessel_derivative_phase_mx(v, x);
BOOST_MATH_INSTRUMENT_VARIABLE(ampl);
BOOST_MATH_INSTRUMENT_VARIABLE(phase);
//
// Calculate the sine of the phase, using
// sine/cosine addition rules to factor in
// the x - PI(v/2 - 1/4) term not added to the
// phase when we calculated it.
//
BOOST_MATH_INSTRUMENT_CODE(cos(phase));
BOOST_MATH_INSTRUMENT_CODE(cos(x));
BOOST_MATH_INSTRUMENT_CODE(sin(phase));
BOOST_MATH_INSTRUMENT_CODE(sin(x));
const T cx = cos(x);
const T sx = sin(x);
const T vd2shifted = (v / 2) - 0.25f;
const T ci = cos_pi(vd2shifted);
const T si = sin_pi(vd2shifted);
const T sin_phase = cos(phase) * (cx * ci + sx * si) - sin(phase) * (sx * ci - cx * si);
BOOST_MATH_INSTRUMENT_VARIABLE(sin_phase);
return sin_phase * ampl;
}
template <class T>
inline bool asymptotic_bessel_derivative_large_x_limit(const T& v, const T& x)
{
BOOST_MATH_STD_USING
//
// This function is the copy of math::asymptotic_bessel_large_x_limit
// It means that we use the same rules for determining how x is large
// compared to v.
//
// Determines if x is large enough compared to v to take the asymptotic
// forms above. From A&S 9.2.28 we require:
// v < x * eps^1/8
// and from A&S 9.2.29 we require:
// v^12/10 < 1.5 * x * eps^1/10
// using the former seems to work OK in practice with broadly similar
// error rates either side of the divide for v < 10000.
// At double precision eps^1/8 ~= 0.01.
//
return (std::max)(T(fabs(v)), T(1)) < x * sqrt(boost::math::tools::forth_root_epsilon<T>());
}
}}} // namespaces
#endif // BOOST_MATH_SF_DETAIL_BESSEL_JY_DERIVATIVES_ASYM_HPP

View File

@@ -0,0 +1,221 @@
// Copyright (c) 2013 Anton Bikineev
// Use, modification and distribution are subject to 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_BESSEL_JY_DERIVATIVES_SERIES_HPP
#define BOOST_MATH_BESSEL_JY_DERIVATIVES_SERIES_HPP
#ifdef _MSC_VER
#pragma once
#endif
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
struct bessel_j_derivative_small_z_series_term
{
typedef T result_type;
bessel_j_derivative_small_z_series_term(T v_, T x)
: N(0), v(v_), term(1), mult(x / 2)
{
mult *= -mult;
// iterate if v == 0; otherwise result of
// first term is 0 and tools::sum_series stops
if (v == 0)
iterate();
}
T operator()()
{
T r = term * (v + 2 * N);
iterate();
return r;
}
private:
void iterate()
{
++N;
term *= mult / (N * (N + v));
}
unsigned N;
T v;
T term;
T mult;
};
//
// Series evaluation for BesselJ'(v, z) as z -> 0.
// It's derivative of http://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/06/01/04/01/01/0003/
// Converges rapidly for all z << v.
//
template <class T, class Policy>
inline T bessel_j_derivative_small_z_series(T v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
T prefix;
if (v < boost::math::max_factorial<T>::value)
{
prefix = pow(x / 2, v - 1) / 2 / boost::math::tgamma(v + 1, pol);
}
else
{
prefix = (v - 1) * log(x / 2) - constants::ln_two<T>() - boost::math::lgamma(v + 1, pol);
prefix = exp(prefix);
}
if (0 == prefix)
return prefix;
bessel_j_derivative_small_z_series_term<T, Policy> s(v, x);
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::bessel_j_derivative_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
return prefix * result;
}
template <class T, class Policy>
struct bessel_y_derivative_small_z_series_term_a
{
typedef T result_type;
bessel_y_derivative_small_z_series_term_a(T v_, T x)
: N(0), v(v_)
{
mult = x / 2;
mult *= -mult;
term = 1;
}
T operator()()
{
T r = term * (-v + 2 * N);
++N;
term *= mult / (N * (N - v));
return r;
}
private:
unsigned N;
T v;
T mult;
T term;
};
template <class T, class Policy>
struct bessel_y_derivative_small_z_series_term_b
{
typedef T result_type;
bessel_y_derivative_small_z_series_term_b(T v_, T x)
: N(0), v(v_)
{
mult = x / 2;
mult *= -mult;
term = 1;
}
T operator()()
{
T r = term * (v + 2 * N);
++N;
term *= mult / (N * (N + v));
return r;
}
private:
unsigned N;
T v;
T mult;
T term;
};
//
// Series form for BesselY' as z -> 0,
// It's derivative of http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/01/0003/
// This series is only useful when the second term is small compared to the first
// otherwise we get catestrophic cancellation errors.
//
// Approximating tgamma(v) by v^v, and assuming |tgamma(-z)| < eps we end up requiring:
// eps/2 * v^v(x/2)^-v > (x/2)^v or log(eps/2) > v log((x/2)^2/v)
//
template <class T, class Policy>
inline T bessel_y_derivative_small_z_series(T v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* function = "bessel_y_derivative_small_z_series<%1%>(%1%,%1%)";
T prefix;
T gam;
T p = log(x / 2);
T scale = 1;
bool need_logs = (v >= boost::math::max_factorial<T>::value) || (boost::math::tools::log_max_value<T>() / v < fabs(p));
if (!need_logs)
{
gam = boost::math::tgamma(v, pol);
p = pow(x / 2, v + 1) * 2;
if (boost::math::tools::max_value<T>() * p < gam)
{
scale /= gam;
gam = 1;
if (boost::math::tools::max_value<T>() * p < gam)
{
// This term will overflow to -INF, when combined with the series below it becomes +INF:
return boost::math::policies::raise_overflow_error<T>(function, 0, pol);
}
}
prefix = -gam / (boost::math::constants::pi<T>() * p);
}
else
{
gam = boost::math::lgamma(v, pol);
p = (v + 1) * p + constants::ln_two<T>();
prefix = gam - log(boost::math::constants::pi<T>()) - p;
if (boost::math::tools::log_max_value<T>() < prefix)
{
prefix -= log(boost::math::tools::max_value<T>() / 4);
scale /= (boost::math::tools::max_value<T>() / 4);
if (boost::math::tools::log_max_value<T>() < prefix)
{
return boost::math::policies::raise_overflow_error<T>(function, 0, pol);
}
}
prefix = -exp(prefix);
}
bessel_y_derivative_small_z_series_term_a<T, Policy> s(v, x);
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::bessel_y_derivative_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
result *= prefix;
p = pow(x / 2, v - 1) / 2;
if (!need_logs)
{
prefix = boost::math::tgamma(-v, pol) * boost::math::cos_pi(v) * p / boost::math::constants::pi<T>();
}
else
{
int sgn;
prefix = boost::math::lgamma(-v, &sgn, pol) + (v - 1) * log(x / 2) - constants::ln_two<T>();
prefix = exp(prefix) * sgn / boost::math::constants::pi<T>();
}
bessel_y_derivative_small_z_series_term_b<T, Policy> s2(v, x);
max_iter = boost::math::policies::get_max_series_iterations<Policy>();
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
T b = boost::math::tools::sum_series(s2, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
#else
T b = boost::math::tools::sum_series(s2, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
#endif
result += scale * prefix * b;
return result;
}
// Calculating of BesselY'(v,x) with small x (x < epsilon) and integer x using derivatives
// of formulas in http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/02/
// seems to lose precision. Instead using linear combination of regular Bessel is preferred.
}}} // namespaces
#endif // BOOST_MATH_BESSEL_JY_DERIVATVIES_SERIES_HPP

View File

@@ -0,0 +1,261 @@
// Copyright (c) 2011 John Maddock
// Use, modification and distribution are subject to 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_BESSEL_JN_SERIES_HPP
#define BOOST_MATH_BESSEL_JN_SERIES_HPP
#ifdef _MSC_VER
#pragma once
#endif
namespace boost { namespace math { namespace detail{
template <class T, class Policy>
struct bessel_j_small_z_series_term
{
typedef T result_type;
bessel_j_small_z_series_term(T v_, T x)
: N(0), v(v_)
{
BOOST_MATH_STD_USING
mult = x / 2;
mult *= -mult;
term = 1;
}
T operator()()
{
T r = term;
++N;
term *= mult / (N * (N + v));
return r;
}
private:
unsigned N;
T v;
T mult;
T term;
};
//
// Series evaluation for BesselJ(v, z) as z -> 0.
// See http://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/06/01/04/01/01/0003/
// Converges rapidly for all z << v.
//
template <class T, class Policy>
inline T bessel_j_small_z_series(T v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
T prefix;
if(v < max_factorial<T>::value)
{
prefix = pow(x / 2, v) / boost::math::tgamma(v+1, pol);
}
else
{
prefix = v * log(x / 2) - boost::math::lgamma(v+1, pol);
prefix = exp(prefix);
}
if(0 == prefix)
return prefix;
bessel_j_small_z_series_term<T, Policy> s(v, x);
boost::uintmax_t max_iter = 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
policies::check_series_iterations<T>("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
return prefix * result;
}
template <class T, class Policy>
struct bessel_y_small_z_series_term_a
{
typedef T result_type;
bessel_y_small_z_series_term_a(T v_, T x)
: N(0), v(v_)
{
BOOST_MATH_STD_USING
mult = x / 2;
mult *= -mult;
term = 1;
}
T operator()()
{
BOOST_MATH_STD_USING
T r = term;
++N;
term *= mult / (N * (N - v));
return r;
}
private:
unsigned N;
T v;
T mult;
T term;
};
template <class T, class Policy>
struct bessel_y_small_z_series_term_b
{
typedef T result_type;
bessel_y_small_z_series_term_b(T v_, T x)
: N(0), v(v_)
{
BOOST_MATH_STD_USING
mult = x / 2;
mult *= -mult;
term = 1;
}
T operator()()
{
T r = term;
++N;
term *= mult / (N * (N + v));
return r;
}
private:
unsigned N;
T v;
T mult;
T term;
};
//
// Series form for BesselY as z -> 0,
// see: http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/01/0003/
// This series is only useful when the second term is small compared to the first
// otherwise we get catestrophic cancellation errors.
//
// Approximating tgamma(v) by v^v, and assuming |tgamma(-z)| < eps we end up requiring:
// eps/2 * v^v(x/2)^-v > (x/2)^v or log(eps/2) > v log((x/2)^2/v)
//
template <class T, class Policy>
inline T bessel_y_small_z_series(T v, T x, T* pscale, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* function = "bessel_y_small_z_series<%1%>(%1%,%1%)";
T prefix;
T gam;
T p = log(x / 2);
T scale = 1;
bool need_logs = (v >= max_factorial<T>::value) || (tools::log_max_value<T>() / v < fabs(p));
if(!need_logs)
{
gam = boost::math::tgamma(v, pol);
p = pow(x / 2, v);
if(tools::max_value<T>() * p < gam)
{
scale /= gam;
gam = 1;
if(tools::max_value<T>() * p < gam)
{
return -policies::raise_overflow_error<T>(function, 0, pol);
}
}
prefix = -gam / (constants::pi<T>() * p);
}
else
{
gam = boost::math::lgamma(v, pol);
p = v * p;
prefix = gam - log(constants::pi<T>()) - p;
if(tools::log_max_value<T>() < prefix)
{
prefix -= log(tools::max_value<T>() / 4);
scale /= (tools::max_value<T>() / 4);
if(tools::log_max_value<T>() < prefix)
{
return -policies::raise_overflow_error<T>(function, 0, pol);
}
}
prefix = -exp(prefix);
}
bessel_y_small_z_series_term_a<T, Policy> s(v, x);
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
*pscale = scale;
#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
policies::check_series_iterations<T>("boost::math::bessel_y_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
result *= prefix;
if(!need_logs)
{
prefix = boost::math::tgamma(-v, pol) * boost::math::cos_pi(v) * p / constants::pi<T>();
}
else
{
int sgn;
prefix = boost::math::lgamma(-v, &sgn, pol) + p;
prefix = exp(prefix) * sgn / constants::pi<T>();
}
bessel_y_small_z_series_term_b<T, Policy> s2(v, x);
max_iter = policies::get_max_series_iterations<Policy>();
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
T b = boost::math::tools::sum_series(s2, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
#else
T b = boost::math::tools::sum_series(s2, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
#endif
result -= scale * prefix * b;
return result;
}
template <class T, class Policy>
T bessel_yn_small_z(int n, T z, T* scale, const Policy& pol)
{
//
// See http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/02/
//
// Note that when called we assume that x < epsilon and n is a positive integer.
//
BOOST_MATH_STD_USING
BOOST_ASSERT(n >= 0);
BOOST_ASSERT((z < policies::get_epsilon<T, Policy>()));
if(n == 0)
{
return (2 / constants::pi<T>()) * (log(z / 2) + constants::euler<T>());
}
else if(n == 1)
{
return (z / constants::pi<T>()) * log(z / 2)
- 2 / (constants::pi<T>() * z)
- (z / (2 * constants::pi<T>())) * (1 - 2 * constants::euler<T>());
}
else if(n == 2)
{
return (z * z) / (4 * constants::pi<T>()) * log(z / 2)
- (4 / (constants::pi<T>() * z * z))
- ((z * z) / (8 * constants::pi<T>())) * (T(3)/2 - 2 * constants::euler<T>());
}
else
{
T p = pow(z / 2, n);
T result = -((boost::math::factorial<T>(n - 1) / constants::pi<T>()));
if(p * tools::max_value<T>() < result)
{
T div = tools::max_value<T>() / 8;
result /= div;
*scale /= div;
if(p * tools::max_value<T>() < result)
{
return -policies::raise_overflow_error<T>("bessel_yn_small_z<%1%>(%1%,%1%)", 0, pol);
}
}
return result / p;
}
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_JN_SERIES_HPP

View File

@@ -0,0 +1,617 @@
// Copyright (c) 2013 Christopher Kormanyos
// Use, modification and distribution are subject to 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)
//
// This work is based on an earlier work:
// "Algorithm 910: A Portable C++ Multiple-Precision System for Special-Function Calculations",
// in ACM TOMS, {VOL 37, ISSUE 4, (February 2011)} (C) ACM, 2011. http://doi.acm.org/10.1145/1916461.1916469
//
// This header contains implementation details for estimating the zeros
// of cylindrical Bessel and Neumann functions on the positive real axis.
// Support is included for both positive as well as negative order.
// Various methods are used to estimate the roots. These include
// empirical curve fitting and McMahon's asymptotic approximation
// for small order, uniform asymptotic expansion for large order,
// and iteration and root interlacing for negative order.
//
#ifndef _BESSEL_JY_ZERO_2013_01_18_HPP_
#define _BESSEL_JY_ZERO_2013_01_18_HPP_
#include <algorithm>
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/cbrt.hpp>
#include <boost/math/special_functions/detail/airy_ai_bi_zero.hpp>
namespace boost { namespace math {
namespace detail
{
namespace bessel_zero
{
template<class T>
T equation_nist_10_21_19(const T& v, const T& a)
{
// Get the initial estimate of the m'th root of Jv or Yv.
// This subroutine is used for the order m with m > 1.
// The order m has been used to create the input parameter a.
// This is Eq. 10.21.19 in the NIST Handbook.
const T mu = (v * v) * 4U;
const T mu_minus_one = mu - T(1);
const T eight_a_inv = T(1) / (a * 8U);
const T eight_a_inv_squared = eight_a_inv * eight_a_inv;
const T term3 = ((mu_minus_one * 4U) * ((mu * 7U) - T(31U) )) / 3U;
const T term5 = ((mu_minus_one * 32U) * ((((mu * 83U) - T(982U) ) * mu) + T(3779U) )) / 15U;
const T term7 = ((mu_minus_one * 64U) * ((((((mu * 6949U) - T(153855UL)) * mu) + T(1585743UL)) * mu) - T(6277237UL))) / 105U;
return a + (((( - term7
* eight_a_inv_squared - term5)
* eight_a_inv_squared - term3)
* eight_a_inv_squared - mu_minus_one)
* eight_a_inv);
}
template<typename T>
class equation_as_9_3_39_and_its_derivative
{
public:
equation_as_9_3_39_and_its_derivative(const T& zt) : zeta(zt) { }
boost::math::tuple<T, T> operator()(const T& z) const
{
BOOST_MATH_STD_USING // ADL of std names, needed for acos, sqrt.
// Return the function of zeta that is implicitly defined
// in A&S Eq. 9.3.39 as a function of z. The function is
// returned along with its derivative with respect to z.
const T zsq_minus_one_sqrt = sqrt((z * z) - T(1));
const T the_function(
zsq_minus_one_sqrt
- ( acos(T(1) / z) + ((T(2) / 3U) * (zeta * sqrt(zeta)))));
const T its_derivative(zsq_minus_one_sqrt / z);
return boost::math::tuple<T, T>(the_function, its_derivative);
}
private:
const equation_as_9_3_39_and_its_derivative& operator=(const equation_as_9_3_39_and_its_derivative&);
const T zeta;
};
template<class T>
static T equation_as_9_5_26(const T& v, const T& ai_bi_root)
{
BOOST_MATH_STD_USING // ADL of std names, needed for log, sqrt.
// Obtain the estimate of the m'th zero of Jv or Yv.
// The order m has been used to create the input parameter ai_bi_root.
// Here, v is larger than about 2.2. The estimate is computed
// from Abramowitz and Stegun Eqs. 9.5.22 and 9.5.26, page 371.
//
// The inversion of z as a function of zeta is mentioned in the text
// following A&S Eq. 9.5.26. Here, we accomplish the inversion by
// performing a Taylor expansion of Eq. 9.3.39 for large z to order 2
// and solving the resulting quadratic equation, thereby taking
// the positive root of the quadratic.
// In other words: (2/3)(-zeta)^(3/2) approx = z + 1/(2z) - pi/2.
// This leads to: z^2 - [(2/3)(-zeta)^(3/2) + pi/2]z + 1/2 = 0.
//
// With this initial estimate, Newton-Raphson iteration is used
// to refine the value of the estimate of the root of z
// as a function of zeta.
const T v_pow_third(boost::math::cbrt(v));
const T v_pow_minus_two_thirds(T(1) / (v_pow_third * v_pow_third));
// Obtain zeta using the order v combined with the m'th root of
// an airy function, as shown in A&S Eq. 9.5.22.
const T zeta = v_pow_minus_two_thirds * (-ai_bi_root);
const T zeta_sqrt = sqrt(zeta);
// Set up a quadratic equation based on the Taylor series
// expansion mentioned above.
const T b = -((((zeta * zeta_sqrt) * 2U) / 3U) + boost::math::constants::half_pi<T>());
// Solve the quadratic equation, taking the positive root.
const T z_estimate = (-b + sqrt((b * b) - T(2))) / 2U;
// Establish the range, the digits, and the iteration limit
// for the upcoming root-finding.
const T range_zmin = (std::max<T>)(z_estimate - T(1), T(1));
const T range_zmax = z_estimate + T(1);
const int my_digits10 = static_cast<int>(static_cast<float>(boost::math::tools::digits<T>() * 0.301F));
// Select the maximum allowed iterations based on the number
// of decimal digits in the numeric type T, being at least 12.
const boost::uintmax_t iterations_allowed = static_cast<boost::uintmax_t>((std::max)(12, my_digits10 * 2));
boost::uintmax_t iterations_used = iterations_allowed;
// Calculate the root of z as a function of zeta.
const T z = boost::math::tools::newton_raphson_iterate(
boost::math::detail::bessel_zero::equation_as_9_3_39_and_its_derivative<T>(zeta),
z_estimate,
range_zmin,
range_zmax,
(std::min)(boost::math::tools::digits<T>(), boost::math::tools::digits<float>()),
iterations_used);
static_cast<void>(iterations_used);
// Continue with the implementation of A&S Eq. 9.3.39.
const T zsq_minus_one = (z * z) - T(1);
const T zsq_minus_one_sqrt = sqrt(zsq_minus_one);
// This is A&S Eq. 9.3.42.
const T b0_term_5_24 = T(5) / ((zsq_minus_one * zsq_minus_one_sqrt) * 24U);
const T b0_term_1_8 = T(1) / ( zsq_minus_one_sqrt * 8U);
const T b0_term_5_48 = T(5) / ((zeta * zeta) * 48U);
const T b0 = -b0_term_5_48 + ((b0_term_5_24 + b0_term_1_8) / zeta_sqrt);
// This is the second line of A&S Eq. 9.5.26 for f_k with k = 1.
const T f1 = ((z * zeta_sqrt) * b0) / zsq_minus_one_sqrt;
// This is A&S Eq. 9.5.22 expanded to k = 1 (i.e., one term in the series).
return (v * z) + (f1 / v);
}
namespace cyl_bessel_j_zero_detail
{
template<class T>
T equation_nist_10_21_40_a(const T& v)
{
const T v_pow_third(boost::math::cbrt(v));
const T v_pow_minus_two_thirds(T(1) / (v_pow_third * v_pow_third));
return v * ((((( + T(0.043)
* v_pow_minus_two_thirds - T(0.0908))
* v_pow_minus_two_thirds - T(0.00397))
* v_pow_minus_two_thirds + T(1.033150))
* v_pow_minus_two_thirds + T(1.8557571))
* v_pow_minus_two_thirds + T(1));
}
template<class T, class Policy>
class function_object_jv
{
public:
function_object_jv(const T& v,
const Policy& pol) : my_v(v),
my_pol(pol) { }
T operator()(const T& x) const
{
return boost::math::cyl_bessel_j(my_v, x, my_pol);
}
private:
const T my_v;
const Policy& my_pol;
const function_object_jv& operator=(const function_object_jv&);
};
template<class T, class Policy>
class function_object_jv_and_jv_prime
{
public:
function_object_jv_and_jv_prime(const T& v,
const bool order_is_zero,
const Policy& pol) : my_v(v),
my_order_is_zero(order_is_zero),
my_pol(pol) { }
boost::math::tuple<T, T> operator()(const T& x) const
{
// Obtain Jv(x) and Jv'(x).
// Chris's original code called the Bessel function implementation layer direct,
// but that circumvented optimizations for integer-orders. Call the documented
// top level functions instead, and let them sort out which implementation to use.
T j_v;
T j_v_prime;
if(my_order_is_zero)
{
j_v = boost::math::cyl_bessel_j(0, x, my_pol);
j_v_prime = -boost::math::cyl_bessel_j(1, x, my_pol);
}
else
{
j_v = boost::math::cyl_bessel_j( my_v, x, my_pol);
const T j_v_m1 (boost::math::cyl_bessel_j(T(my_v - 1), x, my_pol));
j_v_prime = j_v_m1 - ((my_v * j_v) / x);
}
// Return a tuple containing both Jv(x) and Jv'(x).
return boost::math::make_tuple(j_v, j_v_prime);
}
private:
const T my_v;
const bool my_order_is_zero;
const Policy& my_pol;
const function_object_jv_and_jv_prime& operator=(const function_object_jv_and_jv_prime&);
};
template<class T> bool my_bisection_unreachable_tolerance(const T&, const T&) { return false; }
template<class T, class Policy>
T initial_guess(const T& v, const int m, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names, needed for floor.
// Compute an estimate of the m'th root of cyl_bessel_j.
T guess;
// There is special handling for negative order.
if(v < 0)
{
if((m == 1) && (v > -0.5F))
{
// For small, negative v, use the results of empirical curve fitting.
// Mathematica(R) session for the coefficients:
// Table[{n, BesselJZero[n, 1]}, {n, -(1/2), 0, 1/10}]
// N[%, 20]
// Fit[%, {n^0, n^1, n^2, n^3, n^4, n^5, n^6}, n]
guess = ((((( - T(0.2321156900729)
* v - T(0.1493247777488))
* v - T(0.15205419167239))
* v + T(0.07814930561249))
* v - T(0.17757573537688))
* v + T(1.542805677045663))
* v + T(2.40482555769577277);
return guess;
}
// Create the positive order and extract its positive floor integer part.
const T vv(-v);
const T vv_floor(floor(vv));
// The to-be-found root is bracketed by the roots of the
// Bessel function whose reflected, positive integer order
// is less than, but nearest to vv.
T root_hi = boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::initial_guess(vv_floor, m, pol);
T root_lo;
if(m == 1)
{
// The estimate of the first root for negative order is found using
// an adaptive range-searching algorithm.
root_lo = T(root_hi - 0.1F);
const bool hi_end_of_bracket_is_negative = (boost::math::cyl_bessel_j(v, root_hi, pol) < 0);
while((root_lo > boost::math::tools::epsilon<T>()))
{
const bool lo_end_of_bracket_is_negative = (boost::math::cyl_bessel_j(v, root_lo, pol) < 0);
if(hi_end_of_bracket_is_negative != lo_end_of_bracket_is_negative)
{
break;
}
root_hi = root_lo;
// Decrease the lower end of the bracket using an adaptive algorithm.
if(root_lo > 0.5F)
{
root_lo -= 0.5F;
}
else
{
root_lo *= 0.75F;
}
}
}
else
{
root_lo = boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::initial_guess(vv_floor, m - 1, pol);
}
// Perform several steps of bisection iteration to refine the guess.
boost::uintmax_t number_of_iterations(12U);
// Do the bisection iteration.
const boost::math::tuple<T, T> guess_pair =
boost::math::tools::bisect(
boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::function_object_jv<T, Policy>(v, pol),
root_lo,
root_hi,
boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::my_bisection_unreachable_tolerance<T>,
number_of_iterations);
return (boost::math::get<0>(guess_pair) + boost::math::get<1>(guess_pair)) / 2U;
}
if(m == 1U)
{
// Get the initial estimate of the first root.
if(v < 2.2F)
{
// For small v, use the results of empirical curve fitting.
// Mathematica(R) session for the coefficients:
// Table[{n, BesselJZero[n, 1]}, {n, 0, 22/10, 1/10}]
// N[%, 20]
// Fit[%, {n^0, n^1, n^2, n^3, n^4, n^5, n^6}, n]
guess = ((((( - T(0.0008342379046010)
* v + T(0.007590035637410))
* v - T(0.030640914772013))
* v + T(0.078232088020106))
* v - T(0.169668712590620))
* v + T(1.542187960073750))
* v + T(2.4048359915254634);
}
else
{
// For larger v, use the first line of Eqs. 10.21.40 in the NIST Handbook.
guess = boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::equation_nist_10_21_40_a(v);
}
}
else
{
if(v < 2.2F)
{
// Use Eq. 10.21.19 in the NIST Handbook.
const T a(((v + T(m * 2U)) - T(0.5)) * boost::math::constants::half_pi<T>());
guess = boost::math::detail::bessel_zero::equation_nist_10_21_19(v, a);
}
else
{
// Get an estimate of the m'th root of airy_ai.
const T airy_ai_root(boost::math::detail::airy_zero::airy_ai_zero_detail::initial_guess<T>(m));
// Use Eq. 9.5.26 in the A&S Handbook.
guess = boost::math::detail::bessel_zero::equation_as_9_5_26(v, airy_ai_root);
}
}
return guess;
}
} // namespace cyl_bessel_j_zero_detail
namespace cyl_neumann_zero_detail
{
template<class T>
T equation_nist_10_21_40_b(const T& v)
{
const T v_pow_third(boost::math::cbrt(v));
const T v_pow_minus_two_thirds(T(1) / (v_pow_third * v_pow_third));
return v * ((((( - T(0.001)
* v_pow_minus_two_thirds - T(0.0060))
* v_pow_minus_two_thirds + T(0.01198))
* v_pow_minus_two_thirds + T(0.260351))
* v_pow_minus_two_thirds + T(0.9315768))
* v_pow_minus_two_thirds + T(1));
}
template<class T, class Policy>
class function_object_yv
{
public:
function_object_yv(const T& v,
const Policy& pol) : my_v(v),
my_pol(pol) { }
T operator()(const T& x) const
{
return boost::math::cyl_neumann(my_v, x, my_pol);
}
private:
const T my_v;
const Policy& my_pol;
const function_object_yv& operator=(const function_object_yv&);
};
template<class T, class Policy>
class function_object_yv_and_yv_prime
{
public:
function_object_yv_and_yv_prime(const T& v,
const Policy& pol) : my_v(v),
my_pol(pol) { }
boost::math::tuple<T, T> operator()(const T& x) const
{
const T half_epsilon(boost::math::tools::epsilon<T>() / 2U);
const bool order_is_zero = ((my_v > -half_epsilon) && (my_v < +half_epsilon));
// Obtain Yv(x) and Yv'(x).
// Chris's original code called the Bessel function implementation layer direct,
// but that circumvented optimizations for integer-orders. Call the documented
// top level functions instead, and let them sort out which implementation to use.
T y_v;
T y_v_prime;
if(order_is_zero)
{
y_v = boost::math::cyl_neumann(0, x, my_pol);
y_v_prime = -boost::math::cyl_neumann(1, x, my_pol);
}
else
{
y_v = boost::math::cyl_neumann( my_v, x, my_pol);
const T y_v_m1 (boost::math::cyl_neumann(T(my_v - 1), x, my_pol));
y_v_prime = y_v_m1 - ((my_v * y_v) / x);
}
// Return a tuple containing both Yv(x) and Yv'(x).
return boost::math::make_tuple(y_v, y_v_prime);
}
private:
const T my_v;
const Policy& my_pol;
const function_object_yv_and_yv_prime& operator=(const function_object_yv_and_yv_prime&);
};
template<class T> bool my_bisection_unreachable_tolerance(const T&, const T&) { return false; }
template<class T, class Policy>
T initial_guess(const T& v, const int m, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names, needed for floor.
// Compute an estimate of the m'th root of cyl_neumann.
T guess;
// There is special handling for negative order.
if(v < 0)
{
// Create the positive order and extract its positive floor and ceiling integer parts.
const T vv(-v);
const T vv_floor(floor(vv));
// The to-be-found root is bracketed by the roots of the
// Bessel function whose reflected, positive integer order
// is less than, but nearest to vv.
// The special case of negative, half-integer order uses
// the relation between Yv and spherical Bessel functions
// in order to obtain the bracket for the root.
// In these special cases, cyl_neumann(-n/2, x) = sph_bessel_j(+n/2, x)
// for v = -n/2.
T root_hi;
T root_lo;
if(m == 1)
{
// The estimate of the first root for negative order is found using
// an adaptive range-searching algorithm.
// Take special precautions for the discontinuity at negative,
// half-integer orders and use different brackets above and below these.
if(T(vv - vv_floor) < 0.5F)
{
root_hi = boost::math::detail::bessel_zero::cyl_neumann_zero_detail::initial_guess(vv_floor, m, pol);
}
else
{
root_hi = boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::initial_guess(T(vv_floor + 0.5F), m, pol);
}
root_lo = T(root_hi - 0.1F);
const bool hi_end_of_bracket_is_negative = (boost::math::cyl_neumann(v, root_hi, pol) < 0);
while((root_lo > boost::math::tools::epsilon<T>()))
{
const bool lo_end_of_bracket_is_negative = (boost::math::cyl_neumann(v, root_lo, pol) < 0);
if(hi_end_of_bracket_is_negative != lo_end_of_bracket_is_negative)
{
break;
}
root_hi = root_lo;
// Decrease the lower end of the bracket using an adaptive algorithm.
if(root_lo > 0.5F)
{
root_lo -= 0.5F;
}
else
{
root_lo *= 0.75F;
}
}
}
else
{
if(T(vv - vv_floor) < 0.5F)
{
root_lo = boost::math::detail::bessel_zero::cyl_neumann_zero_detail::initial_guess(vv_floor, m - 1, pol);
root_hi = boost::math::detail::bessel_zero::cyl_neumann_zero_detail::initial_guess(vv_floor, m, pol);
root_lo += 0.01F;
root_hi += 0.01F;
}
else
{
root_lo = boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::initial_guess(T(vv_floor + 0.5F), m - 1, pol);
root_hi = boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::initial_guess(T(vv_floor + 0.5F), m, pol);
root_lo += 0.01F;
root_hi += 0.01F;
}
}
// Perform several steps of bisection iteration to refine the guess.
boost::uintmax_t number_of_iterations(12U);
// Do the bisection iteration.
const boost::math::tuple<T, T> guess_pair =
boost::math::tools::bisect(
boost::math::detail::bessel_zero::cyl_neumann_zero_detail::function_object_yv<T, Policy>(v, pol),
root_lo,
root_hi,
boost::math::detail::bessel_zero::cyl_neumann_zero_detail::my_bisection_unreachable_tolerance<T>,
number_of_iterations);
return (boost::math::get<0>(guess_pair) + boost::math::get<1>(guess_pair)) / 2U;
}
if(m == 1U)
{
// Get the initial estimate of the first root.
if(v < 2.2F)
{
// For small v, use the results of empirical curve fitting.
// Mathematica(R) session for the coefficients:
// Table[{n, BesselYZero[n, 1]}, {n, 0, 22/10, 1/10}]
// N[%, 20]
// Fit[%, {n^0, n^1, n^2, n^3, n^4, n^5, n^6}, n]
guess = ((((( - T(0.0025095909235652)
* v + T(0.021291887049053))
* v - T(0.076487785486526))
* v + T(0.159110268115362))
* v - T(0.241681668765196))
* v + T(1.4437846310885244))
* v + T(0.89362115190200490);
}
else
{
// For larger v, use the second line of Eqs. 10.21.40 in the NIST Handbook.
guess = boost::math::detail::bessel_zero::cyl_neumann_zero_detail::equation_nist_10_21_40_b(v);
}
}
else
{
if(v < 2.2F)
{
// Use Eq. 10.21.19 in the NIST Handbook.
const T a(((v + T(m * 2U)) - T(1.5)) * boost::math::constants::half_pi<T>());
guess = boost::math::detail::bessel_zero::equation_nist_10_21_19(v, a);
}
else
{
// Get an estimate of the m'th root of airy_bi.
const T airy_bi_root(boost::math::detail::airy_zero::airy_bi_zero_detail::initial_guess<T>(m));
// Use Eq. 9.5.26 in the A&S Handbook.
guess = boost::math::detail::bessel_zero::equation_as_9_5_26(v, airy_bi_root);
}
}
return guess;
}
} // namespace cyl_neumann_zero_detail
} // namespace bessel_zero
} } } // namespace boost::math::detail
#endif // _BESSEL_JY_ZERO_2013_01_18_HPP_

View File

@@ -0,0 +1,509 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2017 John Maddock
// Use, modification and distribution are subject to 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_BESSEL_K0_HPP
#define BOOST_MATH_BESSEL_K0_HPP
#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/assert.hpp>
// Modified Bessel function of the second kind of order zero
// minimax rational approximations on intervals, see
// Russon and Blair, Chalk River Report AECL-3461, 1969,
// as revised by Pavel Holoborodko in "Rational Approximations
// for the Modified Bessel Function of the Second Kind - K0(x)
// for Computations with Double Precision", see
// http://www.advanpix.com/2015/11/25/rational-approximations-for-the-modified-bessel-function-of-the-second-kind-k0-for-computations-with-double-precision/
//
// The actual coefficients used are our own derivation (by JM)
// since we extend to both greater and lesser precision than the
// references above. We can also improve performance WRT to
// Holoborodko without loss of precision.
namespace boost { namespace math { namespace detail{
template <typename T>
T bessel_k0(const T& x);
template <class T, class tag>
struct bessel_k0_initializer
{
struct init
{
init()
{
do_init(tag());
}
static void do_init(const mpl::int_<113>&)
{
bessel_k0(T(0.5));
bessel_k0(T(1.5));
}
static void do_init(const mpl::int_<64>&)
{
bessel_k0(T(0.5));
bessel_k0(T(1.5));
}
template <class U>
static void do_init(const U&){}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class tag>
const typename bessel_k0_initializer<T, tag>::init bessel_k0_initializer<T, tag>::initializer;
template <typename T, int N>
T bessel_k0_imp(const T& x, const mpl::int_<N>&)
{
BOOST_ASSERT(0);
return 0;
}
template <typename T>
T bessel_k0_imp(const T& x, const mpl::int_<24>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found : 2.358e-09
// Expected Error Term : -2.358e-09
// Maximum Relative Change in Control Points : 9.552e-02
// Max Error found at float precision = Poly : 4.448220e-08
static const T Y = 1.137250900268554688f;
static const T P[] =
{
-1.372508979104259711e-01f,
2.622545986273687617e-01f,
5.047103728247919836e-03f
};
static const T Q[] =
{
1.000000000000000000e+00f,
-8.928694018000029415e-02f,
2.985980684180969241e-03f
};
T a = x * x / 4;
a = (tools::evaluate_rational(P, Q, a) + Y) * a + 1;
// Maximum Deviation Found: 1.346e-09
// Expected Error Term : -1.343e-09
// Maximum Relative Change in Control Points : 2.405e-02
// Max Error found at float precision = Poly : 1.354814e-07
static const T P2[] = {
1.159315158e-01f,
2.789828686e-01f,
2.524902861e-02f,
8.457241514e-04f,
1.530051997e-05f
};
return tools::evaluate_polynomial(P2, T(x * x)) - log(x) * a;
}
else
{
// Maximum Deviation Found: 1.587e-08
// Expected Error Term : 1.531e-08
// Maximum Relative Change in Control Points : 9.064e-02
// Max Error found at float precision = Poly : 5.065020e-08
static const T P[] =
{
2.533141220e-01,
5.221502603e-01,
6.380180669e-02,
-5.934976547e-02
};
static const T Q[] =
{
1.000000000e+00,
2.679722431e+00,
1.561635813e+00,
1.573660661e-01
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_rational(P, Q, T(1 / x)) + 1) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_rational(P, Q, T(1 / x)) + 1) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k0_imp(const T& x, const mpl::int_<53>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found: 6.077e-17
// Expected Error Term : -6.077e-17
// Maximum Relative Change in Control Points : 7.797e-02
// Max Error found at double precision = Poly : 1.003156e-16
static const T Y = 1.137250900268554688;
static const T P[] =
{
-1.372509002685546267e-01,
2.574916117833312855e-01,
1.395474602146869316e-02,
5.445476986653926759e-04,
7.125159422136622118e-06
};
static const T Q[] =
{
1.000000000000000000e+00,
-5.458333438017788530e-02,
1.291052816975251298e-03,
-1.367653946978586591e-05
};
T a = x * x / 4;
a = (tools::evaluate_polynomial(P, a) / tools::evaluate_polynomial(Q, a) + Y) * a + 1;
// Maximum Deviation Found: 3.429e-18
// Expected Error Term : 3.392e-18
// Maximum Relative Change in Control Points : 2.041e-02
// Max Error found at double precision = Poly : 2.513112e-16
static const T P2[] =
{
1.159315156584124484e-01,
2.789828789146031732e-01,
2.524892993216121934e-02,
8.460350907213637784e-04,
1.491471924309617534e-05,
1.627106892422088488e-07,
1.208266102392756055e-09,
6.611686391749704310e-12
};
return tools::evaluate_polynomial(P2, T(x * x)) - log(x) * a;
}
else
{
// Maximum Deviation Found: 4.316e-17
// Expected Error Term : 9.570e-18
// Maximum Relative Change in Control Points : 2.757e-01
// Max Error found at double precision = Poly : 1.001560e-16
static const T Y = 1;
static const T P[] =
{
2.533141373155002416e-01,
3.628342133984595192e+00,
1.868441889406606057e+01,
4.306243981063412784e+01,
4.424116209627428189e+01,
1.562095339356220468e+01,
-1.810138978229410898e+00,
-1.414237994269995877e+00,
-9.369168119754924625e-02
};
static const T Q[] =
{
1.000000000000000000e+00,
1.494194694879908328e+01,
8.265296455388554217e+01,
2.162779506621866970e+02,
2.845145155184222157e+02,
1.851714491916334995e+02,
5.486540717439723515e+01,
6.118075837628957015e+00,
1.586261269326235053e-01
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k0_imp(const T& x, const mpl::int_<64>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found: 2.180e-22
// Expected Error Term : 2.180e-22
// Maximum Relative Change in Control Points : 2.943e-01
// Max Error found at float80 precision = Poly : 3.923207e-20
static const T Y = 1.137250900268554687500e+00;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, -1.372509002685546875002e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.566481981037407600436e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.551881122448948854873e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.646112454323276529650e-04),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.213747930378196492543e-05),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.423709328020389560844e-08)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 1.000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.843828412587773008342e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.088484822515098936140e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.374724008530702784829e-05),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.452665455952581680339e-08)
};
T a = x * x / 4;
a = (tools::evaluate_polynomial(P, a) / tools::evaluate_polynomial(Q, a) + Y) * a + 1;
// Maximum Deviation Found: 2.440e-21
// Expected Error Term : -2.434e-21
// Maximum Relative Change in Control Points : 2.459e-02
// Max Error found at float80 precision = Poly : 1.482487e-19
static const T P2[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 1.159315156584124488110e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.764832791416047889734e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.926062887220923354112e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.660777862036966089410e-04),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.094942446930673386849e-06)
};
static const T Q2[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 1.000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -2.156100313881251616320e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.315993873344905957033e-04),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.529444499350703363451e-06),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.524988589917857531177e-09)
};
return tools::evaluate_rational(P2, Q2, T(x * x)) - log(x) * a;
}
else
{
// Maximum Deviation Found: 4.291e-20
// Expected Error Term : 2.236e-21
// Maximum Relative Change in Control Points : 3.021e-01
//Max Error found at float80 precision = Poly : 8.727378e-20
static const T Y = 1;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 2.533141373155002512056e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.417942070721928652715e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.477464607463971754433e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.838745728725943889876e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.009736314927811202517e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.557411293123609803452e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.360222564015361268955e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.385435333168505701022e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.750195760942181592050e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.059789241612946683713e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.612783121537333908889e-01)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 1.000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.200669254769325861404e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.900177593527144126549e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.361003989965786932682e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.041319870804843395893e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.828491555113790345068e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.190342229261529076624e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.003330795963812219852e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.773371397243777891569e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.368634935531158398439e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.543310879400359967327e-01)
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k0_imp(const T& x, const mpl::int_<113>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found: 5.682e-37
// Expected Error Term : 5.682e-37
// Maximum Relative Change in Control Points : 6.094e-04
// Max Error found at float128 precision = Poly : 5.338213e-35
static const T Y = 1.137250900268554687500000000000000000e+00f;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, -1.372509002685546875000000000000000006e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.556212905071072782462974351698081303e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.742459135264203478530904179889103929e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.077860530453688571555479526961318918e-04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.868173911669241091399374307788635148e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.496405768838992243478709145123306602e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.752489221949580551692915881999762125e-09),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.243010555737173524710512824955368526e-12)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 1.000000000000000000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.095631064064621099785696980653193721e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.313880983725212151967078809725835532e-04),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.095229912293480063501285562382835142e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.022828799511943141130509410251996277e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, -6.860874007419812445494782795829046836e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.107297802344970725756092082686799037e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.460529579244623559164763757787600944e-15)
};
T a = x * x / 4;
a = (tools::evaluate_rational(P, Q, a) + Y) * a + 1;
// Maximum Deviation Found: 5.173e-38
// Expected Error Term : 5.105e-38
// Maximum Relative Change in Control Points : 9.734e-03
// Max Error found at float128 precision = Poly : 1.688806e-34
static const T P2[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 1.159315156584124488107200313757741370e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.789828789146031122026800078439435369e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.524892993216269451266750049024628432e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.460350907082229957222453839935101823e-04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.491471929926042875260452849503857976e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.627105610481598430816014719558896866e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.208426165007797264194914898538250281e-09),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.508697838747354949164182457073784117e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.659784680639805301101014383907273109e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.531090131964391104248859415958109654e-17),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.205195117066478034260323124669936314e-19),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.692219280289030165761119775783115426e-22),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.362350161092532344171965861545860747e-25),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.277990623924628999539014980773738258e-27)
};
return tools::evaluate_polynomial(P2, T(x * x)) - log(x) * a;
}
else
{
// Maximum Deviation Found: 1.462e-34
// Expected Error Term : 4.917e-40
// Maximum Relative Change in Control Points : 3.385e-01
// Max Error found at float128 precision = Poly : 1.567573e-34
static const T Y = 1;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 2.533141373155002512078826424055226265e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.001949740768235770078339977110749204e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.991516715983883248363351472378349986e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.429587951594593159075690819360687720e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.911933815201948768044660065771258450e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.769943016204926614862175317962439875e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.170866154649560750500954150401105606e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.634687099724383996792011977705727661e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.989524036456492581597607246664394014e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.160394785715328062088529400178080360e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.778173054417826368076483100902201433e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.335667778588806892764139643950439733e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.283635100080306980206494425043706838e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.300616188213640626577036321085025855e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.277591957076162984986406540894621482e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.564360536834214058158565361486115932e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.043505161612403359098596828115690596e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.217035248223503605127967970903027314e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.422938158797326748375799596769964430e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.229125746200586805278634786674745210e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.201632288615609937883545928660649813e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.690820607338480548346746717311811406e+01)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 1.000000000000000000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.964877874035741452203497983642653107e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.808929943826193766839360018583294769e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.814524004679994110944366890912384139e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.897794522506725610540209610337355118e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.456339470955813675629523617440433672e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.057818717813969772198911392875127212e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.513821619536852436424913886081133209e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.255938846873380596038513316919990776e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.537077551699028079347581816919572141e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.176769339768120752974843214652367321e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.828722317390455845253191337207432060e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.698864296569996402006511705803675890e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.007803261356636409943826918468544629e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.016564631288740308993071395104715469e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.595893010619754750655947035567624730e+09),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.241241839120481076862742189989406856e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.168778094393076220871007550235840858e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.156200301360388147635052029404211109e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.752130382550379886741949463587008794e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.370574966987293592457152146806662562e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.871254714311063594080644835895740323e+01)
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k0_imp(const T& x, const mpl::int_<0>&)
{
if(boost::math::tools::digits<T>() <= 24)
return bessel_k0_imp(x, mpl::int_<24>());
else if(boost::math::tools::digits<T>() <= 53)
return bessel_k0_imp(x, mpl::int_<53>());
else if(boost::math::tools::digits<T>() <= 64)
return bessel_k0_imp(x, mpl::int_<64>());
else if(boost::math::tools::digits<T>() <= 113)
return bessel_k0_imp(x, mpl::int_<113>());
BOOST_ASSERT(0);
return 0;
}
template <typename T>
inline T bessel_k0(const T& x)
{
typedef mpl::int_<
((std::numeric_limits<T>::digits == 0) || (std::numeric_limits<T>::radix != 2)) ?
0 :
std::numeric_limits<T>::digits <= 24 ?
24 :
std::numeric_limits<T>::digits <= 53 ?
53 :
std::numeric_limits<T>::digits <= 64 ?
64 :
std::numeric_limits<T>::digits <= 113 ?
113 : -1
> tag_type;
bessel_k0_initializer<T, tag_type>::force_instantiate();
return bessel_k0_imp(x, tag_type());
}
}}} // namespaces
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // BOOST_MATH_BESSEL_K0_HPP

View File

@@ -0,0 +1,551 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2017 John Maddock
// Use, modification and distribution are subject to 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_BESSEL_K1_HPP
#define BOOST_MATH_BESSEL_K1_HPP
#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/assert.hpp>
// Modified Bessel function of the second kind of order zero
// minimax rational approximations on intervals, see
// Russon and Blair, Chalk River Report AECL-3461, 1969,
// as revised by Pavel Holoborodko in "Rational Approximations
// for the Modified Bessel Function of the Second Kind - K0(x)
// for Computations with Double Precision", see
// http://www.advanpix.com/2016/01/05/rational-approximations-for-the-modified-bessel-function-of-the-second-kind-k1-for-computations-with-double-precision/
//
// The actual coefficients used are our own derivation (by JM)
// since we extend to both greater and lesser precision than the
// references above. We can also improve performance WRT to
// Holoborodko without loss of precision.
namespace boost { namespace math { namespace detail{
template <typename T>
T bessel_k1(const T& x);
template <class T, class tag>
struct bessel_k1_initializer
{
struct init
{
init()
{
do_init(tag());
}
static void do_init(const mpl::int_<113>&)
{
bessel_k1(T(0.5));
bessel_k1(T(2));
bessel_k1(T(6));
}
static void do_init(const mpl::int_<64>&)
{
bessel_k1(T(0.5));
bessel_k1(T(6));
}
template <class U>
static void do_init(const U&) {}
void force_instantiate()const {}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class tag>
const typename bessel_k1_initializer<T, tag>::init bessel_k1_initializer<T, tag>::initializer;
template <typename T, int N>
inline T bessel_k1_imp(const T& x, const mpl::int_<N>&)
{
BOOST_ASSERT(0);
return 0;
}
template <typename T>
T bessel_k1_imp(const T& x, const mpl::int_<24>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found: 3.090e-12
// Expected Error Term : -3.053e-12
// Maximum Relative Change in Control Points : 4.927e-02
// Max Error found at float precision = Poly : 7.918347e-10
static const T Y = 8.695471287e-02f;
static const T P[] =
{
-3.621379531e-03f,
7.131781976e-03f,
-1.535278300e-05f
};
static const T Q[] =
{
1.000000000e+00f,
-5.173102701e-02f,
9.203530671e-04f
};
T a = x * x / 4;
a = ((tools::evaluate_rational(P, Q, a) + Y) * a * a + a / 2 + 1) * x / 2;
// Maximum Deviation Found: 3.556e-08
// Expected Error Term : -3.541e-08
// Maximum Relative Change in Control Points : 8.203e-02
static const T P2[] =
{
-3.079657469e-01f,
-8.537108913e-02f,
-4.640275408e-03f,
-1.156442414e-04f
};
return tools::evaluate_polynomial(P2, T(x * x)) * x + 1 / x + log(x) * a;
}
else
{
// Maximum Deviation Found: 3.369e-08
// Expected Error Term : -3.227e-08
// Maximum Relative Change in Control Points : 9.917e-02
// Max Error found at float precision = Poly : 6.084411e-08
static const T Y = 1.450342178f;
static const T P[] =
{
-1.970280088e-01f,
2.188747807e-02f,
7.270394756e-01f,
2.490678196e-01f
};
static const T Q[] =
{
1.000000000e+00f,
2.274292882e+00f,
9.904984851e-01f,
4.585534549e-02f
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k1_imp(const T& x, const mpl::int_<53>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found: 1.922e-17
// Expected Error Term : 1.921e-17
// Maximum Relative Change in Control Points : 5.287e-03
// Max Error found at double precision = Poly : 2.004747e-17
static const T Y = 8.69547128677368164e-02f;
static const T P[] =
{
-3.62137953440350228e-03,
7.11842087490330300e-03,
1.00302560256614306e-05,
1.77231085381040811e-06
};
static const T Q[] =
{
1.00000000000000000e+00,
-4.80414794429043831e-02,
9.85972641934416525e-04,
-8.91196859397070326e-06
};
T a = x * x / 4;
a = ((tools::evaluate_rational(P, Q, a) + Y) * a * a + a / 2 + 1) * x / 2;
// Maximum Deviation Found: 4.053e-17
// Expected Error Term : -4.053e-17
// Maximum Relative Change in Control Points : 3.103e-04
// Max Error found at double precision = Poly : 1.246698e-16
static const T P2[] =
{
-3.07965757829206184e-01,
-7.80929703673074907e-02,
-2.70619343754051620e-03,
-2.49549522229072008e-05
};
static const T Q2[] =
{
1.00000000000000000e+00,
-2.36316836412163098e-02,
2.64524577525962719e-04,
-1.49749618004162787e-06
};
return tools::evaluate_rational(P2, Q2, T(x * x)) * x + 1 / x + log(x) * a;
}
else
{
// Maximum Deviation Found: 8.883e-17
// Expected Error Term : -1.641e-17
// Maximum Relative Change in Control Points : 2.786e-01
// Max Error found at double precision = Poly : 1.258798e-16
static const T Y = 1.45034217834472656f;
static const T P[] =
{
-1.97028041029226295e-01,
-2.32408961548087617e+00,
-7.98269784507699938e+00,
-2.39968410774221632e+00,
3.28314043780858713e+01,
5.67713761158496058e+01,
3.30907788466509823e+01,
6.62582288933739787e+00,
3.08851840645286691e-01
};
static const T Q[] =
{
1.00000000000000000e+00,
1.41811409298826118e+01,
7.35979466317556420e+01,
1.77821793937080859e+02,
2.11014501598705982e+02,
1.19425262951064454e+02,
2.88448064302447607e+01,
2.27912927104139732e+00,
2.50358186953478678e-02
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_rational(P, Q, T(1 / x)) + Y) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k1_imp(const T& x, const mpl::int_<64>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found: 5.549e-23
// Expected Error Term : -5.548e-23
// Maximum Relative Change in Control Points : 2.002e-03
// Max Error found at float80 precision = Poly : 9.352785e-22
static const T Y = 8.695471286773681640625e-02f;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, -3.621379534403483072861e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.102135866103952705932e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.167545240236717601167e-05),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.537484002571894870830e-06),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.603228256820000135990e-09)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 1.000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.354457194045068370363e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.709137201220209072820e-04),
BOOST_MATH_BIG_CONSTANT(T, 64, -9.676151796359590545143e-06),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.162715192766245311659e-08)
};
T a = x * x / 4;
a = ((tools::evaluate_rational(P, Q, a) + Y) * a * a + a / 2 + 1) * x / 2;
// Maximum Deviation Found: 1.995e-23
// Expected Error Term : 1.995e-23
// Maximum Relative Change in Control Points : 8.174e-04
// Max Error found at float80 precision = Poly : 4.137325e-20
static const T P2[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, -3.079657578292062244054e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -7.963049154965966503231e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, -3.103277523735639924895e-03),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.023052834702215699504e-05),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.719459155018493821839e-07)
};
static const T Q2[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 1.000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.863917670410152669768e-02),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.699367098849735298090e-04),
BOOST_MATH_BIG_CONSTANT(T, 64, -9.309358790546076298429e-07),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.708893480271612711933e-09)
};
return tools::evaluate_rational(P2, Q2, T(x * x)) * x + 1 / x + log(x) * a;
}
else
{
// Maximum Deviation Found: 9.785e-20
// Expected Error Term : -3.302e-21
// Maximum Relative Change in Control Points : 3.432e-01
// Max Error found at float80 precision = Poly : 1.083755e-19
static const T Y = 1.450342178344726562500e+00f;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, -1.970280410292263112917e-01),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.058564803062959169322e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, -3.036658174194917777473e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, -9.576825392332820142173e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, -6.706969489248020941949e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.264572499406168221382e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.584972047303151034100e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.422082733280017909550e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.738005441471368178383e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.016938390144121276609e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.319614662598089438939e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.710715864316521856193e-02)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 64, 1.000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.298433045824439052398e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.082047745067709230037e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 9.662367854250262046592e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.504148628460454004686e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.712730364911389908905e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.108002081150068641112e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.400149940532448553143e+03),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.083303048095846226299e+02),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.748706060530351833346e+01),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.321900849331506946977e-01),
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_polynomial(P, T(1 / x)) / tools::evaluate_polynomial(Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_polynomial(P, T(1 / x)) / tools::evaluate_polynomial(Q, T(1 / x)) + Y) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k1_imp(const T& x, const mpl::int_<113>&)
{
BOOST_MATH_STD_USING
if(x <= 1)
{
// Maximum Deviation Found: 7.120e-35
// Expected Error Term : -7.119e-35
// Maximum Relative Change in Control Points : 1.207e-03
// Max Error found at float128 precision = Poly : 7.143688e-35
static const T Y = 8.695471286773681640625000000000000000e-02f;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, -3.621379534403483072916666666666595475e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.074117676930975433219826471336547627e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.631337631362776369069668419033041661e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.468935967870048731821071646104412775e-06),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.956705020559599861444492614737168261e-08),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.347140307321161346703214099534250263e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.569608494081482873946791086435679661e-13)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 1.000000000000000000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.580768910152105375615558920428350204e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.197467671701485365363068445534557369e-04),
BOOST_MATH_BIG_CONSTANT(T, 113, -6.707466533308630411966030561446666237e-06),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.846687802282250112624373388491123527e-08),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.248493131151981569517383040323900343e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.319279786372775264555728921709381080e-13)
};
T a = x * x / 4;
a = ((tools::evaluate_rational(P, Q, a) + Y) * a * a + a / 2 + 1) * x / 2;
// Maximum Deviation Found: 4.473e-37
// Expected Error Term : 4.473e-37
// Maximum Relative Change in Control Points : 8.550e-04
// Max Error found at float128 precision = Poly : 8.167701e-35
static const T P2[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, -3.079657578292062244053600156878870690e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -8.133183745732467770755578848987414875e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.548968792764174773125420229299431951e-03),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.886125468718182876076972186152445490e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.506712111733707245745396404449639865e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.632502325880313239698965376754406011e-09),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.311973065898784812266544485665624227e-12)
};
static const T Q2[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 1.000000000000000000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.311471216733781016657962995723287450e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.571876054797365417068164018709472969e-05),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.630181215268238731442496851497901293e-07),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.070176111227805048604885986867484807e-09),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.129046580769872602793220056461084761e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.294906469421390890762001971790074432e-15)
};
return tools::evaluate_rational(P2, Q2, T(x * x)) * x + 1 / x + log(x) * a;
}
else if(x < 4)
{
// Max error in interpolated form: 5.307e-37
// Max Error found at float128 precision = Poly: 7.087862e-35
static const T Y = 1.5023040771484375f;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, -2.489899398329369710528254347931380044e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, -6.819080211203854781858815596508456873e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.599915699069767382647695624952723034e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.450211910821295507926582231071300718e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.451374687870925175794150513723956533e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.405805746895098802803503988539098226e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.638808326778389656403861103277220518e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.513958744081268456191778822780865708e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.121301640926540743072258116122834804e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.080094900175649541266613109971296190e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.896531083639613332407534434915552429e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.856602122319645694042555107114028437e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.237121918853145421414003823957537419e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.842072954561323076230238664623893504e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.039705646510167437971862966128055524e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.008418100718254816100425022904039530e-02)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 1.000000000000000000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.927456835239137986889227412815459529e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.598985593265577043711382994516531273e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.449897377085510281395819892689690579e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.025555887684561913263090023158085327e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.774140447181062463181892531100679195e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.962055507843204417243602332246120418e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.908269326976180183216954452196772931e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.655160454422016855911700790722577942e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.383586885019548163464418964577684608e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.679920375586960324298491662159976419e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.478586421028842906987799049804565008e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.565384974896746094224942654383537090e+02),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.902617937084010911005732488607114511e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.429293010387921526110949911029094926e-01),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.880342607911083143560111853491047663e-04)
};
return ((tools::evaluate_polynomial(P, T(1 / x)) / tools::evaluate_polynomial(Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
}
else
{
// Maximum Deviation Found: 4.359e-37
// Expected Error Term : -6.565e-40
// Maximum Relative Change in Control Points : 1.880e-01
// Max Error found at float128 precision = Poly : 2.943572e-35
static const T Y = 1.308816909790039062500000000000000000f;
static const T P[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, -5.550277247453881129211735759447737350e-02),
BOOST_MATH_BIG_CONSTANT(T, 113, -3.485883080219574328217554864956175929e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, -8.903760658131484239300875153154881958e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.144813672213626237418235110712293337e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, -6.498400501156131446691826557494158173e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.573531831870363502604119835922166116e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.417416550054632009958262596048841154e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.271266450613557412825896604269130661e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.898386013314389952534433455681107783e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.353798784656436259250791761023512750e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.839619195427352438957774052763490067e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.169246368651532232388152442538005637e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.696368884166831199967845883371116431e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.810226630422736458064005843327500169e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.854996610560406127438950635716757614e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.981057433937398731355768088809437625e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.519440069856232098711793483639792952e+04)
};
static const T Q[] =
{
BOOST_MATH_BIG_CONSTANT(T, 113, 1.000000000000000000000000000000000000e+00),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.127348248283623146544565916604103560e+01),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.205092684176906740104488180754982065e+03),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.911249195069050636298346469740075758e+04),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.426103406579046249654548481377792614e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.365861555422488771286500241966208541e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.765377714160383676864913709252529840e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.453822726931857253365138260720815246e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.643207885048369990391975749439783892e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.882540678243694621895816336640877878e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.410120808992380266174106812005338148e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.628138016559335882019310900426773027e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.250794693811010646965360198541047961e+08),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.378723408195485594610593014072950078e+07),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.488253856312453816451380319061865560e+06),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.202167197882689873967723350537104582e+05),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.673233230356966539460728211412989843e+03)
};
if(x < tools::log_max_value<T>())
return ((tools::evaluate_polynomial(P, T(1 / x)) / tools::evaluate_polynomial(Q, T(1 / x)) + Y) * exp(-x) / sqrt(x));
else
{
T ex = exp(-x / 2);
return ((tools::evaluate_polynomial(P, T(1 / x)) / tools::evaluate_polynomial(Q, T(1 / x)) + Y) * ex / sqrt(x)) * ex;
}
}
}
template <typename T>
T bessel_k1_imp(const T& x, const mpl::int_<0>&)
{
if(boost::math::tools::digits<T>() <= 24)
return bessel_k1_imp(x, mpl::int_<24>());
else if(boost::math::tools::digits<T>() <= 53)
return bessel_k1_imp(x, mpl::int_<53>());
else if(boost::math::tools::digits<T>() <= 64)
return bessel_k1_imp(x, mpl::int_<64>());
else if(boost::math::tools::digits<T>() <= 113)
return bessel_k1_imp(x, mpl::int_<113>());
BOOST_ASSERT(0);
return 0;
}
template <typename T>
inline T bessel_k1(const T& x)
{
typedef mpl::int_<
((std::numeric_limits<T>::digits == 0) || (std::numeric_limits<T>::radix != 2)) ?
0 :
std::numeric_limits<T>::digits <= 24 ?
24 :
std::numeric_limits<T>::digits <= 53 ?
53 :
std::numeric_limits<T>::digits <= 64 ?
64 :
std::numeric_limits<T>::digits <= 113 ?
113 : -1
> tag_type;
bessel_k1_initializer<T, tag_type>::force_instantiate();
return bessel_k1_imp(x, tag_type());
}
}}} // namespaces
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // BOOST_MATH_BESSEL_K1_HPP

View File

@@ -0,0 +1,86 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_KN_HPP
#define BOOST_MATH_BESSEL_KN_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_k0.hpp>
#include <boost/math/special_functions/detail/bessel_k1.hpp>
#include <boost/math/policies/error_handling.hpp>
// Modified Bessel function of the second kind of integer order
// K_n(z) is the dominant solution, forward recurrence always OK (though unstable)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T bessel_kn(int n, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
T value, current, prev;
using namespace boost::math::tools;
static const char* function = "boost::math::bessel_kn<%1%>(%1%,%1%)";
if (x < 0)
{
return policies::raise_domain_error<T>(function,
"Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol);
}
if (x == 0)
{
return policies::raise_overflow_error<T>(function, 0, pol);
}
if (n < 0)
{
n = -n; // K_{-n}(z) = K_n(z)
}
if (n == 0)
{
value = bessel_k0(x);
}
else if (n == 1)
{
value = bessel_k1(x);
}
else
{
prev = bessel_k0(x);
current = bessel_k1(x);
int k = 1;
BOOST_ASSERT(k < n);
T scale = 1;
do
{
T fact = 2 * k / x;
if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
{
scale /= current;
prev /= current;
current = 1;
}
value = fact * current + prev;
prev = current;
current = value;
++k;
}
while(k < n);
if(tools::max_value<T>() * scale < fabs(value))
return sign(scale) * sign(value) * policies::raise_overflow_error<T>(function, 0, pol);
value /= scale;
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_KN_HPP

View File

@@ -0,0 +1,230 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_Y0_HPP
#define BOOST_MATH_BESSEL_Y0_HPP
#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#endif
#include <boost/math/special_functions/detail/bessel_j0.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/assert.hpp>
// Bessel function of the second kind of order zero
// x <= 8, minimax rational approximations on root-bracketing intervals
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T bessel_y0(T x, const Policy&);
template <class T, class Policy>
struct bessel_y0_initializer
{
struct init
{
init()
{
do_init();
}
static void do_init()
{
bessel_y0(T(1), Policy());
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename bessel_y0_initializer<T, Policy>::init bessel_y0_initializer<T, Policy>::initializer;
template <typename T, typename Policy>
T bessel_y0(T x, const Policy& pol)
{
bessel_y0_initializer<T, Policy>::force_instantiate();
static const T P1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0723538782003176831e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.3716255451260504098e+09)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.0422274357376619816e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.1287548474401797963e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0102532948020907590e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.8402381979244993524e+01)),
};
static const T Q1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.8873865738997033405e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.1617187777290363573e+09)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.5662956624278251596e+07)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.3889393209447253406e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.6475986689240190091e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T P2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2213976967566192242e+13)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.5107435206722644429e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.3600098638603061642e+10)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.9590439394619619534e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.6905288611678631510e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4566865832663635920e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7427031242901594547e+01)),
};
static const T Q2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.3386146580707264428e+14)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.4266824419412347550e+12)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.4015103849971240096e+10)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3960202770986831075e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.0669982352539552018e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.3030857612070288823e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T P3[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.0728726905150210443e+15)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.7016641869173237784e+14)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.2829912364088687306e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.9363051266772083678e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1958827170518100757e+09)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0085539923498211426e+07)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1363534169313901632e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.7439661319197499338e+01)),
};
static const T Q3[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.4563724628846457519e+17)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.9272425569640309819e+15)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.2598377924042897629e+13)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.6926121104209825246e+10)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.4727219475672302327e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.3924739209768057030e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.7903362168128450017e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T PC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.2779090197304684302e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.1345386639580765797e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1170523380864944322e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.4806486443249270347e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.5376201909008354296e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.8961548424210455236e-01)),
};
static const T QC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.2779090197304684318e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.1370412495510416640e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1215350561880115730e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.5028735138235608207e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.5711159858080893649e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T PS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.9226600200800094098e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.8591953644342993800e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.1183429920482737611e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2300261666214198472e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.2441026745835638459e+00)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.8033303048680751817e-03)),
};
static const T QS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.7105024128512061905e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1951131543434613647e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.2642780169211018836e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.4887231232283756582e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.0593769594993125859e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T x1 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.9357696627916752158e-01)),
x2 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.9576784193148578684e+00)),
x3 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.0860510603017726976e+00)),
x11 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.280e+02)),
x12 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.9519662791675215849e-03)),
x21 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0130e+03)),
x22 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.4716931485786837568e-04)),
x31 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8140e+03)),
x32 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1356030177269762362e-04))
;
T value, factor, r, rc, rs;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
static const char* function = "boost::math::bessel_y0<%1%>(%1%,%1%)";
if (x < 0)
{
return policies::raise_domain_error<T>(function,
"Got x = %1% but x must be non-negative, complex result not supported.", x, pol);
}
if (x == 0)
{
return -policies::raise_overflow_error<T>(function, 0, pol);
}
if (x <= 3) // x in (0, 3]
{
T y = x * x;
T z = 2 * log(x/x1) * bessel_j0(x) / pi<T>();
r = evaluate_rational(P1, Q1, y);
factor = (x + x1) * ((x - x11/256) - x12);
value = z + factor * r;
}
else if (x <= 5.5f) // x in (3, 5.5]
{
T y = x * x;
T z = 2 * log(x/x2) * bessel_j0(x) / pi<T>();
r = evaluate_rational(P2, Q2, y);
factor = (x + x2) * ((x - x21/256) - x22);
value = z + factor * r;
}
else if (x <= 8) // x in (5.5, 8]
{
T y = x * x;
T z = 2 * log(x/x3) * bessel_j0(x) / pi<T>();
r = evaluate_rational(P3, Q3, y);
factor = (x + x3) * ((x - x31/256) - x32);
value = z + factor * r;
}
else // x in (8, \infty)
{
T y = 8 / x;
T y2 = y * y;
rc = evaluate_rational(PC, QC, y2);
rs = evaluate_rational(PS, QS, y2);
factor = constants::one_div_root_pi<T>() / sqrt(x);
//
// The following code is really just:
//
// T z = x - 0.25f * pi<T>();
// value = factor * (rc * sin(z) + y * rs * cos(z));
//
// But using the sin/cos addition formulae and constant values for
// sin/cos of PI/4 which then cancel part of the "factor" term as they're all
// 1 / sqrt(2):
//
T sx = sin(x);
T cx = cos(x);
value = factor * (rc * (sx - cx) + y * rs * (cx + sx));
}
return value;
}
}}} // namespaces
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // BOOST_MATH_BESSEL_Y0_HPP

View File

@@ -0,0 +1,202 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_Y1_HPP
#define BOOST_MATH_BESSEL_Y1_HPP
#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#endif
#include <boost/math/special_functions/detail/bessel_j1.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/big_constant.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/assert.hpp>
// Bessel function of the second kind of order one
// x <= 8, minimax rational approximations on root-bracketing intervals
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T bessel_y1(T x, const Policy&);
template <class T, class Policy>
struct bessel_y1_initializer
{
struct init
{
init()
{
do_init();
}
static void do_init()
{
bessel_y1(T(1), Policy());
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename bessel_y1_initializer<T, Policy>::init bessel_y1_initializer<T, Policy>::initializer;
template <typename T, typename Policy>
T bessel_y1(T x, const Policy& pol)
{
bessel_y1_initializer<T, Policy>::force_instantiate();
static const T P1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.0535726612579544093e+13)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.4708611716525426053e+12)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.7595974497819597599e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.2144548214502560419e+09)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.9157479997408395984e+07)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.2157953222280260820e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.1714424660046133456e+02)),
};
static const T Q1[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.0737873921079286084e+14)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.1272286200406461981e+12)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.7800352738690585613e+10)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.2250435122182963220e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.8136470753052572164e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.2079908168393867438e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T P2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1514276357909013326e+19)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.6808094574724204577e+18)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.3638408497043134724e+16)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.0686275289804744814e+15)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.9530713129741981618e+13)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.7453673962438488783e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.1957961912070617006e+09)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.9153806858264202986e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.2337180442012953128e+03)),
};
static const T Q2[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.3321844313316185697e+20)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.6968198822857178911e+18)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.0837179548112881950e+16)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1187010065856971027e+14)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.0221766852960403645e+11)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.3550318087088919566e+08)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0453748201934079734e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.2855164849321609336e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T PC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.4357578167941278571e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -9.9422465050776411957e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.6033732483649391093e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.5235293511811373833e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0982405543459346727e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.6116166443246101165e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.0)),
};
static const T QC[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.4357578167941278568e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -9.9341243899345856590e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.5853394797230870728e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.5118095066341608816e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0726385991103820119e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4550094401904961825e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T PS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.3220913409857223519e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.5145160675335701966e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.6178836581270835179e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8494262873223866797e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7063754290207680021e+03)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.5265133846636032186e+01)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.0)),
};
static const T QS[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.0871281941028743574e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8194580422439972989e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.4194606696037208929e+06)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.0029443582266975117e+05)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.7890229745772202641e+04)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.6383677696049909675e+02)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
};
static const T x1 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1971413260310170351e+00)),
x2 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.4296810407941351328e+00)),
x11 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.620e+02)),
x12 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8288260310170351490e-03)),
x21 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3900e+03)),
x22 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.4592058648672279948e-06))
;
T value, factor, r, rc, rs;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
if (x <= 0)
{
return policies::raise_domain_error<T>("bost::math::bessel_y1<%1%>(%1%,%1%)",
"Got x == %1%, but x must be > 0, complex result not supported.", x, pol);
}
if (x <= 4) // x in (0, 4]
{
T y = x * x;
T z = 2 * log(x/x1) * bessel_j1(x) / pi<T>();
r = evaluate_rational(P1, Q1, y);
factor = (x + x1) * ((x - x11/256) - x12) / x;
value = z + factor * r;
}
else if (x <= 8) // x in (4, 8]
{
T y = x * x;
T z = 2 * log(x/x2) * bessel_j1(x) / pi<T>();
r = evaluate_rational(P2, Q2, y);
factor = (x + x2) * ((x - x21/256) - x22) / x;
value = z + factor * r;
}
else // x in (8, \infty)
{
T y = 8 / x;
T y2 = y * y;
rc = evaluate_rational(PC, QC, y2);
rs = evaluate_rational(PS, QS, y2);
factor = 1 / (sqrt(x) * root_pi<T>());
//
// This code is really just:
//
// T z = x - 0.75f * pi<T>();
// value = factor * (rc * sin(z) + y * rs * cos(z));
//
// But using the sin/cos addition rules, plus constants for sin/cos of 3PI/4
// which then cancel out with corresponding terms in "factor".
//
T sx = sin(x);
T cx = cos(x);
value = factor * (y * rs * (sx - cx) - rc * (sx + cx));
}
return value;
}
}}} // namespaces
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // BOOST_MATH_BESSEL_Y1_HPP

View File

@@ -0,0 +1,112 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to 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_BESSEL_YN_HPP
#define BOOST_MATH_BESSEL_YN_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_y0.hpp>
#include <boost/math/special_functions/detail/bessel_y1.hpp>
#include <boost/math/special_functions/detail/bessel_jy_series.hpp>
#include <boost/math/policies/error_handling.hpp>
// Bessel function of the second kind of integer order
// Y_n(z) is the dominant solution, forward recurrence always OK (though unstable)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T bessel_yn(int n, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
T value, factor, current, prev;
using namespace boost::math::tools;
static const char* function = "boost::math::bessel_yn<%1%>(%1%,%1%)";
if ((x == 0) && (n == 0))
{
return -policies::raise_overflow_error<T>(function, 0, pol);
}
if (x <= 0)
{
return policies::raise_domain_error<T>(function,
"Got x = %1%, but x must be > 0, complex result not supported.", x, pol);
}
//
// Reflection comes first:
//
if (n < 0)
{
factor = static_cast<T>((n & 0x1) ? -1 : 1); // Y_{-n}(z) = (-1)^n Y_n(z)
n = -n;
}
else
{
factor = 1;
}
if(x < policies::get_epsilon<T, Policy>())
{
T scale = 1;
value = bessel_yn_small_z(n, x, &scale, pol);
if(tools::max_value<T>() * fabs(scale) < fabs(value))
return boost::math::sign(scale) * boost::math::sign(value) * policies::raise_overflow_error<T>(function, 0, pol);
value /= scale;
}
else if(asymptotic_bessel_large_x_limit(n, x))
{
value = factor * asymptotic_bessel_y_large_x_2(static_cast<T>(abs(n)), x);
}
else if (n == 0)
{
value = bessel_y0(x, pol);
}
else if (n == 1)
{
value = factor * bessel_y1(x, pol);
}
else
{
prev = bessel_y0(x, pol);
current = bessel_y1(x, pol);
int k = 1;
BOOST_ASSERT(k < n);
policies::check_series_iterations<T>("boost::math::bessel_y_n<%1%>(%1%,%1%)", n, pol);
T mult = 2 * k / x;
value = mult * current - prev;
prev = current;
current = value;
++k;
if((mult > 1) && (fabs(current) > 1))
{
prev /= current;
factor /= current;
value /= current;
current = 1;
}
while(k < n)
{
mult = 2 * k / x;
value = mult * current - prev;
prev = current;
current = value;
++k;
}
if(fabs(tools::max_value<T>() * factor) < fabs(value))
return sign(value) * sign(factor) * policies::raise_overflow_error<T>(function, 0, pol);
value /= factor;
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_YN_HPP

View File

@@ -0,0 +1,549 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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_SF_ERF_INV_HPP
#define BOOST_MATH_SF_ERF_INV_HPP
#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4127) // Conditional expression is constant
#pragma warning(disable:4702) // Unreachable code: optimization warning
#endif
namespace boost{ namespace math{
namespace detail{
//
// The inverse erf and erfc functions share a common implementation,
// this version is for 80-bit long double's and smaller:
//
template <class T, class Policy>
T erf_inv_imp(const T& p, const T& q, const Policy&, const boost::mpl::int_<64>*)
{
BOOST_MATH_STD_USING // for ADL of std names.
T result = 0;
if(p <= 0.5)
{
//
// Evaluate inverse erf using the rational approximation:
//
// x = p(p+10)(Y+R(p))
//
// Where Y is a constant, and R(p) is optimised for a low
// absolute error compared to |Y|.
//
// double: Max error found: 2.001849e-18
// long double: Max error found: 1.017064e-20
// Maximum Deviation Found (actual error term at infinite precision) 8.030e-21
//
static const float Y = 0.0891314744949340820313f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000508781949658280665617),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00836874819741736770379),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0334806625409744615033),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0126926147662974029034),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0365637971411762664006),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0219878681111168899165),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00822687874676915743155),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00538772965071242932965)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.970005043303290640362),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.56574558234175846809),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.56221558398423026363),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.662328840472002992063),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.71228902341542847553),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0527396382340099713954),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0795283687341571680018),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00233393759374190016776),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000886216390456424707504)
};
T g = p * (p + 10);
T r = tools::evaluate_polynomial(P, p) / tools::evaluate_polynomial(Q, p);
result = g * Y + g * r;
}
else if(q >= 0.25)
{
//
// Rational approximation for 0.5 > q >= 0.25
//
// x = sqrt(-2*log(q)) / (Y + R(q))
//
// Where Y is a constant, and R(q) is optimised for a low
// absolute error compared to Y.
//
// double : Max error found: 7.403372e-17
// long double : Max error found: 6.084616e-20
// Maximum Deviation Found (error term) 4.811e-20
//
static const float Y = 2.249481201171875f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.202433508355938759655),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.105264680699391713268),
BOOST_MATH_BIG_CONSTANT(T, 64, 8.37050328343119927838),
BOOST_MATH_BIG_CONSTANT(T, 64, 17.6447298408374015486),
BOOST_MATH_BIG_CONSTANT(T, 64, -18.8510648058714251895),
BOOST_MATH_BIG_CONSTANT(T, 64, -44.6382324441786960818),
BOOST_MATH_BIG_CONSTANT(T, 64, 17.445385985570866523),
BOOST_MATH_BIG_CONSTANT(T, 64, 21.1294655448340526258),
BOOST_MATH_BIG_CONSTANT(T, 64, -3.67192254707729348546)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.24264124854247537712),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.9713437953343869095),
BOOST_MATH_BIG_CONSTANT(T, 64, -28.6608180499800029974),
BOOST_MATH_BIG_CONSTANT(T, 64, -20.1432634680485188801),
BOOST_MATH_BIG_CONSTANT(T, 64, 48.5609213108739935468),
BOOST_MATH_BIG_CONSTANT(T, 64, 10.8268667355460159008),
BOOST_MATH_BIG_CONSTANT(T, 64, -22.6436933413139721736),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.72114765761200282724)
};
T g = sqrt(-2 * log(q));
T xs = q - 0.25f;
T r = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
result = g / (Y + r);
}
else
{
//
// For q < 0.25 we have a series of rational approximations all
// of the general form:
//
// let: x = sqrt(-log(q))
//
// Then the result is given by:
//
// x(Y+R(x-B))
//
// where Y is a constant, B is the lowest value of x for which
// the approximation is valid, and R(x-B) is optimised for a low
// absolute error compared to Y.
//
// Note that almost all code will really go through the first
// or maybe second approximation. After than we're dealing with very
// small input values indeed: 80 and 128 bit long double's go all the
// way down to ~ 1e-5000 so the "tail" is rather long...
//
T x = sqrt(-log(q));
if(x < 3)
{
// Max error found: 1.089051e-20
static const float Y = 0.807220458984375f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.131102781679951906451),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.163794047193317060787),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.117030156341995252019),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.387079738972604337464),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.337785538912035898924),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.142869534408157156766),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0290157910005329060432),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00214558995388805277169),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.679465575181126350155e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.285225331782217055858e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.681149956853776992068e-9)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.46625407242567245975),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.38168345707006855425),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.77846592945843778382),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.59301921623620271374),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.848854343457902036425),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.152264338295331783612),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.01105924229346489121)
};
T xs = x - 1.125f;
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
result = Y * x + R * x;
}
else if(x < 6)
{
// Max error found: 8.389174e-21
static const float Y = 0.93995571136474609375f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0350353787183177984712),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00222426529213447927281),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0185573306514231072324),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00950804701325919603619),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00187123492819559223345),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000157544617424960554631),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.460469890584317994083e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.230404776911882601748e-9),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.266339227425782031962e-11)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.3653349817554063097),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.762059164553623404043),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.220091105764131249824),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0341589143670947727934),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00263861676657015992959),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.764675292302794483503e-4)
};
T xs = x - 3;
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
result = Y * x + R * x;
}
else if(x < 18)
{
// Max error found: 1.481312e-19
static const float Y = 0.98362827301025390625f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0167431005076633737133),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00112951438745580278863),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00105628862152492910091),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000209386317487588078668),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.149624783758342370182e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.449696789927706453732e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.462596163522878599135e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.281128735628831791805e-13),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.99055709973310326855e-16)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.591429344886417493481),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.138151865749083321638),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0160746087093676504695),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000964011807005165528527),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.275335474764726041141e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.282243172016108031869e-6)
};
T xs = x - 6;
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
result = Y * x + R * x;
}
else if(x < 44)
{
// Max error found: 5.697761e-20
static const float Y = 0.99714565277099609375f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0024978212791898131227),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.779190719229053954292e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.254723037413027451751e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.162397777342510920873e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.396341011304801168516e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.411632831190944208473e-9),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.145596286718675035587e-11),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.116765012397184275695e-17)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.207123112214422517181),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0169410838120975906478),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000690538265622684595676),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.145007359818232637924e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.144437756628144157666e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.509761276599778486139e-9)
};
T xs = x - 18;
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
result = Y * x + R * x;
}
else
{
// Max error found: 1.279746e-20
static const float Y = 0.99941349029541015625f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000539042911019078575891),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.28398759004727721098e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.899465114892291446442e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.229345859265920864296e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.225561444863500149219e-9),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.947846627503022684216e-12),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.135880130108924861008e-14),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.348890393399948882918e-21)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0845746234001899436914),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00282092984726264681981),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.468292921940894236786e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.399968812193862100054e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.161809290887904476097e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.231558608310259605225e-11)
};
T xs = x - 44;
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
result = Y * x + R * x;
}
}
return result;
}
template <class T, class Policy>
struct erf_roots
{
boost::math::tuple<T,T,T> operator()(const T& guess)
{
BOOST_MATH_STD_USING
T derivative = sign * (2 / sqrt(constants::pi<T>())) * exp(-(guess * guess));
T derivative2 = -2 * guess * derivative;
return boost::math::make_tuple(((sign > 0) ? static_cast<T>(boost::math::erf(guess, Policy()) - target) : static_cast<T>(boost::math::erfc(guess, Policy())) - target), derivative, derivative2);
}
erf_roots(T z, int s) : target(z), sign(s) {}
private:
T target;
int sign;
};
template <class T, class Policy>
T erf_inv_imp(const T& p, const T& q, const Policy& pol, const boost::mpl::int_<0>*)
{
//
// Generic version, get a guess that's accurate to 64-bits (10^-19)
//
T guess = erf_inv_imp(p, q, pol, static_cast<mpl::int_<64> const*>(0));
T result;
//
// If T has more bit's than 64 in it's mantissa then we need to iterate,
// otherwise we can just return the result:
//
if(policies::digits<T, Policy>() > 64)
{
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
if(p <= 0.5)
{
result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(p, 1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3, max_iter);
}
else
{
result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(q, -1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3, max_iter);
}
policies::check_root_iterations<T>("boost::math::erf_inv<%1%>", max_iter, pol);
}
else
{
result = guess;
}
return result;
}
template <class T, class Policy>
struct erf_inv_initializer
{
struct init
{
init()
{
do_init();
}
static bool is_value_non_zero(T);
static void do_init()
{
// If std::numeric_limits<T>::digits is zero, we must not call
// our inituialization code here as the precision presumably
// varies at runtime, and will not have been set yet.
if(std::numeric_limits<T>::digits)
{
boost::math::erf_inv(static_cast<T>(0.25), Policy());
boost::math::erf_inv(static_cast<T>(0.55), Policy());
boost::math::erf_inv(static_cast<T>(0.95), Policy());
boost::math::erfc_inv(static_cast<T>(1e-15), Policy());
// These following initializations must not be called if
// type T can not hold the relevant values without
// underflow to zero. We check this at runtime because
// some tools such as valgrind silently change the precision
// of T at runtime, and numeric_limits basically lies!
if(is_value_non_zero(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-130))))
boost::math::erfc_inv(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-130)), Policy());
// Some compilers choke on constants that would underflow, even in code that isn't instantiated
// so try and filter these cases out in the preprocessor:
#if LDBL_MAX_10_EXP >= 800
if(is_value_non_zero(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-800))))
boost::math::erfc_inv(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-800)), Policy());
if(is_value_non_zero(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-900))))
boost::math::erfc_inv(static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1e-900)), Policy());
#else
if(is_value_non_zero(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-800))))
boost::math::erfc_inv(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-800)), Policy());
if(is_value_non_zero(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-900))))
boost::math::erfc_inv(static_cast<T>(BOOST_MATH_HUGE_CONSTANT(T, 64, 1e-900)), Policy());
#endif
}
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename erf_inv_initializer<T, Policy>::init erf_inv_initializer<T, Policy>::initializer;
template <class T, class Policy>
bool erf_inv_initializer<T, Policy>::init::is_value_non_zero(T v)
{
// This needs to be non-inline to detect whether v is non zero at runtime
// rather than at compile time, only relevant when running under valgrind
// which changes long double's to double's on the fly.
return v != 0;
}
} // namespace detail
template <class T, class Policy>
typename tools::promote_args<T>::type erfc_inv(T z, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
//
// Begin by testing for domain errors, and other special cases:
//
static const char* function = "boost::math::erfc_inv<%1%>(%1%, %1%)";
if((z < 0) || (z > 2))
return policies::raise_domain_error<result_type>(function, "Argument outside range [0,2] in inverse erfc function (got p=%1%).", z, pol);
if(z == 0)
return policies::raise_overflow_error<result_type>(function, 0, pol);
if(z == 2)
return -policies::raise_overflow_error<result_type>(function, 0, pol);
//
// Normalise the input, so it's in the range [0,1], we will
// negate the result if z is outside that range. This is a simple
// application of the erfc reflection formula: erfc(-z) = 2 - erfc(z)
//
result_type p, q, s;
if(z > 1)
{
q = 2 - z;
p = 1 - q;
s = -1;
}
else
{
p = 1 - z;
q = z;
s = 1;
}
//
// A bit of meta-programming to figure out which implementation
// to use, based on the number of bits in the mantissa of T:
//
typedef typename policies::precision<result_type, Policy>::type precision_type;
typedef typename mpl::if_<
mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >,
mpl::int_<0>,
mpl::int_<64>
>::type tag_type;
//
// Likewise use internal promotion, so we evaluate at a higher
// precision internally if it's appropriate:
//
typedef typename policies::evaluation<result_type, Policy>::type eval_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
detail::erf_inv_initializer<eval_type, forwarding_policy>::force_instantiate();
//
// And get the result, negating where required:
//
return s * policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function);
}
template <class T, class Policy>
typename tools::promote_args<T>::type erf_inv(T z, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
//
// Begin by testing for domain errors, and other special cases:
//
static const char* function = "boost::math::erf_inv<%1%>(%1%, %1%)";
if((z < -1) || (z > 1))
return policies::raise_domain_error<result_type>(function, "Argument outside range [-1, 1] in inverse erf function (got p=%1%).", z, pol);
if(z == 1)
return policies::raise_overflow_error<result_type>(function, 0, pol);
if(z == -1)
return -policies::raise_overflow_error<result_type>(function, 0, pol);
if(z == 0)
return 0;
//
// Normalise the input, so it's in the range [0,1], we will
// negate the result if z is outside that range. This is a simple
// application of the erf reflection formula: erf(-z) = -erf(z)
//
result_type p, q, s;
if(z < 0)
{
p = -z;
q = 1 - p;
s = -1;
}
else
{
p = z;
q = 1 - z;
s = 1;
}
//
// A bit of meta-programming to figure out which implementation
// to use, based on the number of bits in the mantissa of T:
//
typedef typename policies::precision<result_type, Policy>::type precision_type;
typedef typename mpl::if_<
mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >,
mpl::int_<0>,
mpl::int_<64>
>::type tag_type;
//
// Likewise use internal promotion, so we evaluate at a higher
// precision internally if it's appropriate:
//
typedef typename policies::evaluation<result_type, Policy>::type eval_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
//
// Likewise use internal promotion, so we evaluate at a higher
// precision internally if it's appropriate:
//
typedef typename policies::evaluation<result_type, Policy>::type eval_type;
detail::erf_inv_initializer<eval_type, forwarding_policy>::force_instantiate();
//
// And get the result, negating where required:
//
return s * policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function);
}
template <class T>
inline typename tools::promote_args<T>::type erfc_inv(T z)
{
return erfc_inv(z, policies::policy<>());
}
template <class T>
inline typename tools::promote_args<T>::type erf_inv(T z)
{
return erf_inv(z, policies::policy<>());
}
} // namespace math
} // namespace boost
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // BOOST_MATH_SF_ERF_INV_HPP

View File

@@ -0,0 +1,581 @@
// fp_traits.hpp
#ifndef BOOST_MATH_FP_TRAITS_HPP
#define BOOST_MATH_FP_TRAITS_HPP
// Copyright (c) 2006 Johan Rade
// 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)
/*
To support old compilers, care has been taken to avoid partial template
specialization and meta function forwarding.
With these techniques, the code could be simplified.
*/
#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
// The VAX floating point formats are used (for float and double)
# define BOOST_FPCLASSIFY_VAX_FORMAT
#endif
#include <cstring>
#include <boost/assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/predef/other/endian.h>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::memcpy; }
#endif
#ifndef FP_NORMAL
#define FP_ZERO 0
#define FP_NORMAL 1
#define FP_INFINITE 2
#define FP_NAN 3
#define FP_SUBNORMAL 4
#else
#define BOOST_HAS_FPCLASSIFY
#ifndef fpclassify
# if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \
&& defined(_GLIBCXX_USE_C99_MATH) \
&& !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \
&& (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))
# ifdef _STLP_VENDOR_CSTD
# if _STLPORT_VERSION >= 0x520
# define BOOST_FPCLASSIFY_PREFIX ::__std_alias::
# else
# define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD::
# endif
# else
# define BOOST_FPCLASSIFY_PREFIX ::std::
# endif
# else
# undef BOOST_HAS_FPCLASSIFY
# define BOOST_FPCLASSIFY_PREFIX
# endif
#elif (defined(__HP_aCC) && !defined(__hppa))
// aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit!
# define BOOST_FPCLASSIFY_PREFIX ::
#else
# define BOOST_FPCLASSIFY_PREFIX
#endif
#ifdef __MINGW32__
# undef BOOST_HAS_FPCLASSIFY
#endif
#endif
//------------------------------------------------------------------------------
namespace boost {
namespace math {
namespace detail {
//------------------------------------------------------------------------------
/*
The following classes are used to tag the different methods that are used
for floating point classification
*/
struct native_tag {};
template <bool has_limits>
struct generic_tag {};
struct ieee_tag {};
struct ieee_copy_all_bits_tag : public ieee_tag {};
struct ieee_copy_leading_bits_tag : public ieee_tag {};
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
//
// These helper functions are used only when numeric_limits<>
// members are not compile time constants:
//
inline bool is_generic_tag_false(const generic_tag<false>*)
{
return true;
}
inline bool is_generic_tag_false(const void*)
{
return false;
}
#endif
//------------------------------------------------------------------------------
/*
Most processors support three different floating point precisions:
single precision (32 bits), double precision (64 bits)
and extended double precision (80 - 128 bits, depending on the processor)
Note that the C++ type long double can be implemented
both as double precision and extended double precision.
*/
struct unknown_precision{};
struct single_precision {};
struct double_precision {};
struct extended_double_precision {};
// native_tag version --------------------------------------------------------------
template<class T> struct fp_traits_native
{
typedef native_tag method;
};
// generic_tag version -------------------------------------------------------------
template<class T, class U> struct fp_traits_non_native
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
typedef generic_tag<std::numeric_limits<T>::is_specialized> method;
#else
typedef generic_tag<false> method;
#endif
};
// ieee_tag versions ---------------------------------------------------------------
/*
These specializations of fp_traits_non_native contain information needed
to "parse" the binary representation of a floating point number.
Typedef members:
bits -- the target type when copying the leading bytes of a floating
point number. It is a typedef for uint32_t or uint64_t.
method -- tells us whether all bytes are copied or not.
It is a typedef for ieee_copy_all_bits_tag or ieee_copy_leading_bits_tag.
Static data members:
sign, exponent, flag, significand -- bit masks that give the meaning of the
bits in the leading bytes.
Static function members:
get_bits(), set_bits() -- provide access to the leading bytes.
*/
// ieee_tag version, float (32 bits) -----------------------------------------------
#ifndef BOOST_FPCLASSIFY_VAX_FORMAT
template<> struct fp_traits_non_native<float, single_precision>
{
typedef ieee_copy_all_bits_tag method;
BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7f800000);
BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
BOOST_STATIC_CONSTANT(uint32_t, significand = 0x007fffff);
typedef uint32_t bits;
static void get_bits(float x, uint32_t& a) { std::memcpy(&a, &x, 4); }
static void set_bits(float& x, uint32_t a) { std::memcpy(&x, &a, 4); }
};
// ieee_tag version, double (64 bits) ----------------------------------------------
#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION) \
|| defined(__BORLANDC__) || defined(__CODEGEAR__)
template<> struct fp_traits_non_native<double, double_precision>
{
typedef ieee_copy_leading_bits_tag method;
BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
typedef uint32_t bits;
static void get_bits(double x, uint32_t& a)
{
std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
}
static void set_bits(double& x, uint32_t a)
{
std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
}
private:
#if BOOST_ENDIAN_BIG_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif BOOST_ENDIAN_LITTLE_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 4);
#else
BOOST_STATIC_ASSERT(false);
#endif
};
//..............................................................................
#else
template<> struct fp_traits_non_native<double, double_precision>
{
typedef ieee_copy_all_bits_tag method;
static const uint64_t sign = ((uint64_t)0x80000000u) << 32;
static const uint64_t exponent = ((uint64_t)0x7ff00000) << 32;
static const uint64_t flag = 0;
static const uint64_t significand
= (((uint64_t)0x000fffff) << 32) + ((uint64_t)0xffffffffu);
typedef uint64_t bits;
static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
};
#endif
#endif // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT
// long double (64 bits) -------------------------------------------------------
#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\
|| defined(__BORLANDC__) || defined(__CODEGEAR__)
template<> struct fp_traits_non_native<long double, double_precision>
{
typedef ieee_copy_leading_bits_tag method;
BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
typedef uint32_t bits;
static void get_bits(long double x, uint32_t& a)
{
std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
}
static void set_bits(long double& x, uint32_t a)
{
std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
}
private:
#if BOOST_ENDIAN_BIG_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif BOOST_ENDIAN_LITTLE_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 4);
#else
BOOST_STATIC_ASSERT(false);
#endif
};
//..............................................................................
#else
template<> struct fp_traits_non_native<long double, double_precision>
{
typedef ieee_copy_all_bits_tag method;
static const uint64_t sign = (uint64_t)0x80000000u << 32;
static const uint64_t exponent = (uint64_t)0x7ff00000 << 32;
static const uint64_t flag = 0;
static const uint64_t significand
= ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffffu;
typedef uint64_t bits;
static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
};
#endif
// long double (>64 bits), x86 and x64 -----------------------------------------
#if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
|| defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \
|| defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
// Intel extended double precision format (80 bits)
template<>
struct fp_traits_non_native<long double, extended_double_precision>
{
typedef ieee_copy_leading_bits_tag method;
BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
typedef uint32_t bits;
static void get_bits(long double x, uint32_t& a)
{
std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);
}
static void set_bits(long double& x, uint32_t a)
{
std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);
}
};
// long double (>64 bits), Itanium ---------------------------------------------
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
// The floating point format is unknown at compile time
// No template specialization is provided.
// The generic_tag definition is used.
// The Itanium supports both
// the Intel extended double precision format (80 bits) and
// the IEEE extended double precision format with 15 exponent bits (128 bits).
#elif defined(__GNUC__) && (LDBL_MANT_DIG == 106)
//
// Define nothing here and fall though to generic_tag:
// We have GCC's "double double" in effect, and any attempt
// to handle it via bit-fiddling is pretty much doomed to fail...
//
// long double (>64 bits), PowerPC ---------------------------------------------
#elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
|| defined(__ppc) || defined(__ppc__) || defined(__PPC__)
// PowerPC extended double precision format (128 bits)
template<>
struct fp_traits_non_native<long double, extended_double_precision>
{
typedef ieee_copy_leading_bits_tag method;
BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
typedef uint32_t bits;
static void get_bits(long double x, uint32_t& a)
{
std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
}
static void set_bits(long double& x, uint32_t a)
{
std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
}
private:
#if BOOST_ENDIAN_BIG_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif BOOST_ENDIAN_LITTLE_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 12);
#else
BOOST_STATIC_ASSERT(false);
#endif
};
// long double (>64 bits), Motorola 68K ----------------------------------------
#elif defined(__m68k) || defined(__m68k__) \
|| defined(__mc68000) || defined(__mc68000__) \
// Motorola extended double precision format (96 bits)
// It is the same format as the Intel extended double precision format,
// except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
// 3) the flag bit is not set for infinity
template<>
struct fp_traits_non_native<long double, extended_double_precision>
{
typedef ieee_copy_leading_bits_tag method;
BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
// copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
typedef uint32_t bits;
static void get_bits(long double x, uint32_t& a)
{
std::memcpy(&a, &x, 2);
std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
reinterpret_cast<const unsigned char*>(&x) + 4, 2);
}
static void set_bits(long double& x, uint32_t a)
{
std::memcpy(&x, &a, 2);
std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
reinterpret_cast<const unsigned char*>(&a) + 2, 2);
}
};
// long double (>64 bits), All other processors --------------------------------
#else
// IEEE extended double precision format with 15 exponent bits (128 bits)
template<>
struct fp_traits_non_native<long double, extended_double_precision>
{
typedef ieee_copy_leading_bits_tag method;
BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
BOOST_STATIC_CONSTANT(uint32_t, significand = 0x0000ffff);
typedef uint32_t bits;
static void get_bits(long double x, uint32_t& a)
{
std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
}
static void set_bits(long double& x, uint32_t a)
{
std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
}
private:
#if BOOST_ENDIAN_BIG_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif BOOST_ENDIAN_LITTLE_BYTE
BOOST_STATIC_CONSTANT(int, offset_ = 12);
#else
BOOST_STATIC_ASSERT(false);
#endif
};
#endif
//------------------------------------------------------------------------------
// size_to_precision is a type switch for converting a C++ floating point type
// to the corresponding precision type.
template<int n, bool fp> struct size_to_precision
{
typedef unknown_precision type;
};
template<> struct size_to_precision<4, true>
{
typedef single_precision type;
};
template<> struct size_to_precision<8, true>
{
typedef double_precision type;
};
template<> struct size_to_precision<10, true>
{
typedef extended_double_precision type;
};
template<> struct size_to_precision<12, true>
{
typedef extended_double_precision type;
};
template<> struct size_to_precision<16, true>
{
typedef extended_double_precision type;
};
//------------------------------------------------------------------------------
//
// Figure out whether to use native classification functions based on
// whether T is a built in floating point type or not:
//
template <class T>
struct select_native
{
typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
typedef fp_traits_non_native<T, precision> type;
};
template<>
struct select_native<float>
{
typedef fp_traits_native<float> type;
};
template<>
struct select_native<double>
{
typedef fp_traits_native<double> type;
};
template<>
struct select_native<long double>
{
typedef fp_traits_native<long double> type;
};
//------------------------------------------------------------------------------
// fp_traits is a type switch that selects the right fp_traits_non_native
#if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \
&& !defined(__hpux) \
&& !defined(__DECCXX)\
&& !defined(__osf__) \
&& !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\
&& !defined(__FAST_MATH__)\
&& !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)\
&& !defined(BOOST_INTEL)\
&& !defined(sun)\
&& !defined(__VXWORKS__)
# define BOOST_MATH_USE_STD_FPCLASSIFY
#endif
template<class T> struct fp_traits
{
typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
typedef typename select_native<T>::type type;
#else
typedef fp_traits_non_native<T, precision> type;
#endif
typedef fp_traits_non_native<T, precision> sign_change_type;
};
//------------------------------------------------------------------------------
} // namespace detail
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,233 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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)
//
// This is not a complete header file, it is included by gamma.hpp
// after it has defined it's definitions. This inverts the incomplete
// gamma functions P and Q on the first parameter "a" using a generic
// root finding algorithm (TOMS Algorithm 748).
//
#ifndef BOOST_MATH_SP_DETAIL_GAMMA_INVA
#define BOOST_MATH_SP_DETAIL_GAMMA_INVA
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/toms748_solve.hpp>
#include <boost/cstdint.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
struct gamma_inva_t
{
gamma_inva_t(T z_, T p_, bool invert_) : z(z_), p(p_), invert(invert_) {}
T operator()(T a)
{
return invert ? p - boost::math::gamma_q(a, z, Policy()) : boost::math::gamma_p(a, z, Policy()) - p;
}
private:
T z, p;
bool invert;
};
template <class T, class Policy>
T inverse_poisson_cornish_fisher(T lambda, T p, T q, const Policy& pol)
{
BOOST_MATH_STD_USING
// mean:
T m = lambda;
// standard deviation:
T sigma = sqrt(lambda);
// skewness
T sk = 1 / sigma;
// kurtosis:
// T k = 1/lambda;
// Get the inverse of a std normal distribution:
T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
// Set the sign:
if(p < 0.5)
x = -x;
T x2 = x * x;
// w is correction term due to skewness
T w = x + sk * (x2 - 1) / 6;
/*
// Add on correction due to kurtosis.
// Disabled for now, seems to make things worse?
//
if(lambda >= 10)
w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
*/
w = m + sigma * w;
return w > tools::min_value<T>() ? w : tools::min_value<T>();
}
template <class T, class Policy>
T gamma_inva_imp(const T& z, const T& p, const T& q, const Policy& pol)
{
BOOST_MATH_STD_USING // for ADL of std lib math functions
//
// Special cases first:
//
if(p == 0)
{
return policies::raise_overflow_error<T>("boost::math::gamma_p_inva<%1%>(%1%, %1%)", 0, Policy());
}
if(q == 0)
{
return tools::min_value<T>();
}
//
// Function object, this is the functor whose root
// we have to solve:
//
gamma_inva_t<T, Policy> f(z, (p < q) ? p : q, (p < q) ? false : true);
//
// Tolerance: full precision.
//
tools::eps_tolerance<T> tol(policies::digits<T, Policy>());
//
// Now figure out a starting guess for what a may be,
// we'll start out with a value that'll put p or q
// right bang in the middle of their range, the functions
// are quite sensitive so we should need too many steps
// to bracket the root from there:
//
T guess;
T factor = 8;
if(z >= 1)
{
//
// We can use the relationship between the incomplete
// gamma function and the poisson distribution to
// calculate an approximate inverse, for large z
// this is actually pretty accurate, but it fails badly
// when z is very small. Also set our step-factor according
// to how accurate we think the result is likely to be:
//
guess = 1 + inverse_poisson_cornish_fisher(z, q, p, pol);
if(z > 5)
{
if(z > 1000)
factor = 1.01f;
else if(z > 50)
factor = 1.1f;
else if(guess > 10)
factor = 1.25f;
else
factor = 2;
if(guess < 1.1)
factor = 8;
}
}
else if(z > 0.5)
{
guess = z * 1.2f;
}
else
{
guess = -0.4f / log(z);
}
//
// Max iterations permitted:
//
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
//
// Use our generic derivative-free root finding procedure.
// We could use Newton steps here, taking the PDF of the
// Poisson distribution as our derivative, but that's
// even worse performance-wise than the generic method :-(
//
std::pair<T, T> r = bracket_and_solve_root(f, guess, factor, false, tol, max_iter, pol);
if(max_iter >= policies::get_max_root_iterations<Policy>())
return policies::raise_evaluation_error<T>("boost::math::gamma_p_inva<%1%>(%1%, %1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol);
return (r.first + r.second) / 2;
}
} // namespace detail
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
gamma_p_inva(T1 x, T2 p, const Policy& pol)
{
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;
if(p == 0)
{
policies::raise_overflow_error<result_type>("boost::math::gamma_p_inva<%1%>(%1%, %1%)", 0, Policy());
}
if(p == 1)
{
return tools::min_value<result_type>();
}
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::gamma_inva_imp(
static_cast<value_type>(x),
static_cast<value_type>(p),
static_cast<value_type>(1 - static_cast<value_type>(p)),
pol), "boost::math::gamma_p_inva<%1%>(%1%, %1%)");
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
gamma_q_inva(T1 x, T2 q, const Policy& pol)
{
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;
if(q == 1)
{
policies::raise_overflow_error<result_type>("boost::math::gamma_q_inva<%1%>(%1%, %1%)", 0, Policy());
}
if(q == 0)
{
return tools::min_value<result_type>();
}
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::gamma_inva_imp(
static_cast<value_type>(x),
static_cast<value_type>(1 - static_cast<value_type>(q)),
static_cast<value_type>(q),
pol), "boost::math::gamma_q_inva<%1%>(%1%, %1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
gamma_p_inva(T1 x, T2 p)
{
return boost::math::gamma_p_inva(x, p, policies::policy<>());
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
gamma_q_inva(T1 x, T2 q)
{
return boost::math::gamma_q_inva(x, q, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SP_DETAIL_GAMMA_INVA

View File

@@ -0,0 +1,328 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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)
//
// This is not a complete header file, it is included by beta.hpp
// after it has defined it's definitions. This inverts the incomplete
// beta functions ibeta and ibetac on the first parameters "a"
// and "b" using a generic root finding algorithm (TOMS Algorithm 748).
//
#ifndef BOOST_MATH_SP_DETAIL_BETA_INV_AB
#define BOOST_MATH_SP_DETAIL_BETA_INV_AB
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/toms748_solve.hpp>
#include <boost/cstdint.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
struct beta_inv_ab_t
{
beta_inv_ab_t(T b_, T z_, T p_, bool invert_, bool swap_ab_) : b(b_), z(z_), p(p_), invert(invert_), swap_ab(swap_ab_) {}
T operator()(T a)
{
return invert ?
p - boost::math::ibetac(swap_ab ? b : a, swap_ab ? a : b, z, Policy())
: boost::math::ibeta(swap_ab ? b : a, swap_ab ? a : b, z, Policy()) - p;
}
private:
T b, z, p;
bool invert, swap_ab;
};
template <class T, class Policy>
T inverse_negative_binomial_cornish_fisher(T n, T sf, T sfc, T p, T q, const Policy& pol)
{
BOOST_MATH_STD_USING
// mean:
T m = n * (sfc) / sf;
T t = sqrt(n * (sfc));
// standard deviation:
T sigma = t / sf;
// skewness
T sk = (1 + sfc) / t;
// kurtosis:
T k = (6 - sf * (5+sfc)) / (n * (sfc));
// Get the inverse of a std normal distribution:
T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
// Set the sign:
if(p < 0.5)
x = -x;
T x2 = x * x;
// w is correction term due to skewness
T w = x + sk * (x2 - 1) / 6;
//
// Add on correction due to kurtosis.
//
if(n >= 10)
w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
w = m + sigma * w;
if(w < tools::min_value<T>())
return tools::min_value<T>();
return w;
}
template <class T, class Policy>
T ibeta_inv_ab_imp(const T& b, const T& z, const T& p, const T& q, bool swap_ab, const Policy& pol)
{
BOOST_MATH_STD_USING // for ADL of std lib math functions
//
// Special cases first:
//
BOOST_MATH_INSTRUMENT_CODE("b = " << b << " z = " << z << " p = " << p << " q = " << " swap = " << swap_ab);
if(p == 0)
{
return swap_ab ? tools::min_value<T>() : tools::max_value<T>();
}
if(q == 0)
{
return swap_ab ? tools::max_value<T>() : tools::min_value<T>();
}
//
// Function object, this is the functor whose root
// we have to solve:
//
beta_inv_ab_t<T, Policy> f(b, z, (p < q) ? p : q, (p < q) ? false : true, swap_ab);
//
// Tolerance: full precision.
//
tools::eps_tolerance<T> tol(policies::digits<T, Policy>());
//
// Now figure out a starting guess for what a may be,
// we'll start out with a value that'll put p or q
// right bang in the middle of their range, the functions
// are quite sensitive so we should need too many steps
// to bracket the root from there:
//
T guess = 0;
T factor = 5;
//
// Convert variables to parameters of a negative binomial distribution:
//
T n = b;
T sf = swap_ab ? z : 1-z;
T sfc = swap_ab ? 1-z : z;
T u = swap_ab ? p : q;
T v = swap_ab ? q : p;
if(u <= pow(sf, n))
{
//
// Result is less than 1, negative binomial approximation
// is useless....
//
if((p < q) != swap_ab)
{
guess = (std::min)(T(b * 2), T(1));
}
else
{
guess = (std::min)(T(b / 2), T(1));
}
}
if(n * n * n * u * sf > 0.005)
guess = 1 + inverse_negative_binomial_cornish_fisher(n, sf, sfc, u, v, pol);
if(guess < 10)
{
//
// Negative binomial approximation not accurate in this area:
//
if((p < q) != swap_ab)
{
guess = (std::min)(T(b * 2), T(10));
}
else
{
guess = (std::min)(T(b / 2), T(10));
}
}
else
factor = (v < sqrt(tools::epsilon<T>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
//
// Max iterations permitted:
//
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
std::pair<T, T> r = bracket_and_solve_root(f, guess, factor, swap_ab ? true : false, tol, max_iter, pol);
if(max_iter >= policies::get_max_root_iterations<Policy>())
return policies::raise_evaluation_error<T>("boost::math::ibeta_invab_imp<%1%>(%1%,%1%,%1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol);
return (r.first + r.second) / 2;
}
} // namespace detail
template <class RT1, class RT2, class RT3, class Policy>
typename tools::promote_args<RT1, RT2, RT3>::type
ibeta_inva(RT1 b, RT2 x, RT3 p, const Policy& pol)
{
typedef typename tools::promote_args<RT1, RT2, RT3>::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;
static const char* function = "boost::math::ibeta_inva<%1%>(%1%,%1%,%1%)";
if(p == 0)
{
return policies::raise_overflow_error<result_type>(function, 0, Policy());
}
if(p == 1)
{
return tools::min_value<result_type>();
}
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::ibeta_inv_ab_imp(
static_cast<value_type>(b),
static_cast<value_type>(x),
static_cast<value_type>(p),
static_cast<value_type>(1 - static_cast<value_type>(p)),
false, pol),
function);
}
template <class RT1, class RT2, class RT3, class Policy>
typename tools::promote_args<RT1, RT2, RT3>::type
ibetac_inva(RT1 b, RT2 x, RT3 q, const Policy& pol)
{
typedef typename tools::promote_args<RT1, RT2, RT3>::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;
static const char* function = "boost::math::ibetac_inva<%1%>(%1%,%1%,%1%)";
if(q == 1)
{
return policies::raise_overflow_error<result_type>(function, 0, Policy());
}
if(q == 0)
{
return tools::min_value<result_type>();
}
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::ibeta_inv_ab_imp(
static_cast<value_type>(b),
static_cast<value_type>(x),
static_cast<value_type>(1 - static_cast<value_type>(q)),
static_cast<value_type>(q),
false, pol),
function);
}
template <class RT1, class RT2, class RT3, class Policy>
typename tools::promote_args<RT1, RT2, RT3>::type
ibeta_invb(RT1 a, RT2 x, RT3 p, const Policy& pol)
{
typedef typename tools::promote_args<RT1, RT2, RT3>::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;
static const char* function = "boost::math::ibeta_invb<%1%>(%1%,%1%,%1%)";
if(p == 0)
{
return tools::min_value<result_type>();
}
if(p == 1)
{
return policies::raise_overflow_error<result_type>(function, 0, Policy());
}
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::ibeta_inv_ab_imp(
static_cast<value_type>(a),
static_cast<value_type>(x),
static_cast<value_type>(p),
static_cast<value_type>(1 - static_cast<value_type>(p)),
true, pol),
function);
}
template <class RT1, class RT2, class RT3, class Policy>
typename tools::promote_args<RT1, RT2, RT3>::type
ibetac_invb(RT1 a, RT2 x, RT3 q, const Policy& pol)
{
static const char* function = "boost::math::ibeta_invb<%1%>(%1%, %1%, %1%)";
typedef typename tools::promote_args<RT1, RT2, RT3>::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;
if(q == 1)
{
return tools::min_value<result_type>();
}
if(q == 0)
{
return policies::raise_overflow_error<result_type>(function, 0, Policy());
}
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::ibeta_inv_ab_imp(
static_cast<value_type>(a),
static_cast<value_type>(x),
static_cast<value_type>(1 - static_cast<value_type>(q)),
static_cast<value_type>(q),
true, pol),
function);
}
template <class RT1, class RT2, class RT3>
inline typename tools::promote_args<RT1, RT2, RT3>::type
ibeta_inva(RT1 b, RT2 x, RT3 p)
{
return boost::math::ibeta_inva(b, x, p, policies::policy<>());
}
template <class RT1, class RT2, class RT3>
inline typename tools::promote_args<RT1, RT2, RT3>::type
ibetac_inva(RT1 b, RT2 x, RT3 q)
{
return boost::math::ibetac_inva(b, x, q, policies::policy<>());
}
template <class RT1, class RT2, class RT3>
inline typename tools::promote_args<RT1, RT2, RT3>::type
ibeta_invb(RT1 a, RT2 x, RT3 p)
{
return boost::math::ibeta_invb(a, x, p, policies::policy<>());
}
template <class RT1, class RT2, class RT3>
inline typename tools::promote_args<RT1, RT2, RT3>::type
ibetac_invb(RT1 a, RT2 x, RT3 q)
{
return boost::math::ibetac_invb(a, x, q, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SP_DETAIL_BETA_INV_AB

View File

@@ -0,0 +1,993 @@
// Copyright John Maddock 2006.
// Copyright Paul A. Bristow 2007
// Use, modification and distribution are subject to 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_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
#define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/beta.hpp>
#include <boost/math/special_functions/erf.hpp>
#include <boost/math/tools/roots.hpp>
#include <boost/math/special_functions/detail/t_distribution_inv.hpp>
namespace boost{ namespace math{ namespace detail{
//
// Helper object used by root finding
// code to convert eta to x.
//
template <class T>
struct temme_root_finder
{
temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {}
boost::math::tuple<T, T> operator()(T x)
{
BOOST_MATH_STD_USING // ADL of std names
T y = 1 - x;
if(y == 0)
{
T big = tools::max_value<T>() / 4;
return boost::math::make_tuple(static_cast<T>(-big), static_cast<T>(-big));
}
if(x == 0)
{
T big = tools::max_value<T>() / 4;
return boost::math::make_tuple(static_cast<T>(-big), big);
}
T f = log(x) + a * log(y) + t;
T f1 = (1 / x) - (a / (y));
return boost::math::make_tuple(f, f1);
}
private:
T t, a;
};
//
// See:
// "Asymptotic Inversion of the Incomplete Beta Function"
// N.M. Temme
// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
// Section 2.
//
template <class T, class Policy>
T temme_method_1_ibeta_inverse(T a, T b, T z, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
const T r2 = sqrt(T(2));
//
// get the first approximation for eta from the inverse
// error function (Eq: 2.9 and 2.10).
//
T eta0 = boost::math::erfc_inv(2 * z, pol);
eta0 /= -sqrt(a / 2);
T terms[4] = { eta0 };
T workspace[7];
//
// calculate powers:
//
T B = b - a;
T B_2 = B * B;
T B_3 = B_2 * B;
//
// Calculate correction terms:
//
// See eq following 2.15:
workspace[0] = -B * r2 / 2;
workspace[1] = (1 - 2 * B) / 8;
workspace[2] = -(B * r2 / 48);
workspace[3] = T(-1) / 192;
workspace[4] = -B * r2 / 3840;
terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
// Eq Following 2.17:
workspace[0] = B * r2 * (3 * B - 2) / 12;
workspace[1] = (20 * B_2 - 12 * B + 1) / 128;
workspace[2] = B * r2 * (20 * B - 1) / 960;
workspace[3] = (16 * B_2 + 30 * B - 15) / 4608;
workspace[4] = B * r2 * (21 * B + 32) / 53760;
workspace[5] = (-32 * B_2 + 63) / 368640;
workspace[6] = -B * r2 * (120 * B + 17) / 25804480;
terms[2] = tools::evaluate_polynomial(workspace, eta0, 7);
// Eq Following 2.17:
workspace[0] = B * r2 * (-75 * B_2 + 80 * B - 16) / 480;
workspace[1] = (-1080 * B_3 + 868 * B_2 - 90 * B - 45) / 9216;
workspace[2] = B * r2 * (-1190 * B_2 + 84 * B + 373) / 53760;
workspace[3] = (-2240 * B_3 - 2508 * B_2 + 2100 * B - 165) / 368640;
terms[3] = tools::evaluate_polynomial(workspace, eta0, 4);
//
// Bring them together to get a final estimate for eta:
//
T eta = tools::evaluate_polynomial(terms, T(1/a), 4);
//
// now we need to convert eta to x, by solving the appropriate
// quadratic equation:
//
T eta_2 = eta * eta;
T c = -exp(-eta_2 / 2);
T x;
if(eta_2 == 0)
x = 0.5;
else
x = (1 + eta * sqrt((1 + c) / eta_2)) / 2;
BOOST_ASSERT(x >= 0);
BOOST_ASSERT(x <= 1);
BOOST_ASSERT(eta * (x - 0.5) >= 0);
#ifdef BOOST_INSTRUMENT
std::cout << "Estimating x with Temme method 1: " << x << std::endl;
#endif
return x;
}
//
// See:
// "Asymptotic Inversion of the Incomplete Beta Function"
// N.M. Temme
// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
// Section 3.
//
template <class T, class Policy>
T temme_method_2_ibeta_inverse(T /*a*/, T /*b*/, T z, T r, T theta, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
//
// Get first estimate for eta, see Eq 3.9 and 3.10,
// but note there is a typo in Eq 3.10:
//
T eta0 = boost::math::erfc_inv(2 * z, pol);
eta0 /= -sqrt(r / 2);
T s = sin(theta);
T c = cos(theta);
//
// Now we need to purturb eta0 to get eta, which we do by
// evaluating the polynomial in 1/r at the bottom of page 151,
// to do this we first need the error terms e1, e2 e3
// which we'll fill into the array "terms". Since these
// terms are themselves polynomials, we'll need another
// array "workspace" to calculate those...
//
T terms[4] = { eta0 };
T workspace[6];
//
// some powers of sin(theta)cos(theta) that we'll need later:
//
T sc = s * c;
T sc_2 = sc * sc;
T sc_3 = sc_2 * sc;
T sc_4 = sc_2 * sc_2;
T sc_5 = sc_2 * sc_3;
T sc_6 = sc_3 * sc_3;
T sc_7 = sc_4 * sc_3;
//
// Calculate e1 and put it in terms[1], see the middle of page 151:
//
workspace[0] = (2 * s * s - 1) / (3 * s * c);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co1[] = { -1, -5, 5 };
workspace[1] = -tools::evaluate_even_polynomial(co1, s, 3) / (36 * sc_2);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co2[] = { 1, 21, -69, 46 };
workspace[2] = tools::evaluate_even_polynomial(co2, s, 4) / (1620 * sc_3);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 7, -2, 33, -62, 31 };
workspace[3] = -tools::evaluate_even_polynomial(co3, s, 5) / (6480 * sc_4);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 25, -52, -17, 88, -115, 46 };
workspace[4] = tools::evaluate_even_polynomial(co4, s, 6) / (90720 * sc_5);
terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
//
// Now evaluate e2 and put it in terms[2]:
//
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co5[] = { 7, 12, -78, 52 };
workspace[0] = -tools::evaluate_even_polynomial(co5, s, 4) / (405 * sc_3);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co6[] = { -7, 2, 183, -370, 185 };
workspace[1] = tools::evaluate_even_polynomial(co6, s, 5) / (2592 * sc_4);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co7[] = { -533, 776, -1835, 10240, -13525, 5410 };
workspace[2] = -tools::evaluate_even_polynomial(co7, s, 6) / (204120 * sc_5);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co8[] = { -1579, 3747, -3372, -15821, 45588, -45213, 15071 };
workspace[3] = -tools::evaluate_even_polynomial(co8, s, 7) / (2099520 * sc_6);
terms[2] = tools::evaluate_polynomial(workspace, eta0, 4);
//
// And e3, and put it in terms[3]:
//
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co9[] = {449, -1259, -769, 6686, -9260, 3704 };
workspace[0] = tools::evaluate_even_polynomial(co9, s, 6) / (102060 * sc_5);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co10[] = { 63149, -151557, 140052, -727469, 2239932, -2251437, 750479 };
workspace[1] = -tools::evaluate_even_polynomial(co10, s, 7) / (20995200 * sc_6);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co11[] = { 29233, -78755, 105222, 146879, -1602610, 3195183, -2554139, 729754 };
workspace[2] = tools::evaluate_even_polynomial(co11, s, 8) / (36741600 * sc_7);
terms[3] = tools::evaluate_polynomial(workspace, eta0, 3);
//
// Bring the correction terms together to evaluate eta,
// this is the last equation on page 151:
//
T eta = tools::evaluate_polynomial(terms, T(1/r), 4);
//
// Now that we have eta we need to back solve for x,
// we seek the value of x that gives eta in Eq 3.2.
// The two methods used are described in section 5.
//
// Begin by defining a few variables we'll need later:
//
T x;
T s_2 = s * s;
T c_2 = c * c;
T alpha = c / s;
alpha *= alpha;
T lu = (-(eta * eta) / (2 * s_2) + log(s_2) + c_2 * log(c_2) / s_2);
//
// Temme doesn't specify what value to switch on here,
// but this seems to work pretty well:
//
if(fabs(eta) < 0.7)
{
//
// Small eta use the expansion Temme gives in the second equation
// of section 5, it's a polynomial in eta:
//
workspace[0] = s * s;
workspace[1] = s * c;
workspace[2] = (1 - 2 * workspace[0]) / 3;
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co12[] = { 1, -13, 13 };
workspace[3] = tools::evaluate_polynomial(co12, workspace[0], 3) / (36 * s * c);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co13[] = { 1, 21, -69, 46 };
workspace[4] = tools::evaluate_polynomial(co13, workspace[0], 4) / (270 * workspace[0] * c * c);
x = tools::evaluate_polynomial(workspace, eta, 5);
#ifdef BOOST_INSTRUMENT
std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl;
#endif
}
else
{
//
// If eta is large we need to solve Eq 3.2 more directly,
// begin by getting an initial approximation for x from
// the last equation on page 155, this is a polynomial in u:
//
T u = exp(lu);
workspace[0] = u;
workspace[1] = alpha;
workspace[2] = 0;
workspace[3] = 3 * alpha * (3 * alpha + 1) / 6;
workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24;
workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120;
x = tools::evaluate_polynomial(workspace, u, 6);
//
// At this point we may or may not have the right answer, Eq-3.2 has
// two solutions for x for any given eta, however the mapping in 3.2
// is 1:1 with the sign of eta and x-sin^2(theta) being the same.
// So we can check if we have the right root of 3.2, and if not
// switch x for 1-x. This transformation is motivated by the fact
// that the distribution is *almost* symetric so 1-x will be in the right
// ball park for the solution:
//
if((x - s_2) * eta < 0)
x = 1 - x;
#ifdef BOOST_INSTRUMENT
std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl;
#endif
}
//
// The final step is a few Newton-Raphson iterations to
// clean up our approximation for x, this is pretty cheap
// in general, and very cheap compared to an incomplete beta
// evaluation. The limits set on x come from the observation
// that the sign of eta and x-sin^2(theta) are the same.
//
T lower, upper;
if(eta < 0)
{
lower = 0;
upper = s_2;
}
else
{
lower = s_2;
upper = 1;
}
//
// If our initial approximation is out of bounds then bisect:
//
if((x < lower) || (x > upper))
x = (lower+upper) / 2;
//
// And iterate:
//
x = tools::newton_raphson_iterate(
temme_root_finder<T>(-lu, alpha), x, lower, upper, policies::digits<T, Policy>() / 2);
return x;
}
//
// See:
// "Asymptotic Inversion of the Incomplete Beta Function"
// N.M. Temme
// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
// Section 4.
//
template <class T, class Policy>
T temme_method_3_ibeta_inverse(T a, T b, T p, T q, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
//
// Begin by getting an initial approximation for the quantity
// eta from the dominant part of the incomplete beta:
//
T eta0;
if(p < q)
eta0 = boost::math::gamma_q_inv(b, p, pol);
else
eta0 = boost::math::gamma_p_inv(b, q, pol);
eta0 /= a;
//
// Define the variables and powers we'll need later on:
//
T mu = b / a;
T w = sqrt(1 + mu);
T w_2 = w * w;
T w_3 = w_2 * w;
T w_4 = w_2 * w_2;
T w_5 = w_3 * w_2;
T w_6 = w_3 * w_3;
T w_7 = w_4 * w_3;
T w_8 = w_4 * w_4;
T w_9 = w_5 * w_4;
T w_10 = w_5 * w_5;
T d = eta0 - mu;
T d_2 = d * d;
T d_3 = d_2 * d;
T d_4 = d_2 * d_2;
T w1 = w + 1;
T w1_2 = w1 * w1;
T w1_3 = w1 * w1_2;
T w1_4 = w1_2 * w1_2;
//
// Now we need to compute the purturbation error terms that
// convert eta0 to eta, these are all polynomials of polynomials.
// Probably these should be re-written to use tabulated data
// (see examples above), but it's less of a win in this case as we
// need to calculate the individual powers for the denominator terms
// anyway, so we might as well use them for the numerator-polynomials
// as well....
//
// Refer to p154-p155 for the details of these expansions:
//
T e1 = (w + 2) * (w - 1) / (3 * w);
e1 += (w_3 + 9 * w_2 + 21 * w + 5) * d / (36 * w_2 * w1);
e1 -= (w_4 - 13 * w_3 + 69 * w_2 + 167 * w + 46) * d_2 / (1620 * w1_2 * w_3);
e1 -= (7 * w_5 + 21 * w_4 + 70 * w_3 + 26 * w_2 - 93 * w - 31) * d_3 / (6480 * w1_3 * w_4);
e1 -= (75 * w_6 + 202 * w_5 + 188 * w_4 - 888 * w_3 - 1345 * w_2 + 118 * w + 138) * d_4 / (272160 * w1_4 * w_5);
T e2 = (28 * w_4 + 131 * w_3 + 402 * w_2 + 581 * w + 208) * (w - 1) / (1620 * w1 * w_3);
e2 -= (35 * w_6 - 154 * w_5 - 623 * w_4 - 1636 * w_3 - 3983 * w_2 - 3514 * w - 925) * d / (12960 * w1_2 * w_4);
e2 -= (2132 * w_7 + 7915 * w_6 + 16821 * w_5 + 35066 * w_4 + 87490 * w_3 + 141183 * w_2 + 95993 * w + 21640) * d_2 / (816480 * w_5 * w1_3);
e2 -= (11053 * w_8 + 53308 * w_7 + 117010 * w_6 + 163924 * w_5 + 116188 * w_4 - 258428 * w_3 - 677042 * w_2 - 481940 * w - 105497) * d_3 / (14696640 * w1_4 * w_6);
T e3 = -((3592 * w_7 + 8375 * w_6 - 1323 * w_5 - 29198 * w_4 - 89578 * w_3 - 154413 * w_2 - 116063 * w - 29632) * (w - 1)) / (816480 * w_5 * w1_2);
e3 -= (442043 * w_9 + 2054169 * w_8 + 3803094 * w_7 + 3470754 * w_6 + 2141568 * w_5 - 2393568 * w_4 - 19904934 * w_3 - 34714674 * w_2 - 23128299 * w - 5253353) * d / (146966400 * w_6 * w1_3);
e3 -= (116932 * w_10 + 819281 * w_9 + 2378172 * w_8 + 4341330 * w_7 + 6806004 * w_6 + 10622748 * w_5 + 18739500 * w_4 + 30651894 * w_3 + 30869976 * w_2 + 15431867 * w + 2919016) * d_2 / (146966400 * w1_4 * w_7);
//
// Combine eta0 and the error terms to compute eta (Second eqaution p155):
//
T eta = eta0 + e1 / a + e2 / (a * a) + e3 / (a * a * a);
//
// Now we need to solve Eq 4.2 to obtain x. For any given value of
// eta there are two solutions to this equation, and since the distribtion
// may be very skewed, these are not related by x ~ 1-x we used when
// implementing section 3 above. However we know that:
//
// cross < x <= 1 ; iff eta < mu
// x == cross ; iff eta == mu
// 0 <= x < cross ; iff eta > mu
//
// Where cross == 1 / (1 + mu)
// Many thanks to Prof Temme for clarifying this point.
//
// Therefore we'll just jump straight into Newton iterations
// to solve Eq 4.2 using these bounds, and simple bisection
// as the first guess, in practice this converges pretty quickly
// and we only need a few digits correct anyway:
//
if(eta <= 0)
eta = tools::min_value<T>();
T u = eta - mu * log(eta) + (1 + mu) * log(1 + mu) - mu;
T cross = 1 / (1 + mu);
T lower = eta < mu ? cross : 0;
T upper = eta < mu ? 1 : cross;
T x = (lower + upper) / 2;
x = tools::newton_raphson_iterate(
temme_root_finder<T>(u, mu), x, lower, upper, policies::digits<T, Policy>() / 2);
#ifdef BOOST_INSTRUMENT
std::cout << "Estimating x with Temme method 3: " << x << std::endl;
#endif
return x;
}
template <class T, class Policy>
struct ibeta_roots
{
ibeta_roots(T _a, T _b, T t, bool inv = false)
: a(_a), b(_b), target(t), invert(inv) {}
boost::math::tuple<T, T, T> operator()(T x)
{
BOOST_MATH_STD_USING // ADL of std names
BOOST_FPU_EXCEPTION_GUARD
T f1;
T y = 1 - x;
T f = ibeta_imp(a, b, x, Policy(), invert, true, &f1) - target;
if(invert)
f1 = -f1;
if(y == 0)
y = tools::min_value<T>() * 64;
if(x == 0)
x = tools::min_value<T>() * 64;
T f2 = f1 * (-y * a + (b - 2) * x + 1);
if(fabs(f2) < y * x * tools::max_value<T>())
f2 /= (y * x);
if(invert)
f2 = -f2;
// make sure we don't have a zero derivative:
if(f1 == 0)
f1 = (invert ? -1 : 1) * tools::min_value<T>() * 64;
return boost::math::make_tuple(f, f1, f2);
}
private:
T a, b, target;
bool invert;
};
template <class T, class Policy>
T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
{
BOOST_MATH_STD_USING // For ADL of math functions.
//
// The flag invert is set to true if we swap a for b and p for q,
// in which case the result has to be subtracted from 1:
//
bool invert = false;
//
// Handle trivial cases first:
//
if(q == 0)
{
if(py) *py = 0;
return 1;
}
else if(p == 0)
{
if(py) *py = 1;
return 0;
}
else if(a == 1)
{
if(b == 1)
{
if(py) *py = 1 - p;
return p;
}
// Change things around so we can handle as b == 1 special case below:
std::swap(a, b);
std::swap(p, q);
invert = true;
}
//
// Depending upon which approximation method we use, we may end up
// calculating either x or y initially (where y = 1-x):
//
T x = 0; // Set to a safe zero to avoid a
// MSVC 2005 warning C4701: potentially uninitialized local variable 'x' used
// But code inspection appears to ensure that x IS assigned whatever the code path.
T y;
// For some of the methods we can put tighter bounds
// on the result than simply [0,1]:
//
T lower = 0;
T upper = 1;
//
// Student's T with b = 0.5 gets handled as a special case, swap
// around if the arguments are in the "wrong" order:
//
if(a == 0.5f)
{
if(b == 0.5f)
{
x = sin(p * constants::half_pi<T>());
x *= x;
if(py)
{
*py = sin(q * constants::half_pi<T>());
*py *= *py;
}
return x;
}
else if(b > 0.5f)
{
std::swap(a, b);
std::swap(p, q);
invert = !invert;
}
}
//
// Select calculation method for the initial estimate:
//
if((b == 0.5f) && (a >= 0.5f) && (p != 1))
{
//
// We have a Student's T distribution:
x = find_ibeta_inv_from_t_dist(a, p, q, &y, pol);
}
else if(b == 1)
{
if(p < q)
{
if(a > 1)
{
x = pow(p, 1 / a);
y = -boost::math::expm1(log(p) / a, pol);
}
else
{
x = pow(p, 1 / a);
y = 1 - x;
}
}
else
{
x = exp(boost::math::log1p(-q, pol) / a);
y = -boost::math::expm1(boost::math::log1p(-q, pol) / a, pol);
}
if(invert)
std::swap(x, y);
if(py)
*py = y;
return x;
}
else if(a + b > 5)
{
//
// When a+b is large then we can use one of Prof Temme's
// asymptotic expansions, begin by swapping things around
// so that p < 0.5, we do this to avoid cancellations errors
// when p is large.
//
if(p > 0.5)
{
std::swap(a, b);
std::swap(p, q);
invert = !invert;
}
T minv = (std::min)(a, b);
T maxv = (std::max)(a, b);
if((sqrt(minv) > (maxv - minv)) && (minv > 5))
{
//
// When a and b differ by a small amount
// the curve is quite symmetrical and we can use an error
// function to approximate the inverse. This is the cheapest
// of the three Temme expantions, and the calculated value
// for x will never be much larger than p, so we don't have
// to worry about cancellation as long as p is small.
//
x = temme_method_1_ibeta_inverse(a, b, p, pol);
y = 1 - x;
}
else
{
T r = a + b;
T theta = asin(sqrt(a / r));
T lambda = minv / r;
if((lambda >= 0.2) && (lambda <= 0.8) && (r >= 10))
{
//
// The second error function case is the next cheapest
// to use, it brakes down when the result is likely to be
// very small, if a+b is also small, but we can use a
// cheaper expansion there in any case. As before x won't
// be much larger than p, so as long as p is small we should
// be free of cancellation error.
//
T ppa = pow(p, 1/a);
if((ppa < 0.0025) && (a + b < 200))
{
x = ppa * pow(a * boost::math::beta(a, b, pol), 1/a);
}
else
x = temme_method_2_ibeta_inverse(a, b, p, r, theta, pol);
y = 1 - x;
}
else
{
//
// If we get here then a and b are very different in magnitude
// and we need to use the third of Temme's methods which
// involves inverting the incomplete gamma. This is much more
// expensive than the other methods. We also can only use this
// method when a > b, which can lead to cancellation errors
// if we really want y (as we will when x is close to 1), so
// a different expansion is used in that case.
//
if(a < b)
{
std::swap(a, b);
std::swap(p, q);
invert = !invert;
}
//
// Try and compute the easy way first:
//
T bet = 0;
if(b < 2)
bet = boost::math::beta(a, b, pol);
if(bet != 0)
{
y = pow(b * q * bet, 1/b);
x = 1 - y;
}
else
y = 1;
if(y > 1e-5)
{
x = temme_method_3_ibeta_inverse(a, b, p, q, pol);
y = 1 - x;
}
}
}
}
else if((a < 1) && (b < 1))
{
//
// Both a and b less than 1,
// there is a point of inflection at xs:
//
T xs = (1 - a) / (2 - a - b);
//
// Now we need to ensure that we start our iteration from the
// right side of the inflection point:
//
T fs = boost::math::ibeta(a, b, xs, pol) - p;
if(fabs(fs) / p < tools::epsilon<T>() * 3)
{
// The result is at the point of inflection, best just return it:
*py = invert ? xs : 1 - xs;
return invert ? 1-xs : xs;
}
if(fs < 0)
{
std::swap(a, b);
std::swap(p, q);
invert = !invert;
xs = 1 - xs;
}
T xg = pow(a * p * boost::math::beta(a, b, pol), 1/a);
x = xg / (1 + xg);
y = 1 / (1 + xg);
//
// And finally we know that our result is below the inflection
// point, so set an upper limit on our search:
//
if(x > xs)
x = xs;
upper = xs;
}
else if((a > 1) && (b > 1))
{
//
// Small a and b, both greater than 1,
// there is a point of inflection at xs,
// and it's complement is xs2, we must always
// start our iteration from the right side of the
// point of inflection.
//
T xs = (a - 1) / (a + b - 2);
T xs2 = (b - 1) / (a + b - 2);
T ps = boost::math::ibeta(a, b, xs, pol) - p;
if(ps < 0)
{
std::swap(a, b);
std::swap(p, q);
std::swap(xs, xs2);
invert = !invert;
}
//
// Estimate x and y, using expm1 to get a good estimate
// for y when it's very small:
//
T lx = log(p * a * boost::math::beta(a, b, pol)) / a;
x = exp(lx);
y = x < 0.9 ? T(1 - x) : (T)(-boost::math::expm1(lx, pol));
if((b < a) && (x < 0.2))
{
//
// Under a limited range of circumstances we can improve
// our estimate for x, frankly it's clear if this has much effect!
//
T ap1 = a - 1;
T bm1 = b - 1;
T a_2 = a * a;
T a_3 = a * a_2;
T b_2 = b * b;
T terms[5] = { 0, 1 };
terms[2] = bm1 / ap1;
ap1 *= ap1;
terms[3] = bm1 * (3 * a * b + 5 * b + a_2 - a - 4) / (2 * (a + 2) * ap1);
ap1 *= (a + 1);
terms[4] = bm1 * (33 * a * b_2 + 31 * b_2 + 8 * a_2 * b_2 - 30 * a * b - 47 * b + 11 * a_2 * b + 6 * a_3 * b + 18 + 4 * a - a_3 + a_2 * a_2 - 10 * a_2)
/ (3 * (a + 3) * (a + 2) * ap1);
x = tools::evaluate_polynomial(terms, x, 5);
}
//
// And finally we know that our result is below the inflection
// point, so set an upper limit on our search:
//
if(x > xs)
x = xs;
upper = xs;
}
else /*if((a <= 1) != (b <= 1))*/
{
//
// If all else fails we get here, only one of a and b
// is above 1, and a+b is small. Start by swapping
// things around so that we have a concave curve with b > a
// and no points of inflection in [0,1]. As long as we expect
// x to be small then we can use the simple (and cheap) power
// term to estimate x, but when we expect x to be large then
// this greatly underestimates x and leaves us trying to
// iterate "round the corner" which may take almost forever...
//
// We could use Temme's inverse gamma function case in that case,
// this works really rather well (albeit expensively) even though
// strictly speaking we're outside it's defined range.
//
// However it's expensive to compute, and an alternative approach
// which models the curve as a distorted quarter circle is much
// cheaper to compute, and still keeps the number of iterations
// required down to a reasonable level. With thanks to Prof Temme
// for this suggestion.
//
if(b < a)
{
std::swap(a, b);
std::swap(p, q);
invert = !invert;
}
if(pow(p, 1/a) < 0.5)
{
x = pow(p * a * boost::math::beta(a, b, pol), 1 / a);
if(x == 0)
x = boost::math::tools::min_value<T>();
y = 1 - x;
}
else /*if(pow(q, 1/b) < 0.1)*/
{
// model a distorted quarter circle:
y = pow(1 - pow(p, b * boost::math::beta(a, b, pol)), 1/b);
if(y == 0)
y = boost::math::tools::min_value<T>();
x = 1 - y;
}
}
//
// Now we have a guess for x (and for y) we can set things up for
// iteration. If x > 0.5 it pays to swap things round:
//
if(x > 0.5)
{
std::swap(a, b);
std::swap(p, q);
std::swap(x, y);
invert = !invert;
T l = 1 - upper;
T u = 1 - lower;
lower = l;
upper = u;
}
//
// lower bound for our search:
//
// We're not interested in denormalised answers as these tend to
// these tend to take up lots of iterations, given that we can't get
// accurate derivatives in this area (they tend to be infinite).
//
if(lower == 0)
{
if(invert && (py == 0))
{
//
// We're not interested in answers smaller than machine epsilon:
//
lower = boost::math::tools::epsilon<T>();
if(x < lower)
x = lower;
}
else
lower = boost::math::tools::min_value<T>();
if(x < lower)
x = lower;
}
//
// Figure out how many digits to iterate towards:
//
int digits = boost::math::policies::digits<T, Policy>() / 2;
if((x < 1e-50) && ((a < 1) || (b < 1)))
{
//
// If we're in a region where the first derivative is very
// large, then we have to take care that the root-finder
// doesn't terminate prematurely. We'll bump the precision
// up to avoid this, but we have to take care not to set the
// precision too high or the last few iterations will just
// thrash around and convergence may be slow in this case.
// Try 3/4 of machine epsilon:
//
digits *= 3;
digits /= 2;
}
//
// Now iterate, we can use either p or q as the target here
// depending on which is smaller:
//
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
x = boost::math::tools::halley_iterate(
boost::math::detail::ibeta_roots<T, Policy>(a, b, (p < q ? p : q), (p < q ? false : true)), x, lower, upper, digits, max_iter);
policies::check_root_iterations<T>("boost::math::ibeta<%1%>(%1%, %1%, %1%)", max_iter, pol);
//
// We don't really want these asserts here, but they are useful for sanity
// checking that we have the limits right, uncomment if you suspect bugs *only*.
//
//BOOST_ASSERT(x != upper);
//BOOST_ASSERT((x != lower) || (x == boost::math::tools::min_value<T>()) || (x == boost::math::tools::epsilon<T>()));
//
// Tidy up, if we "lower" was too high then zero is the best answer we have:
//
if(x == lower)
x = 0;
if(py)
*py = invert ? x : 1 - x;
return invert ? 1-x : x;
}
} // namespace detail
template <class T1, class T2, class T3, class T4, class Policy>
inline typename tools::promote_args<T1, T2, T3, T4>::type
ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol)
{
static const char* function = "boost::math::ibeta_inv<%1%>(%1%,%1%,%1%)";
BOOST_FPU_EXCEPTION_GUARD
typedef typename tools::promote_args<T1, T2, T3, T4>::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;
if(a <= 0)
return policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
if(b <= 0)
return policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
if((p < 0) || (p > 1))
return policies::raise_domain_error<result_type>(function, "Argument p outside the range [0,1] in the incomplete beta function inverse (got p=%1%).", p, pol);
value_type rx, ry;
rx = detail::ibeta_inv_imp(
static_cast<value_type>(a),
static_cast<value_type>(b),
static_cast<value_type>(p),
static_cast<value_type>(1 - p),
forwarding_policy(), &ry);
if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
}
template <class T1, class T2, class T3, class T4>
inline typename tools::promote_args<T1, T2, T3, T4>::type
ibeta_inv(T1 a, T2 b, T3 p, T4* py)
{
return ibeta_inv(a, b, p, py, policies::policy<>());
}
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
ibeta_inv(T1 a, T2 b, T3 p)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
return ibeta_inv(a, b, p, static_cast<result_type*>(0), policies::policy<>());
}
template <class T1, class T2, class T3, class Policy>
inline typename tools::promote_args<T1, T2, T3>::type
ibeta_inv(T1 a, T2 b, T3 p, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
return ibeta_inv(a, b, p, static_cast<result_type*>(0), pol);
}
template <class T1, class T2, class T3, class T4, class Policy>
inline typename tools::promote_args<T1, T2, T3, T4>::type
ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol)
{
static const char* function = "boost::math::ibetac_inv<%1%>(%1%,%1%,%1%)";
BOOST_FPU_EXCEPTION_GUARD
typedef typename tools::promote_args<T1, T2, T3, T4>::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;
if(a <= 0)
return policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
if(b <= 0)
return policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
if((q < 0) || (q > 1))
return policies::raise_domain_error<result_type>(function, "Argument q outside the range [0,1] in the incomplete beta function inverse (got q=%1%).", q, pol);
value_type rx, ry;
rx = detail::ibeta_inv_imp(
static_cast<value_type>(a),
static_cast<value_type>(b),
static_cast<value_type>(1 - q),
static_cast<value_type>(q),
forwarding_policy(), &ry);
if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
}
template <class T1, class T2, class T3, class T4>
inline typename tools::promote_args<T1, T2, T3, T4>::type
ibetac_inv(T1 a, T2 b, T3 q, T4* py)
{
return ibetac_inv(a, b, q, py, policies::policy<>());
}
template <class RT1, class RT2, class RT3>
inline typename tools::promote_args<RT1, RT2, RT3>::type
ibetac_inv(RT1 a, RT2 b, RT3 q)
{
typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
return ibetac_inv(a, b, q, static_cast<result_type*>(0), policies::policy<>());
}
template <class RT1, class RT2, class RT3, class Policy>
inline typename tools::promote_args<RT1, RT2, RT3>::type
ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy& pol)
{
typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
return ibetac_inv(a, b, q, static_cast<result_type*>(0), pol);
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2009 John Maddock
// Use, modification and distribution are subject to 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_ICONV_HPP
#define BOOST_MATH_ICONV_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/round.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace boost { namespace math { namespace detail{
template <class T, class Policy>
inline int iconv_imp(T v, Policy const&, mpl::true_ const&)
{
return static_cast<int>(v);
}
template <class T, class Policy>
inline int iconv_imp(T v, Policy const& pol, mpl::false_ const&)
{
BOOST_MATH_STD_USING
return iround(v, pol);
}
template <class T, class Policy>
inline int iconv(T v, Policy const& pol)
{
typedef typename boost::is_convertible<T, int>::type tag_type;
return iconv_imp(v, pol, tag_type());
}
}}} // namespaces
#endif // BOOST_MATH_ICONV_HPP

View File

@@ -0,0 +1,551 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
#define BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/tuple.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <boost/math/tools/roots.hpp>
#include <boost/math/policies/error_handling.hpp>
namespace boost{ namespace math{
namespace detail{
template <class T>
T find_inverse_s(T p, T q)
{
//
// Computation of the Incomplete Gamma Function Ratios and their Inverse
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
// December 1986, Pages 377-393.
//
// See equation 32.
//
BOOST_MATH_STD_USING
T t;
if(p < 0.5)
{
t = sqrt(-2 * log(p));
}
else
{
t = sqrt(-2 * log(q));
}
static const double a[4] = { 3.31125922108741, 11.6616720288968, 4.28342155967104, 0.213623493715853 };
static const double b[5] = { 1, 6.61053765625462, 6.40691597760039, 1.27364489782223, 0.3611708101884203e-1 };
T s = t - tools::evaluate_polynomial(a, t) / tools::evaluate_polynomial(b, t);
if(p < 0.5)
s = -s;
return s;
}
template <class T>
T didonato_SN(T a, T x, unsigned N, T tolerance = 0)
{
//
// Computation of the Incomplete Gamma Function Ratios and their Inverse
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
// December 1986, Pages 377-393.
//
// See equation 34.
//
T sum = 1;
if(N >= 1)
{
T partial = x / (a + 1);
sum += partial;
for(unsigned i = 2; i <= N; ++i)
{
partial *= x / (a + i);
sum += partial;
if(partial < tolerance)
break;
}
}
return sum;
}
template <class T, class Policy>
inline T didonato_FN(T p, T a, T x, unsigned N, T tolerance, const Policy& pol)
{
//
// Computation of the Incomplete Gamma Function Ratios and their Inverse
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
// December 1986, Pages 377-393.
//
// See equation 34.
//
BOOST_MATH_STD_USING
T u = log(p) + boost::math::lgamma(a + 1, pol);
return exp((u + x - log(didonato_SN(a, x, N, tolerance))) / a);
}
template <class T, class Policy>
T find_inverse_gamma(T a, T p, T q, const Policy& pol, bool* p_has_10_digits)
{
//
// In order to understand what's going on here, you will
// need to refer to:
//
// Computation of the Incomplete Gamma Function Ratios and their Inverse
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
// December 1986, Pages 377-393.
//
BOOST_MATH_STD_USING
T result;
*p_has_10_digits = false;
if(a == 1)
{
result = -log(q);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else if(a < 1)
{
T g = boost::math::tgamma(a, pol);
T b = q * g;
BOOST_MATH_INSTRUMENT_VARIABLE(g);
BOOST_MATH_INSTRUMENT_VARIABLE(b);
if((b > 0.6) || ((b >= 0.45) && (a >= 0.3)))
{
// DiDonato & Morris Eq 21:
//
// There is a slight variation from DiDonato and Morris here:
// the first form given here is unstable when p is close to 1,
// making it impossible to compute the inverse of Q(a,x) for small
// q. Fortunately the second form works perfectly well in this case.
//
T u;
if((b * q > 1e-8) && (q > 1e-5))
{
u = pow(p * g * a, 1 / a);
BOOST_MATH_INSTRUMENT_VARIABLE(u);
}
else
{
u = exp((-q / a) - constants::euler<T>());
BOOST_MATH_INSTRUMENT_VARIABLE(u);
}
result = u / (1 - (u / (a + 1)));
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else if((a < 0.3) && (b >= 0.35))
{
// DiDonato & Morris Eq 22:
T t = exp(-constants::euler<T>() - b);
T u = t * exp(t);
result = t * exp(u);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else if((b > 0.15) || (a >= 0.3))
{
// DiDonato & Morris Eq 23:
T y = -log(b);
T u = y - (1 - a) * log(y);
result = y - (1 - a) * log(u) - log(1 + (1 - a) / (1 + u));
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else if (b > 0.1)
{
// DiDonato & Morris Eq 24:
T y = -log(b);
T u = y - (1 - a) * log(y);
result = y - (1 - a) * log(u) - log((u * u + 2 * (3 - a) * u + (2 - a) * (3 - a)) / (u * u + (5 - a) * u + 2));
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else
{
// DiDonato & Morris Eq 25:
T y = -log(b);
T c1 = (a - 1) * log(y);
T c1_2 = c1 * c1;
T c1_3 = c1_2 * c1;
T c1_4 = c1_2 * c1_2;
T a_2 = a * a;
T a_3 = a_2 * a;
T c2 = (a - 1) * (1 + c1);
T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2);
T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6);
T c5 = (a - 1) * (-(c1_4 / 4)
+ (11 * a - 17) * c1_3 / 6
+ (-3 * a_2 + 13 * a -13) * c1_2
+ (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2
+ (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12);
T y_2 = y * y;
T y_3 = y_2 * y;
T y_4 = y_2 * y_2;
result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
if(b < 1e-28f)
*p_has_10_digits = true;
}
}
else
{
// DiDonato and Morris Eq 31:
T s = find_inverse_s(p, q);
BOOST_MATH_INSTRUMENT_VARIABLE(s);
T s_2 = s * s;
T s_3 = s_2 * s;
T s_4 = s_2 * s_2;
T s_5 = s_4 * s;
T ra = sqrt(a);
BOOST_MATH_INSTRUMENT_VARIABLE(ra);
T w = a + s * ra + (s * s -1) / 3;
w += (s_3 - 7 * s) / (36 * ra);
w -= (3 * s_4 + 7 * s_2 - 16) / (810 * a);
w += (9 * s_5 + 256 * s_3 - 433 * s) / (38880 * a * ra);
BOOST_MATH_INSTRUMENT_VARIABLE(w);
if((a >= 500) && (fabs(1 - w / a) < 1e-6))
{
result = w;
*p_has_10_digits = true;
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else if (p > 0.5)
{
if(w < 3 * a)
{
result = w;
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else
{
T D = (std::max)(T(2), T(a * (a - 1)));
T lg = boost::math::lgamma(a, pol);
T lb = log(q) + lg;
if(lb < -D * 2.3)
{
// DiDonato and Morris Eq 25:
T y = -lb;
T c1 = (a - 1) * log(y);
T c1_2 = c1 * c1;
T c1_3 = c1_2 * c1;
T c1_4 = c1_2 * c1_2;
T a_2 = a * a;
T a_3 = a_2 * a;
T c2 = (a - 1) * (1 + c1);
T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2);
T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6);
T c5 = (a - 1) * (-(c1_4 / 4)
+ (11 * a - 17) * c1_3 / 6
+ (-3 * a_2 + 13 * a -13) * c1_2
+ (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2
+ (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12);
T y_2 = y * y;
T y_3 = y_2 * y;
T y_4 = y_2 * y_2;
result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else
{
// DiDonato and Morris Eq 33:
T u = -lb + (a - 1) * log(w) - log(1 + (1 - a) / (1 + w));
result = -lb + (a - 1) * log(u) - log(1 + (1 - a) / (1 + u));
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
}
}
else
{
T z = w;
T ap1 = a + 1;
T ap2 = a + 2;
if(w < 0.15f * ap1)
{
// DiDonato and Morris Eq 35:
T v = log(p) + boost::math::lgamma(ap1, pol);
z = exp((v + w) / a);
s = boost::math::log1p(z / ap1 * (1 + z / ap2), pol);
z = exp((v + z - s) / a);
s = boost::math::log1p(z / ap1 * (1 + z / ap2), pol);
z = exp((v + z - s) / a);
s = boost::math::log1p(z / ap1 * (1 + z / ap2 * (1 + z / (a + 3))), pol);
z = exp((v + z - s) / a);
BOOST_MATH_INSTRUMENT_VARIABLE(z);
}
if((z <= 0.01 * ap1) || (z > 0.7 * ap1))
{
result = z;
if(z <= 0.002 * ap1)
*p_has_10_digits = true;
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else
{
// DiDonato and Morris Eq 36:
T ls = log(didonato_SN(a, z, 100, T(1e-4)));
T v = log(p) + boost::math::lgamma(ap1, pol);
z = exp((v + z - ls) / a);
result = z * (1 - (a * log(z) - z - v + ls) / (a - z));
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
}
}
return result;
}
template <class T, class Policy>
struct gamma_p_inverse_func
{
gamma_p_inverse_func(T a_, T p_, bool inv) : a(a_), p(p_), invert(inv)
{
//
// If p is too near 1 then P(x) - p suffers from cancellation
// errors causing our root-finding algorithms to "thrash", better
// to invert in this case and calculate Q(x) - (1-p) instead.
//
// Of course if p is *very* close to 1, then the answer we get will
// be inaccurate anyway (because there's not enough information in p)
// but at least we will converge on the (inaccurate) answer quickly.
//
if(p > 0.9)
{
p = 1 - p;
invert = !invert;
}
}
boost::math::tuple<T, T, T> operator()(const T& x)const
{
BOOST_FPU_EXCEPTION_GUARD
//
// Calculate P(x) - p and the first two derivates, or if the invert
// flag is set, then Q(x) - q and it's derivatives.
//
typedef typename policies::evaluation<T, Policy>::type value_type;
// typedef typename lanczos::lanczos<T, Policy>::type evaluation_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
BOOST_MATH_STD_USING // For ADL of std functions.
T f, f1;
value_type ft;
f = static_cast<T>(boost::math::detail::gamma_incomplete_imp(
static_cast<value_type>(a),
static_cast<value_type>(x),
true, invert,
forwarding_policy(), &ft));
f1 = static_cast<T>(ft);
T f2;
T div = (a - x - 1) / x;
f2 = f1;
if((fabs(div) > 1) && (tools::max_value<T>() / fabs(div) < f2))
{
// overflow:
f2 = -tools::max_value<T>() / 2;
}
else
{
f2 *= div;
}
if(invert)
{
f1 = -f1;
f2 = -f2;
}
return boost::math::make_tuple(static_cast<T>(f - p), f1, f2);
}
private:
T a, p;
bool invert;
};
template <class T, class Policy>
T gamma_p_inv_imp(T a, T p, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const char* function = "boost::math::gamma_p_inv<%1%>(%1%, %1%)";
BOOST_MATH_INSTRUMENT_VARIABLE(a);
BOOST_MATH_INSTRUMENT_VARIABLE(p);
if(a <= 0)
return policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
if((p < 0) || (p > 1))
return policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got p=%1%).", p, pol);
if(p == 1)
return policies::raise_overflow_error<T>(function, 0, Policy());
if(p == 0)
return 0;
bool has_10_digits;
T guess = detail::find_inverse_gamma<T>(a, p, 1 - p, pol, &has_10_digits);
if((policies::digits<T, Policy>() <= 36) && has_10_digits)
return guess;
T lower = tools::min_value<T>();
if(guess <= lower)
guess = tools::min_value<T>();
BOOST_MATH_INSTRUMENT_VARIABLE(guess);
//
// Work out how many digits to converge to, normally this is
// 2/3 of the digits in T, but if the first derivative is very
// large convergence is slow, so we'll bump it up to full
// precision to prevent premature termination of the root-finding routine.
//
unsigned digits = policies::digits<T, Policy>();
if(digits < 30)
{
digits *= 2;
digits /= 3;
}
else
{
digits /= 2;
digits -= 1;
}
if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
digits = policies::digits<T, Policy>() - 2;
//
// Go ahead and iterate:
//
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
guess = tools::halley_iterate(
detail::gamma_p_inverse_func<T, Policy>(a, p, false),
guess,
lower,
tools::max_value<T>(),
digits,
max_iter);
policies::check_root_iterations<T>(function, max_iter, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(guess);
if(guess == lower)
guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
return guess;
}
template <class T, class Policy>
T gamma_q_inv_imp(T a, T q, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const char* function = "boost::math::gamma_q_inv<%1%>(%1%, %1%)";
if(a <= 0)
return policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
if((q < 0) || (q > 1))
return policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got q=%1%).", q, pol);
if(q == 0)
return policies::raise_overflow_error<T>(function, 0, Policy());
if(q == 1)
return 0;
bool has_10_digits;
T guess = detail::find_inverse_gamma<T>(a, 1 - q, q, pol, &has_10_digits);
if((policies::digits<T, Policy>() <= 36) && has_10_digits)
return guess;
T lower = tools::min_value<T>();
if(guess <= lower)
guess = tools::min_value<T>();
//
// Work out how many digits to converge to, normally this is
// 2/3 of the digits in T, but if the first derivative is very
// large convergence is slow, so we'll bump it up to full
// precision to prevent premature termination of the root-finding routine.
//
unsigned digits = policies::digits<T, Policy>();
if(digits < 30)
{
digits *= 2;
digits /= 3;
}
else
{
digits /= 2;
digits -= 1;
}
if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
digits = policies::digits<T, Policy>();
//
// Go ahead and iterate:
//
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
guess = tools::halley_iterate(
detail::gamma_p_inverse_func<T, Policy>(a, q, true),
guess,
lower,
tools::max_value<T>(),
digits,
max_iter);
policies::check_root_iterations<T>(function, max_iter, pol);
if(guess == lower)
guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
return guess;
}
} // namespace detail
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
gamma_p_inv(T1 a, T2 p, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
return detail::gamma_p_inv_imp(
static_cast<result_type>(a),
static_cast<result_type>(p), pol);
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
gamma_q_inv(T1 a, T2 p, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
return detail::gamma_q_inv_imp(
static_cast<result_type>(a),
static_cast<result_type>(p), pol);
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
gamma_p_inv(T1 a, T2 p)
{
return gamma_p_inv(a, p, policies::policy<>());
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
gamma_q_inv(T1 a, T2 p)
{
return gamma_q_inv(a, p, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP

View File

@@ -0,0 +1,768 @@
// Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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)
//
// This file implements the asymptotic expansions of the incomplete
// gamma functions P(a, x) and Q(a, x), used when a is large and
// x ~ a.
//
// The primary reference is:
//
// "The Asymptotic Expansion of the Incomplete Gamma Functions"
// N. M. Temme.
// Siam J. Math Anal. Vol 10 No 4, July 1979, p757.
//
// A different way of evaluating these expansions,
// plus a lot of very useful background information is in:
//
// "A Set of Algorithms For the Incomplete Gamma Functions."
// N. M. Temme.
// Probability in the Engineering and Informational Sciences,
// 8, 1994, 291.
//
// An alternative implementation is in:
//
// "Computation of the Incomplete Gamma Function Ratios and their Inverse."
// A. R. Didonato and A. H. Morris.
// ACM TOMS, Vol 12, No 4, Dec 1986, p377.
//
// There are various versions of the same code below, each accurate
// to a different precision. To understand the code, refer to Didonato
// and Morris, from Eq 17 and 18 onwards.
//
// The coefficients used here are not taken from Didonato and Morris:
// the domain over which these expansions are used is slightly different
// to theirs, and their constants are not quite accurate enough for
// 128-bit long double's. Instead the coefficients were calculated
// using the methods described by Temme p762 from Eq 3.8 onwards.
// The values obtained agree with those obtained by Didonato and Morris
// (at least to the first 30 digits that they provide).
// At double precision the degrees of polynomial required for full
// machine precision are close to those recomended to Didonato and Morris,
// but of course many more terms are needed for larger types.
//
#ifndef BOOST_MATH_DETAIL_IGAMMA_LARGE
#define BOOST_MATH_DETAIL_IGAMMA_LARGE
#ifdef _MSC_VER
#pragma once
#endif
namespace boost{ namespace math{ namespace detail{
// This version will never be called (at runtime), it's a stub used
// when T is unsuitable to be passed to these routines:
//
template <class T, class Policy>
inline T igamma_temme_large(T, T, const Policy& /* pol */, mpl::int_<0> const *)
{
// stub function, should never actually be called
BOOST_ASSERT(0);
return 0;
}
//
// This version is accurate for up to 64-bit mantissa's,
// (80-bit long double, or 10^-20).
//
template <class T, class Policy>
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<64> const *)
{
BOOST_MATH_STD_USING // ADL of std functions
T sigma = (x - a) / a;
T phi = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[13];
static const T C0[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0833333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0148148148148148148148),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00115740740740740740741),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000352733686067019400353),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0001787551440329218107),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.39192631785224377817e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.218544851067999216147e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.18540622107151599607e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.829671134095308600502e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.176659527368260793044e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.670785354340149858037e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.102618097842403080426e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.438203601845335318655e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.914769958223679023418e-9),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.255141939949462497669e-10),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.583077213255042506746e-10),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.243619480206674162437e-10),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.502766928011417558909e-11),
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00185185185185185185185),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00347222222222222222222),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00264550264550264550265),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000990226337448559670782),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000205761316872427983539),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.40187757201646090535e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.18098550334489977837e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.764916091608111008464e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.161209008945634460038e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.464712780280743434226e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.137863344691572095931e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.575254560351770496402e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.119516285997781473243e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.175432417197476476238e-10),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.100915437106004126275e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.416279299184258263623e-9),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.856390702649298063807e-10),
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00413359788359788359788),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00268132716049382716049),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000771604938271604938272),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.200938786008230452675e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000107366532263651605215),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.529234488291201254164e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.127606351886187277134e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.342357873409613807419e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.137219573090629332056e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.629899213838005502291e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.142806142060642417916e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.204770984219908660149e-9),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.140925299108675210533e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.622897408492202203356e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.136704883966171134993e-8),
};
workspace[2] = tools::evaluate_polynomial(C2, z);
static const T C3[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000649434156378600823045),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000229472093621399176955),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000469189494395255712128),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000267720632062838852962),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.756180167188397641073e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.239650511386729665193e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.110826541153473023615e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.56749528269915965675e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.142309007324358839146e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.278610802915281422406e-10),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.169584040919302772899e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.809946490538808236335e-7),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.191111684859736540607e-7),
};
workspace[3] = tools::evaluate_polynomial(C3, z);
static const T C4[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000861888290916711698605),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000784039221720066627474),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000299072480303190179733),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.146384525788434181781e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.664149821546512218666e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.396836504717943466443e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.113757269706784190981e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.250749722623753280165e-9),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.169541495365583060147e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.890750753220530968883e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.229293483400080487057e-6),
};
workspace[4] = tools::evaluate_polynomial(C4, z);
static const T C5[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000336798553366358150309),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.697281375836585777429e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000277275324495939207873),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000199325705161888477003),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.679778047793720783882e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.141906292064396701483e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.135940481897686932785e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.801847025633420153972e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.229148117650809517038e-5),
};
workspace[5] = tools::evaluate_polynomial(C5, z);
static const T C6[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000531307936463992223166),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000592166437353693882865),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000270878209671804482771),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.790235323266032787212e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.815396936756196875093e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.561168275310624965004e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.183291165828433755673e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.307961345060330478256e-8),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.346515536880360908674e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.20291327396058603727e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.57887928631490037089e-6),
};
workspace[6] = tools::evaluate_polynomial(C6, z);
static const T C7[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000344367606892377671254),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.517179090826059219337e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000334931610811422363117),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000281269515476323702274),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000109765822446847310235),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.127410090954844853795e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.277444515115636441571e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.182634888057113326614e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.578769494973505239894e-5),
};
workspace[7] = tools::evaluate_polynomial(C7, z);
static const T C8[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000652623918595309418922),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000839498720672087279993),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000438297098541721005061),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.696909145842055197137e-6),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000166448466420675478374),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000127835176797692185853),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.462995326369130429061e-4),
};
workspace[8] = tools::evaluate_polynomial(C8, z);
static const T C9[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000596761290192746250124),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.720489541602001055909e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000678230883766732836162),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0006401475260262758451),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000277501076343287044992),
};
workspace[9] = tools::evaluate_polynomial(C9, z);
static const T C10[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00133244544948006563713),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0019144384985654775265),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00110893691345966373396),
};
workspace[10] = tools::evaluate_polynomial(C10, z);
static const T C11[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00157972766073083495909),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.000162516262783915816899),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00206334210355432762645),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00213896861856890981541),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00101085593912630031708),
};
workspace[11] = tools::evaluate_polynomial(C11, z);
static const T C12[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00407251211951401664727),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00640336283380806979482),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00404101610816766177474),
};
workspace[12] = tools::evaluate_polynomial(C12, z);
T result = tools::evaluate_polynomial<13, T, T>(workspace, 1/a);
result *= exp(-y) / sqrt(2 * constants::pi<T>() * a);
if(x < a)
result = -result;
result += boost::math::erfc(sqrt(y), pol) / 2;
return result;
}
//
// This one is accurate for 53-bit mantissa's
// (IEEE double precision or 10^-17).
//
template <class T, class Policy>
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<53> const *)
{
BOOST_MATH_STD_USING // ADL of std functions
T sigma = (x - a) / a;
T phi = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[10];
static const T C0[] = {
static_cast<T>(-0.33333333333333333L),
static_cast<T>(0.083333333333333333L),
static_cast<T>(-0.014814814814814815L),
static_cast<T>(0.0011574074074074074L),
static_cast<T>(0.0003527336860670194L),
static_cast<T>(-0.00017875514403292181L),
static_cast<T>(0.39192631785224378e-4L),
static_cast<T>(-0.21854485106799922e-5L),
static_cast<T>(-0.185406221071516e-5L),
static_cast<T>(0.8296711340953086e-6L),
static_cast<T>(-0.17665952736826079e-6L),
static_cast<T>(0.67078535434014986e-8L),
static_cast<T>(0.10261809784240308e-7L),
static_cast<T>(-0.43820360184533532e-8L),
static_cast<T>(0.91476995822367902e-9L),
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
static_cast<T>(-0.0018518518518518519L),
static_cast<T>(-0.0034722222222222222L),
static_cast<T>(0.0026455026455026455L),
static_cast<T>(-0.00099022633744855967L),
static_cast<T>(0.00020576131687242798L),
static_cast<T>(-0.40187757201646091e-6L),
static_cast<T>(-0.18098550334489978e-4L),
static_cast<T>(0.76491609160811101e-5L),
static_cast<T>(-0.16120900894563446e-5L),
static_cast<T>(0.46471278028074343e-8L),
static_cast<T>(0.1378633446915721e-6L),
static_cast<T>(-0.5752545603517705e-7L),
static_cast<T>(0.11951628599778147e-7L),
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
static_cast<T>(0.0041335978835978836L),
static_cast<T>(-0.0026813271604938272L),
static_cast<T>(0.00077160493827160494L),
static_cast<T>(0.20093878600823045e-5L),
static_cast<T>(-0.00010736653226365161L),
static_cast<T>(0.52923448829120125e-4L),
static_cast<T>(-0.12760635188618728e-4L),
static_cast<T>(0.34235787340961381e-7L),
static_cast<T>(0.13721957309062933e-5L),
static_cast<T>(-0.6298992138380055e-6L),
static_cast<T>(0.14280614206064242e-6L),
};
workspace[2] = tools::evaluate_polynomial(C2, z);
static const T C3[] = {
static_cast<T>(0.00064943415637860082L),
static_cast<T>(0.00022947209362139918L),
static_cast<T>(-0.00046918949439525571L),
static_cast<T>(0.00026772063206283885L),
static_cast<T>(-0.75618016718839764e-4L),
static_cast<T>(-0.23965051138672967e-6L),
static_cast<T>(0.11082654115347302e-4L),
static_cast<T>(-0.56749528269915966e-5L),
static_cast<T>(0.14230900732435884e-5L),
};
workspace[3] = tools::evaluate_polynomial(C3, z);
static const T C4[] = {
static_cast<T>(-0.0008618882909167117L),
static_cast<T>(0.00078403922172006663L),
static_cast<T>(-0.00029907248030319018L),
static_cast<T>(-0.14638452578843418e-5L),
static_cast<T>(0.66414982154651222e-4L),
static_cast<T>(-0.39683650471794347e-4L),
static_cast<T>(0.11375726970678419e-4L),
};
workspace[4] = tools::evaluate_polynomial(C4, z);
static const T C5[] = {
static_cast<T>(-0.00033679855336635815L),
static_cast<T>(-0.69728137583658578e-4L),
static_cast<T>(0.00027727532449593921L),
static_cast<T>(-0.00019932570516188848L),
static_cast<T>(0.67977804779372078e-4L),
static_cast<T>(0.1419062920643967e-6L),
static_cast<T>(-0.13594048189768693e-4L),
static_cast<T>(0.80184702563342015e-5L),
static_cast<T>(-0.22914811765080952e-5L),
};
workspace[5] = tools::evaluate_polynomial(C5, z);
static const T C6[] = {
static_cast<T>(0.00053130793646399222L),
static_cast<T>(-0.00059216643735369388L),
static_cast<T>(0.00027087820967180448L),
static_cast<T>(0.79023532326603279e-6L),
static_cast<T>(-0.81539693675619688e-4L),
static_cast<T>(0.56116827531062497e-4L),
static_cast<T>(-0.18329116582843376e-4L),
};
workspace[6] = tools::evaluate_polynomial(C6, z);
static const T C7[] = {
static_cast<T>(0.00034436760689237767L),
static_cast<T>(0.51717909082605922e-4L),
static_cast<T>(-0.00033493161081142236L),
static_cast<T>(0.0002812695154763237L),
static_cast<T>(-0.00010976582244684731L),
};
workspace[7] = tools::evaluate_polynomial(C7, z);
static const T C8[] = {
static_cast<T>(-0.00065262391859530942L),
static_cast<T>(0.00083949872067208728L),
static_cast<T>(-0.00043829709854172101L),
};
workspace[8] = tools::evaluate_polynomial(C8, z);
workspace[9] = static_cast<T>(-0.00059676129019274625L);
T result = tools::evaluate_polynomial<10, T, T>(workspace, 1/a);
result *= exp(-y) / sqrt(2 * constants::pi<T>() * a);
if(x < a)
result = -result;
result += boost::math::erfc(sqrt(y), pol) / 2;
return result;
}
//
// This one is accurate for 24-bit mantissa's
// (IEEE float precision, or 10^-8)
//
template <class T, class Policy>
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<24> const *)
{
BOOST_MATH_STD_USING // ADL of std functions
T sigma = (x - a) / a;
T phi = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[3];
static const T C0[] = {
static_cast<T>(-0.333333333L),
static_cast<T>(0.0833333333L),
static_cast<T>(-0.0148148148L),
static_cast<T>(0.00115740741L),
static_cast<T>(0.000352733686L),
static_cast<T>(-0.000178755144L),
static_cast<T>(0.391926318e-4L),
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
static_cast<T>(-0.00185185185L),
static_cast<T>(-0.00347222222L),
static_cast<T>(0.00264550265L),
static_cast<T>(-0.000990226337L),
static_cast<T>(0.000205761317L),
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
static_cast<T>(0.00413359788L),
static_cast<T>(-0.00268132716L),
static_cast<T>(0.000771604938L),
};
workspace[2] = tools::evaluate_polynomial(C2, z);
T result = tools::evaluate_polynomial(workspace, 1/a);
result *= exp(-y) / sqrt(2 * constants::pi<T>() * a);
if(x < a)
result = -result;
result += boost::math::erfc(sqrt(y), pol) / 2;
return result;
}
//
// And finally, a version for 113-bit mantissa's
// (128-bit long doubles, or 10^-34).
// Note this one has been optimised for a > 200
// It's use for a < 200 is not recomended, that would
// require many more terms in the polynomials.
//
template <class T, class Policy>
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<113> const *)
{
BOOST_MATH_STD_USING // ADL of std functions
T sigma = (x - a) / a;
T phi = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[14];
static const T C0[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0833333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0148148148148148148148148148148148148),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00115740740740740740740740740740740741),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0003527336860670194003527336860670194),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000178755144032921810699588477366255144),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.391926317852243778169704095630021556e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.218544851067999216147364295512443661e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.185406221071515996070179883622956325e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.829671134095308600501624213166443227e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.17665952736826079304360054245742403e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.670785354340149858036939710029613572e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.102618097842403080425739573227252951e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.438203601845335318655297462244719123e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.914769958223679023418248817633113681e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.255141939949462497668779537993887013e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.583077213255042506746408945040035798e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.243619480206674162436940696707789943e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.502766928011417558909054985925744366e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.110043920319561347708374174497293411e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.337176326240098537882769884169200185e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.13923887224181620659193661848957998e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.285348938070474432039669099052828299e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.513911183424257261899064580300494205e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.197522882943494428353962401580710912e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.809952115670456133407115668702575255e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.165225312163981618191514820265351162e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.253054300974788842327061090060267385e-17),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.116869397385595765888230876507793475e-16),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.477003704982048475822167804084816597e-17),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.969912605905623712420709685898585354e-18),
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00185185185185185185185185185185185185),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00347222222222222222222222222222222222),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0026455026455026455026455026455026455),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000990226337448559670781893004115226337),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000205761316872427983539094650205761317),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.401877572016460905349794238683127572e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.180985503344899778370285914867533523e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.76491609160811100846374214980916921e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.16120900894563446003775221882217767e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.464712780280743434226135033938722401e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.137863344691572095931187533077488877e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.575254560351770496402194531835048307e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.119516285997781473243076536699698169e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.175432417197476476237547551202312502e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.100915437106004126274577504686681675e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.416279299184258263623372347219858628e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.856390702649298063807431562579670208e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.606721510160475861512701762169919581e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.716249896481148539007961017165545733e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.293318664377143711740636683615595403e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.599669636568368872330374527568788909e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.216717865273233141017100472779701734e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.497833997236926164052815522048108548e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.202916288237134247736694804325894226e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.413125571381061004935108332558187111e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.828651623988309644380188591057589316e-18),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.341003088693333279336339355910600992e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.138541953028939715357034547426313703e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.281234665322887466568860332727259483e-16),
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0041335978835978835978835978835978836),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00268132716049382716049382716049382716),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000771604938271604938271604938271604938),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.200938786008230452674897119341563786e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000107366532263651605215391223621676297),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.529234488291201254164217127180090143e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.127606351886187277133779191392360117e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.34235787340961380741902003904747389e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.137219573090629332055943852926020279e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.629899213838005502290672234278391876e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.142806142060642417915846008822771748e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.204770984219908660149195854409200226e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.140925299108675210532930244154315272e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.622897408492202203356394293530327112e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.136704883966171134992724380284402402e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.942835615901467819547711211663208075e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.128722524000893180595479368872770442e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.556459561343633211465414765894951439e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.119759355463669810035898150310311343e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.416897822518386350403836626692480096e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.109406404278845944099299008640802908e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.4662239946390135746326204922464679e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.990510576390690597844122258212382301e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.189318767683735145056885183170630169e-16),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.885922187259112726176031067028740667e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.373782039804640545306560251777191937e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.786883363903515525774088394065960751e-15),
};
workspace[2] = tools::evaluate_polynomial(C2, z);
static const T C3[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000649434156378600823045267489711934156),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000229472093621399176954732510288065844),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000469189494395255712128140111679206329),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000267720632062838852962309752433209223),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.756180167188397641072538191879755666e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.239650511386729665193314027333231723e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.110826541153473023614770299726861227e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.567495282699159656749963105701560205e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.14230900732435883914551894470580433e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.278610802915281422405802158211174452e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.16958404091930277289864168795820267e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.809946490538808236335278504852724081e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.191111684859736540606728140872727635e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.239286204398081179686413514022282056e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.206201318154887984369925818486654549e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.946049666185513217375417988510192814e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.215410497757749078380130268468744512e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.138882333681390304603424682490735291e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.218947616819639394064123400466489455e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.979099895117168512568262802255883368e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.217821918801809621153859472011393244e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.62088195734079014258166361684972205e-16),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.212697836327973697696702537114614471e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.934468879151743333127396765626749473e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.204536712267828493249215913063207436e-13),
};
workspace[3] = tools::evaluate_polynomial(C3, z);
static const T C4[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000861888290916711698604702719929057378),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00078403922172006662747403488144228885),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000299072480303190179733389609932819809),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.146384525788434181781232535690697556e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.664149821546512218665853782451862013e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.396836504717943466443123507595386882e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.113757269706784190980552042885831759e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.250749722623753280165221942390057007e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.169541495365583060147164356781525752e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.890750753220530968882898422505515924e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.229293483400080487057216364891158518e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.295679413754404904696572852500004588e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.288658297427087836297341274604184504e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.141897394378032193894774303903982717e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.344635804994648970659527720474194356e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.230245171745280671320192735850147087e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.394092330280464052750697640085291799e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.186023389685045019134258533045185639e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.435632300505661804380678327446262424e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.127860010162962312660550463349930726e-14),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.467927502665791946200382739991760062e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.214924647061348285410535341910721086e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.490881561480965216323649688463984082e-12),
};
workspace[4] = tools::evaluate_polynomial(C4, z);
static const T C5[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000336798553366358150308767592718210002),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.697281375836585777429398828575783308e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00027727532449593920787336425196507501),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000199325705161888477003360405280844238),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.679778047793720783881640176604435742e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.141906292064396701483392727105575757e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.135940481897686932784583938837504469e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.80184702563342015397192571980419684e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.229148117650809517038048790128781806e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.325247355129845395166230137750005047e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.346528464910852649559195496827579815e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.184471871911713432765322367374920978e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.482409670378941807563762631738989002e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.179894667217435153025754291716644314e-13),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.630619450001352343517516981425944698e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.316241762877456793773762181540969623e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.784092425369742929000839303523267545e-9),
};
workspace[5] = tools::evaluate_polynomial(C5, z);
static const T C6[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00053130793646399222316574854297762391),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000592166437353693882864836225604401187),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000270878209671804482771279183488328692),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.790235323266032787212032944390816666e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.815396936756196875092890088464682624e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.561168275310624965003775619041471695e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.183291165828433755673259749374098313e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.307961345060330478256414192546677006e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.346515536880360908673728529745376913e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.202913273960586037269527254582695285e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.578879286314900370889997586203187687e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.233863067382665698933480579231637609e-12),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.88286007463304835250508524317926246e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.474359588804081278032150770595852426e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.125454150207103824457130611214783073e-7),
};
workspace[6] = tools::evaluate_polynomial(C6, z);
static const T C7[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000344367606892377671254279625108523655),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.517179090826059219337057843002058823e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000334931610811422363116635090580012327),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000281269515476323702273722110707777978),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000109765822446847310235396824500789005),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.127410090954844853794579954588107623e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.277444515115636441570715073933712622e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.182634888057113326614324442681892723e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.578769494973505239894178121070843383e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.493875893393627039981813418398565502e-9),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.105953670140260427338098566209633945e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.616671437611040747858836254004890765e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.175629733590604619378669693914265388e-6),
};
workspace[7] = tools::evaluate_polynomial(C7, z);
static const T C8[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000652623918595309418922034919726622692),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000839498720672087279993357516764983445),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000438297098541721005061087953050560377),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.696909145842055197136911097362072702e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00016644846642067547837384572662326101),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000127835176797692185853344001461664247),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.462995326369130429061361032704489636e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.455790986792270771162749294232219616e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.105952711258051954718238500312872328e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.678334290486516662273073740749269432e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.210754766662588042469972680229376445e-5),
};
workspace[8] = tools::evaluate_polynomial(C8, z);
static const T C9[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000596761290192746250124390067179459605),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.720489541602001055908571930225015052e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000678230883766732836161951166000673426),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000640147526026275845100045652582354779),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000277501076343287044992374518205845463),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.181970083804651510461686554030325202e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.847950711706850318239732559632810086e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.610519208250153101764709122740859458e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.210739201834048624082975255893773306e-4),
};
workspace[9] = tools::evaluate_polynomial(C9, z);
static const T C10[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00133244544948006563712694993432717968),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00191443849856547752650089885832852254),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0011089369134596637339607446329267522),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.993240412264229896742295262075817566e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000508745012930931989848393025305956774),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00042735056665392884328432271160040444),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.000168588537679107988033552814662382059),
};
workspace[10] = tools::evaluate_polynomial(C10, z);
static const T C11[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00157972766073083495908785631307733022),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000162516262783915816898635123980270998),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00206334210355432762645284467690276817),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00213896861856890981541061922797693947),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00101085593912630031708085801712479376),
};
workspace[11] = tools::evaluate_polynomial(C11, z);
static const T C12[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00407251211951401664727281097914544601),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00640336283380806979482363809026579583),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00404101610816766177473974858518094879),
};
workspace[12] = tools::evaluate_polynomial(C12, z);
workspace[13] = -0.0059475779383993002845382844736066323L;
T result = tools::evaluate_polynomial(workspace, T(1/a));
result *= exp(-y) / sqrt(2 * constants::pi<T>() * a);
if(x < a)
result = -result;
result += boost::math::erfc(sqrt(y), pol) / 2;
return result;
}
} // namespace detail
} // namespace math
} // namespace math
#endif // BOOST_MATH_DETAIL_IGAMMA_LARGE

View File

@@ -0,0 +1,134 @@
// Copyright Paul A. Bristow 2017.
// 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)
// I:/modular-boost/libs/math/include/boost/math/special_functions/lambert_w_lookup_table.ipp
// A collection of 128-bit precision integral z argument Lambert W values computed using 37 decimal digits precision.
// C++ floating-point precision is 128-bit long double.
// Output as 53 decimal digits, suffixed L.
// C++ floating-point type is provided by lambert_w.hpp typedef.
// For example: typedef lookup_t double; (or float or long double)
// Written by I:\modular-boost\libs\math\test\lambert_w_lookup_table_generator.cpp Thu Jan 25 16:52:07 2018
// Sizes of arrays of z values for Lambert W[0], W[1] ... W[64]" and W[-1], W[-2] ... W[-64].
namespace boost {
namespace math {
namespace lambert_w_detail {
namespace lambert_w_lookup
{
BOOST_STATIC_CONSTEXPR std::size_t noof_sqrts = 12;
BOOST_STATIC_CONSTEXPR std::size_t noof_halves = 12;
BOOST_STATIC_CONSTEXPR std::size_t noof_w0es = 65;
BOOST_STATIC_CONSTEXPR std::size_t noof_w0zs = 65;
BOOST_STATIC_CONSTEXPR std::size_t noof_wm1es = 64;
BOOST_STATIC_CONSTEXPR std::size_t noof_wm1zs = 64;
BOOST_STATIC_CONSTEXPR lookup_t halves[noof_halves] =
{ // Common to Lambert W0 and W-1 (and exactly representable).
0.5L, 0.25L, 0.125L, 0.0625L, 0.03125L, 0.015625L, 0.0078125L, 0.00390625L, 0.001953125L, 0.0009765625L, 0.00048828125L, 0.000244140625L
}; // halves, 0.5, 0.25, ... 0.000244140625, common to W0 and W-1.
BOOST_STATIC_CONSTEXPR lookup_t sqrtw0s[noof_sqrts] =
{ // For Lambert W0 only.
0.6065306597126334242631173765403218567L, 0.77880078307140486866846070009071995L, 0.882496902584595403104717592968701829L, 0.9394130628134757862473572557999761753L, 0.9692332344763440819139583751755278177L, 0.9844964370054084060204319075254540376L, 0.9922179382602435121227899136829802692L, 0.996101369470117490071323985506950379L, 0.9980487811074754727142805899944244847L, 0.9990239141819756622368328253791383317L, 0.9995118379398893653889967919448497792L, 0.9997558891748972165136242351259789505L
}; // sqrtw0s
BOOST_STATIC_CONSTEXPR lookup_t sqrtwm1s[noof_sqrts] =
{ // For Lambert W-1 only.
1.648721270700128146848650787814163572L, 1.284025416687741484073420568062436458L, 1.133148453066826316829007227811793873L, 1.064494458917859429563390594642889673L, 1.031743407499102670938747815281507144L, 1.015747708586685747458535072082351749L, 1.007843097206447977693453559760123579L, 1.003913889338347573443609603903460282L, 1.001955033591002812046518898047477216L, 1.000977039492416535242845292611606506L, 1.000488400478694473126173623807163354L, 1.000244170429747854937005233924135774L
}; // sqrtwm1s
BOOST_STATIC_CONSTEXPR lookup_t w0es[noof_w0zs] =
{ // Fukushima e powers array e[0] = 2.718, 1., e[2] = e^-1 = 0.135, e[3] = e^-2 = 0.133 ... e[64] = 4.3596100000630809736231248158884615452e-28.
2.7182818284590452353602874713526624978e+00L,
1.0000000000000000000000000000000000000e+00L, 3.6787944117144232159552377016146086745e-01L, 1.3533528323661269189399949497248440341e-01L, 4.9787068367863942979342415650061776632e-02L,
1.8315638888734180293718021273241242212e-02L, 6.7379469990854670966360484231484242488e-03L, 2.4787521766663584230451674308166678915e-03L, 9.1188196555451620800313608440928262647e-04L,
3.3546262790251183882138912578086101931e-04L, 1.2340980408667954949763669073003382607e-04L, 4.5399929762484851535591515560550610238e-05L, 1.6701700790245659312635517360580879078e-05L,
6.1442123533282097586823081788055323112e-06L, 2.2603294069810543257852772905386894694e-06L, 8.3152871910356788406398514256526229461e-07L, 3.0590232050182578837147949770228963937e-07L,
1.1253517471925911451377517906012719164e-07L, 4.1399377187851666596510277189552806229e-08L, 1.5229979744712628436136629233517431862e-08L, 5.6027964375372675400129828162064630798e-09L,
2.0611536224385578279659403801558209764e-09L, 7.5825604279119067279417432412681264430e-10L, 2.7894680928689248077189130306442932077e-10L, 1.0261879631701890303927527840612497760e-10L,
3.7751345442790977516449695475234067792e-11L, 1.3887943864964020594661763746086856910e-11L, 5.1090890280633247198744001934792157666e-12L, 1.8795288165390832947582704184221926212e-12L,
6.9144001069402030094125846587414092712e-13L, 2.5436656473769229103033856148576816666e-13L, 9.3576229688401746049158322233787067450e-14L, 3.4424771084699764583923893328515572846e-14L,
1.2664165549094175723120904155965096382e-14L, 4.6588861451033973641842455436101684114e-15L, 1.7139084315420129663027203425760492412e-15L, 6.3051167601469893856390211922465427614e-16L,
2.3195228302435693883122636097380800411e-16L, 8.5330476257440657942780498229412441658e-17L, 3.1391327920480296287089646522319196491e-17L, 1.1548224173015785986262442063323868655e-17L,
4.2483542552915889953292347828586580179e-18L, 1.5628821893349887680908829951058341550e-18L, 5.7495222642935598066643808805734234249e-19L, 2.1151310375910804866314010070226514702e-19L,
7.7811322411337965157133167292798981918e-20L, 2.8625185805493936444701216291839372068e-20L, 1.0530617357553812378763324449428108806e-20L, 3.8739976286871871129314774972691278293e-21L,
1.4251640827409351062853210280340602263e-21L, 5.2428856633634639371718053028323436716e-22L, 1.9287498479639177830173428165270125748e-22L, 7.0954741622847041389832693878080734877e-23L,
2.6102790696677048047026953153318648093e-23L, 9.6026800545086760302307696700074909076e-24L, 3.5326285722008070297353928101772088374e-24L, 1.2995814250075030736007134060714855303e-24L,
4.7808928838854690812771770423179628939e-25L, 1.7587922024243116489558751288034363178e-25L, 6.4702349256454603261540395529264893765e-26L, 2.3802664086944006058943245888024963309e-26L,
8.7565107626965203384887328007391660366e-27L, 3.2213402859925160890012477758489437534e-27L, 1.1850648642339810062850307390972809891e-27L, 4.3596100000630809736231248158884596428e-28L,
}; // w0es
BOOST_STATIC_CONSTEXPR lookup_t w0zs[noof_w0zs] =
{ // z values for W[0], W[1], W[2] ... W[64] (Fukushima array Fk).
0.0000000000000000000000000000000000000e+00L,
2.7182818284590452353602874713526624978e+00L, 1.4778112197861300454460854921150015626e+01L, 6.0256610769563003222785588963745153691e+01L, 2.1839260013257695631244104481144351361e+02L,
7.4206579551288301710557790020276139812e+02L, 2.4205727609564107356503230832603296776e+03L, 7.6764321089992101948460416680168500271e+03L, 2.3847663896333826197948736795623109390e+04L,
7.2927755348178456069389970204894839685e+04L, 2.2026465794806716516957900645284244366e+05L, 6.5861555886717600300859134371483559776e+05L, 1.9530574970280470496960624587818413980e+06L,
5.7513740961159665432393360873381476632e+06L, 1.6836459978306874888489314790750032292e+07L, 4.9035260587081659589527825691375819733e+07L, 1.4217776832812596218820837985250320561e+08L,
4.1063419681078006965118239806655900596e+08L, 1.1818794444719492004981570586630806042e+09L, 3.3911637183005579560532906419857313738e+09L, 9.7033039081958055593821366108308111737e+09L,
2.7695130424147508641409976558651358487e+10L, 7.8868082614895014356985518811525255163e+10L, 2.2413047926372475980079655175092843139e+11L, 6.3573893111624333505933989166748517618e+11L,
1.8001224834346468131040337866531539479e+12L, 5.0889698451498078710141863447784789126e+12L, 1.4365302496248562650461177217211790925e+13L, 4.0495197800161304862957327843914007993e+13L,
1.1400869461717722015726999684446230289e+14L, 3.2059423744573386440971405952224204950e+14L, 9.0051433962267018216365614546207459567e+14L, 2.5268147258457822451512967243234631750e+15L,
7.0832381329352301326018261305316090522e+15L, 1.9837699245933465967698692976753294646e+16L, 5.5510470830970075484537561902113104381e+16L, 1.5520433569614702817608320254284931407e+17L,
4.3360826779369661842459877227403719730e+17L, 1.2105254067703227363724895246493485480e+18L, 3.3771426165357561311906703760513324357e+18L, 9.4154106734807994163159964299613921804e+18L,
2.6233583234732252918129199544138403574e+19L, 7.3049547543861043990576614751671879498e+19L, 2.0329709713386190214340167519800405595e+20L, 5.6547040503180956413560918381429636734e+20L,
1.5720421975868292906615658755032744790e+21L, 4.3682149334771264822761478593874428627e+21L, 1.2132170565093316762294432610117848880e+22L, 3.3680332378068632345542636794533635462e+22L,
9.3459982052259884835729892206738573922e+22L, 2.5923527642935362320437266614667426924e+23L, 7.1876803203773878618909930893087860822e+23L, 1.9921241603726199616378561653688236827e+24L,
5.5192924995054165325072406547517121131e+24L, 1.5286067837683347062387143159276002521e+25L, 4.2321318958281094260005100745711666956e+25L, 1.1713293177672778461879598480402173158e+26L,
3.2408603996214813669049988277609543829e+26L, 8.9641258264226027960478448084812796397e+26L, 2.4787141382364034104243901241243054434e+27L, 6.8520443388941057019777430988685937812e+27L,
1.8936217407781711443114787060753312270e+28L, 5.2317811346197017832254642778313331353e+28L, 1.4450833904658542238325922893692265683e+29L, 3.9904954117194348050619127737142206367e+29L
}; // w0zs
BOOST_STATIC_CONSTEXPR lookup_t wm1es[noof_wm1es] =
{ // Fukushima e array e[0] = e^1 = 2.718, e[1] = e^2 = 7.39 ... e[64] = 4.60718e+28.
2.7182818284590452353602874713526624978e+00L,
7.3890560989306502272304274605750078132e+00L, 2.0085536923187667740928529654581717897e+01L, 5.4598150033144239078110261202860878403e+01L, 1.4841315910257660342111558004055227962e+02L,
4.0342879349273512260838718054338827961e+02L, 1.0966331584284585992637202382881214324e+03L, 2.9809579870417282747435920994528886738e+03L, 8.1030839275753840077099966894327599650e+03L,
2.2026465794806716516957900645284244366e+04L, 5.9874141715197818455326485792257781614e+04L, 1.6275479141900392080800520489848678317e+05L, 4.4241339200892050332610277594908828178e+05L,
1.2026042841647767777492367707678594494e+06L, 3.2690173724721106393018550460917213155e+06L, 8.8861105205078726367630237407814503508e+06L, 2.4154952753575298214775435180385823880e+07L,
6.5659969137330511138786503259060033569e+07L, 1.7848230096318726084491003378872270388e+08L, 4.8516519540979027796910683054154055868e+08L, 1.3188157344832146972099988837453027851e+09L,
3.5849128461315915616811599459784206892e+09L, 9.7448034462489026000346326848229752776e+09L, 2.6489122129843472294139162152811882341e+10L, 7.2004899337385872524161351466126157915e+10L,
1.9572960942883876426977639787609534279e+11L, 5.3204824060179861668374730434117744166e+11L, 1.4462570642914751736770474229969288569e+12L, 3.9313342971440420743886205808435276858e+12L,
1.0686474581524462146990468650741401650e+13L, 2.9048849665247425231085682111679825667e+13L, 7.8962960182680695160978022635108224220e+13L, 2.1464357978591606462429776153126088037e+14L,
5.8346174252745488140290273461039101900e+14L, 1.5860134523134307281296446257746601252e+15L, 4.3112315471151952271134222928569253908e+15L, 1.1719142372802611308772939791190194522e+16L,
3.1855931757113756220328671701298646000e+16L, 8.6593400423993746953606932719264934250e+16L, 2.3538526683701998540789991074903480451e+17L, 6.3984349353005494922266340351557081888e+17L,
1.7392749415205010473946813036112352261e+18L, 4.7278394682293465614744575627442803708e+18L, 1.2851600114359308275809299632143099258e+19L, 3.4934271057485095348034797233406099533e+19L,
9.4961194206024488745133649117118323102e+19L, 2.5813128861900673962328580021527338043e+20L, 7.0167359120976317386547159988611740546e+20L, 1.9073465724950996905250998409538484474e+21L,
5.1847055285870724640874533229334853848e+21L, 1.4093490824269387964492143312370168789e+22L, 3.8310080007165768493035695487861993899e+22L, 1.0413759433029087797183472933493796440e+23L,
2.8307533032746939004420635480140745409e+23L, 7.6947852651420171381827455901293939921e+23L, 2.0916594960129961539070711572146737782e+24L, 5.6857199993359322226403488206332533034e+24L,
1.5455389355901039303530766911174620068e+25L, 4.2012104037905142549565934307191617684e+25L, 1.1420073898156842836629571831447656302e+26L, 3.1042979357019199087073421411071003721e+26L,
8.4383566687414544890733294803731179601e+26L, 2.2937831594696098790993528402686136005e+27L, 6.2351490808116168829092387089284697448e+27L
}; // wm1es
BOOST_STATIC_CONSTEXPR lookup_t wm1zs[noof_wm1zs] =
{ // Fukushima G array of z values for integral K, (Fukushima Gk) g[0] (k = -1) = 1 ... g[64] = -1.0264389699511303e-26.
-3.6787944117144232159552377016146086745e-01L,
-2.7067056647322538378799898994496880682e-01L, -1.4936120510359182893802724695018532990e-01L, -7.3262555554936721174872085092964968848e-02L, -3.3689734995427335483180242115742121244e-02L,
-1.4872513059998150538271004584900007349e-02L, -6.3831737588816134560219525908649783853e-03L, -2.6837010232200947105711130062468881545e-03L, -1.1106882367801159454787302165703044346e-03L,
-4.5399929762484851535591515560550610238e-04L, -1.8371870869270225243899069096638966986e-04L, -7.3730548239938517104187698145666387735e-05L, -2.9384282290753706235208604777002963102e-05L,
-1.1641402067449950376895791995913672125e-05L, -4.5885348075273868255721924655343445906e-06L, -1.8005627955081458322204028649620350662e-06L, -7.0378941219347833214067471222239770590e-07L,
-2.7413963540482731185045932620331377352e-07L, -1.0645313231320808326024667350792279852e-07L, -4.1223072448771156559318807603116419528e-08L, -1.5923376898615004128677660806663065530e-08L,
-6.1368298043116345769816086674174450569e-09L, -2.3602323152914347699033314033408744848e-09L, -9.0603229062698346039479269140561762700e-10L, -3.4719859662410051486654409365217142276e-10L,
-1.3283631472964644271673440503045960993e-10L, -5.0747278046555248958473301297399200773e-11L, -1.9360320299432568426355237044475945959e-11L, -7.3766303773930764398798182830872768331e-12L,
-2.8072868906520523814747496670136120235e-12L, -1.0671679036256927021016406931839827582e-12L, -4.0525329757101362313986893299088308423e-13L, -1.5374324278841211301808010293913555758e-13L,
-5.8272886672428440854292491647585674200e-14L, -2.2067908660514462849736574172862899665e-14L, -8.3502821888768497979241489950570881481e-15L, -3.1572276215253043438828784344882603413e-15L,
-1.1928704609782512589094065678481294667e-15L, -4.5038074274761565346423524046963087756e-16L, -1.6993417021166355981316939131434632072e-16L, -6.4078169762734539491726202799339200356e-17L,
-2.4147993510032951187990399698408378385e-17L, -9.0950634616416460925150243301974013218e-18L, -3.4236981860988704669138593608831552044e-18L, -1.2881333612472271400115547331327717431e-18L,
-4.8440839844747536942311292467369300505e-19L, -1.8207788854829779430777944237164900798e-19L, -6.8407875971564885101695409345634890862e-20L, -2.5690139750480973292141845983878483991e-20L,
-9.6437492398195889150867140826350628738e-21L, -3.6186918227651991108814673877821174787e-21L, -1.3573451162272064984454015639725697008e-21L, -5.0894204288895982960223079251039701810e-22L,
-1.9076194289884357960571121174956927722e-22L, -7.1476978375412669048039237333931704166e-23L, -2.6773000149758626855152191436980592206e-23L, -1.0025115553818576399048488234179587012e-23L,
-3.7527362568743669891693429406973638384e-24L, -1.4043571811296963574776515073934728352e-24L, -5.2539064576179122030932396804434996219e-25L, -1.9650175744554348142907611432678556896e-25L,
-7.3474021582506822389671905824031421322e-26L, -2.7465543000397410133825686340097295749e-26L, -1.0264389699511282259046957018510946438e-26L
}; // wm1zs
} // namespace lambert_w_lookup
} // namespace detail
} // namespace math
} // namespace boost

View File

@@ -0,0 +1,220 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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_SPECIAL_FUNCTIONS_LANCZOS_SSE2
#define BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS_SSE2
#ifdef _MSC_VER
#pragma once
#endif
#include <emmintrin.h>
#if defined(__GNUC__) || defined(__PGI) || defined(__SUNPRO_CC)
#define ALIGN16 __attribute__((__aligned__(16)))
#else
#define ALIGN16 __declspec(align(16))
#endif
namespace boost{ namespace math{ namespace lanczos{
template <>
inline double lanczos13m53::lanczos_sum<double>(const double& x)
{
static const ALIGN16 double coeff[26] = {
static_cast<double>(2.506628274631000270164908177133837338626L),
static_cast<double>(1u),
static_cast<double>(210.8242777515793458725097339207133627117L),
static_cast<double>(66u),
static_cast<double>(8071.672002365816210638002902272250613822L),
static_cast<double>(1925u),
static_cast<double>(186056.2653952234950402949897160456992822L),
static_cast<double>(32670u),
static_cast<double>(2876370.628935372441225409051620849613599L),
static_cast<double>(357423u),
static_cast<double>(31426415.58540019438061423162831820536287L),
static_cast<double>(2637558u),
static_cast<double>(248874557.8620541565114603864132294232163L),
static_cast<double>(13339535u),
static_cast<double>(1439720407.311721673663223072794912393972L),
static_cast<double>(45995730u),
static_cast<double>(6039542586.35202800506429164430729792107L),
static_cast<double>(105258076u),
static_cast<double>(17921034426.03720969991975575445893111267L),
static_cast<double>(150917976u),
static_cast<double>(35711959237.35566804944018545154716670596L),
static_cast<double>(120543840u),
static_cast<double>(42919803642.64909876895789904700198885093L),
static_cast<double>(39916800u),
static_cast<double>(23531376880.41075968857200767445163675473L),
static_cast<double>(0u)
};
__m128d vx = _mm_load1_pd(&x);
__m128d sum_even = _mm_load_pd(coeff);
__m128d sum_odd = _mm_load_pd(coeff+2);
__m128d nc_odd, nc_even;
__m128d vx2 = _mm_mul_pd(vx, vx);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 4);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 6);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 8);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 10);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 12);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 14);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 16);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 18);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 20);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 22);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 24);
sum_odd = _mm_mul_pd(sum_odd, vx);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_even = _mm_add_pd(sum_even, sum_odd);
double ALIGN16 t[2];
_mm_store_pd(t, sum_even);
return t[0] / t[1];
}
template <>
inline double lanczos13m53::lanczos_sum_expG_scaled<double>(const double& x)
{
static const ALIGN16 double coeff[26] = {
static_cast<double>(0.006061842346248906525783753964555936883222L),
static_cast<double>(1u),
static_cast<double>(0.5098416655656676188125178644804694509993L),
static_cast<double>(66u),
static_cast<double>(19.51992788247617482847860966235652136208L),
static_cast<double>(1925u),
static_cast<double>(449.9445569063168119446858607650988409623L),
static_cast<double>(32670u),
static_cast<double>(6955.999602515376140356310115515198987526L),
static_cast<double>(357423u),
static_cast<double>(75999.29304014542649875303443598909137092L),
static_cast<double>(2637558u),
static_cast<double>(601859.6171681098786670226533699352302507L),
static_cast<double>(13339535u),
static_cast<double>(3481712.15498064590882071018964774556468L),
static_cast<double>(45995730u),
static_cast<double>(14605578.08768506808414169982791359218571L),
static_cast<double>(105258076u),
static_cast<double>(43338889.32467613834773723740590533316085L),
static_cast<double>(150917976u),
static_cast<double>(86363131.28813859145546927288977868422342L),
static_cast<double>(120543840u),
static_cast<double>(103794043.1163445451906271053616070238554L),
static_cast<double>(39916800u),
static_cast<double>(56906521.91347156388090791033559122686859L),
static_cast<double>(0u)
};
__m128d vx = _mm_load1_pd(&x);
__m128d sum_even = _mm_load_pd(coeff);
__m128d sum_odd = _mm_load_pd(coeff+2);
__m128d nc_odd, nc_even;
__m128d vx2 = _mm_mul_pd(vx, vx);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 4);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 6);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 8);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 10);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 12);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 14);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 16);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 18);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 20);
sum_odd = _mm_mul_pd(sum_odd, vx2);
nc_odd = _mm_load_pd(coeff + 22);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_odd = _mm_add_pd(sum_odd, nc_odd);
sum_even = _mm_mul_pd(sum_even, vx2);
nc_even = _mm_load_pd(coeff + 24);
sum_odd = _mm_mul_pd(sum_odd, vx);
sum_even = _mm_add_pd(sum_even, nc_even);
sum_even = _mm_add_pd(sum_even, sum_odd);
double ALIGN16 t[2];
_mm_store_pd(t, sum_even);
return t[0] / t[1];
}
#ifdef _MSC_VER
BOOST_STATIC_ASSERT(sizeof(double) == sizeof(long double));
template <>
inline long double lanczos13m53::lanczos_sum<long double>(const long double& x)
{
return lanczos_sum<double>(static_cast<double>(x));
}
template <>
inline long double lanczos13m53::lanczos_sum_expG_scaled<long double>(const long double& x)
{
return lanczos_sum_expG_scaled<double>(static_cast<double>(x));
}
#endif
} // namespace lanczos
} // namespace math
} // namespace boost
#undef ALIGN16
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS

View File

@@ -0,0 +1,522 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
#define BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/big_constant.hpp>
namespace boost{ namespace math{ namespace detail{
//
// These need forward declaring to keep GCC happy:
//
template <class T, class Policy, class Lanczos>
T gamma_imp(T z, const Policy& pol, const Lanczos& l);
template <class T, class Policy>
T gamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos& l);
//
// lgamma for small arguments:
//
template <class T, class Policy, class Lanczos>
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<64>&, const Policy& /* l */, const Lanczos&)
{
// This version uses rational approximations for small
// values of z accurate enough for 64-bit mantissas
// (80-bit long doubles), works well for 53-bit doubles as well.
// Lanczos is only used to select the Lanczos function.
BOOST_MATH_STD_USING // for ADL of std names
T result = 0;
if(z < tools::epsilon<T>())
{
result = -log(z);
}
else if((zm1 == 0) || (zm2 == 0))
{
// nothing to do, result is zero....
}
else if(z > 2)
{
//
// Begin by performing argument reduction until
// z is in [2,3):
//
if(z >= 3)
{
do
{
z -= 1;
zm2 -= 1;
result += log(z);
}while(z >= 3);
// Update zm2, we need it below:
zm2 = z - 2;
}
//
// Use the following form:
//
// lgamma(z) = (z-2)(z+1)(Y + R(z-2))
//
// where R(z-2) is a rational approximation optimised for
// low absolute error - as long as it's absolute error
// is small compared to the constant Y - then any rounding
// error in it's computation will get wiped out.
//
// R(z-2) has the following properties:
//
// At double: Max error found: 4.231e-18
// At long double: Max error found: 1.987e-21
// Maximum Deviation Found (approximation error): 5.900e-24
//
static const T P[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.180355685678449379109e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.25126649619989678683e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.494103151567532234274e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.172491608709613993966e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.259453563205438108893e-3)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.541009869215204396339e-3)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.324588649825948492091e-4))
};
static const T Q[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.1e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.196202987197795200688e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.148019669424231326694e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.541391432071720958364e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.988504251128010129477e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.82130967464889339326e-2)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.224936291922115757597e-3)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.223352763208617092964e-6))
};
static const float Y = 0.158963680267333984375e0f;
T r = zm2 * (z + 1);
T R = tools::evaluate_polynomial(P, zm2);
R /= tools::evaluate_polynomial(Q, zm2);
result += r * Y + r * R;
}
else
{
//
// If z is less than 1 use recurrance to shift to
// z in the interval [1,2]:
//
if(z < 1)
{
result += -log(z);
zm2 = zm1;
zm1 = z;
z += 1;
}
//
// Two approximations, on for z in [1,1.5] and
// one for z in [1.5,2]:
//
if(z <= 1.5)
{
//
// Use the following form:
//
// lgamma(z) = (z-1)(z-2)(Y + R(z-1))
//
// where R(z-1) is a rational approximation optimised for
// low absolute error - as long as it's absolute error
// is small compared to the constant Y - then any rounding
// error in it's computation will get wiped out.
//
// R(z-1) has the following properties:
//
// At double precision: Max error found: 1.230011e-17
// At 80-bit long double precision: Max error found: 5.631355e-21
// Maximum Deviation Found: 3.139e-021
// Expected Error Term: 3.139e-021
//
static const float Y = 0.52815341949462890625f;
static const T P[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.490622454069039543534e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.969117530159521214579e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.414983358359495381969e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.406567124211938417342e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.158413586390692192217e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.240149820648571559892e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.100346687696279557415e-2))
};
static const T Q[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.1e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.302349829846463038743e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.348739585360723852576e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.191415588274426679201e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.507137738614363510846e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.577039722690451849648e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.195768102601107189171e-2))
};
T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1);
T prefix = zm1 * zm2;
result += prefix * Y + prefix * r;
}
else
{
//
// Use the following form:
//
// lgamma(z) = (2-z)(1-z)(Y + R(2-z))
//
// where R(2-z) is a rational approximation optimised for
// low absolute error - as long as it's absolute error
// is small compared to the constant Y - then any rounding
// error in it's computation will get wiped out.
//
// R(2-z) has the following properties:
//
// At double precision, max error found: 1.797565e-17
// At 80-bit long double precision, max error found: 9.306419e-21
// Maximum Deviation Found: 2.151e-021
// Expected Error Term: 2.150e-021
//
static const float Y = 0.452017307281494140625f;
static const T P[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.292329721830270012337e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.144216267757192309184e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.142440390738631274135e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.542809694055053558157e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.850535976868336437746e-2)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.431171342679297331241e-3))
};
static const T Q[] = {
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.1e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.150169356054485044494e1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.846973248876495016101e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.220095151814995745555e0)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.25582797155975869989e-1)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.100666795539143372762e-2)),
static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.827193521891290553639e-6))
};
T r = zm2 * zm1;
T R = tools::evaluate_polynomial(P, T(-zm2)) / tools::evaluate_polynomial(Q, T(-zm2));
result += r * Y + r * R;
}
}
return result;
}
template <class T, class Policy, class Lanczos>
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<113>&, const Policy& /* l */, const Lanczos&)
{
//
// This version uses rational approximations for small
// values of z accurate enough for 113-bit mantissas
// (128-bit long doubles).
//
BOOST_MATH_STD_USING // for ADL of std names
T result = 0;
if(z < tools::epsilon<T>())
{
result = -log(z);
BOOST_MATH_INSTRUMENT_CODE(result);
}
else if((zm1 == 0) || (zm2 == 0))
{
// nothing to do, result is zero....
}
else if(z > 2)
{
//
// Begin by performing argument reduction until
// z is in [2,3):
//
if(z >= 3)
{
do
{
z -= 1;
result += log(z);
}while(z >= 3);
zm2 = z - 2;
}
BOOST_MATH_INSTRUMENT_CODE(zm2);
BOOST_MATH_INSTRUMENT_CODE(z);
BOOST_MATH_INSTRUMENT_CODE(result);
//
// Use the following form:
//
// lgamma(z) = (z-2)(z+1)(Y + R(z-2))
//
// where R(z-2) is a rational approximation optimised for
// low absolute error - as long as it's absolute error
// is small compared to the constant Y - then any rounding
// error in it's computation will get wiped out.
//
// Maximum Deviation Found (approximation error) 3.73e-37
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.018035568567844937910504030027467476655),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.013841458273109517271750705401202404195),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.062031842739486600078866923383017722399),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.052518418329052161202007865149435256093),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.01881718142472784129191838493267755758),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0025104830367021839316463675028524702846),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00021043176101831873281848891452678568311),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00010249622350908722793327719494037981166),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.11381479670982006841716879074288176994e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.49999811718089980992888533630523892389e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.70529798686542184668416911331718963364e-8)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.5877485070422317542808137697939233685),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.8797959228352591788629602533153837126),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.8030885955284082026405495275461180977),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.69774331297747390169238306148355428436),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.17261566063277623942044077039756583802),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.02729301254544230229429621192443000121),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0026776425891195270663133581960016620433),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00015244249160486584591370355730402168106),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.43997034032479866020546814475414346627e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.46295080708455613044541885534408170934e-7),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.93326638207459533682980757982834180952e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.42316456553164995177177407325292867513e-13)
};
T R = tools::evaluate_polynomial(P, zm2);
R /= tools::evaluate_polynomial(Q, zm2);
static const float Y = 0.158963680267333984375F;
T r = zm2 * (z + 1);
result += r * Y + r * R;
BOOST_MATH_INSTRUMENT_CODE(result);
}
else
{
//
// If z is less than 1 use recurrance to shift to
// z in the interval [1,2]:
//
if(z < 1)
{
result += -log(z);
zm2 = zm1;
zm1 = z;
z += 1;
}
BOOST_MATH_INSTRUMENT_CODE(result);
BOOST_MATH_INSTRUMENT_CODE(z);
BOOST_MATH_INSTRUMENT_CODE(zm2);
//
// Three approximations, on for z in [1,1.35], [1.35,1.625] and [1.625,1]
//
if(z <= 1.35)
{
//
// Use the following form:
//
// lgamma(z) = (z-1)(z-2)(Y + R(z-1))
//
// where R(z-1) is a rational approximation optimised for
// low absolute error - as long as it's absolute error
// is small compared to the constant Y - then any rounding
// error in it's computation will get wiped out.
//
// R(z-1) has the following properties:
//
// Maximum Deviation Found (approximation error) 1.659e-36
// Expected Error Term (theoretical error) 1.343e-36
// Max error found at 128-bit long double precision 1.007e-35
//
static const float Y = 0.54076099395751953125f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.036454670944013329356512090082402429697),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.066235835556476033710068679907798799959),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.67492399795577182387312206593595565371),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.4345555263962411429855341651960000166),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.4894319559821365820516771951249649563),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.87210277668067964629483299712322411566),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.29602090537771744401524080430529369136),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0561832587517836908929331992218879676),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0053236785487328044334381502530383140443),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00018629360291358130461736386077971890789),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.10164985672213178500790406939467614498e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.13680157145361387405588201461036338274e-8)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.9106336261005990534095838574132225599),
BOOST_MATH_BIG_CONSTANT(T, 113, 10.258804800866438510889341082793078432),
BOOST_MATH_BIG_CONSTANT(T, 113, 11.88588976846826108836629960537466889),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.3455000546999704314454891036700998428),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.6428823682421746343233362007194282703),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.97465989807254572142266753052776132252),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.15121052897097822172763084966793352524),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.012017363555383555123769849654484594893),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0003583032812720649835431669893011257277)
};
T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1);
T prefix = zm1 * zm2;
result += prefix * Y + prefix * r;
BOOST_MATH_INSTRUMENT_CODE(result);
}
else if(z <= 1.625)
{
//
// Use the following form:
//
// lgamma(z) = (2-z)(1-z)(Y + R(2-z))
//
// where R(2-z) is a rational approximation optimised for
// low absolute error - as long as it's absolute error
// is small compared to the constant Y - then any rounding
// error in it's computation will get wiped out.
//
// R(2-z) has the following properties:
//
// Max error found at 128-bit long double precision 9.634e-36
// Maximum Deviation Found (approximation error) 1.538e-37
// Expected Error Term (theoretical error) 2.350e-38
//
static const float Y = 0.483787059783935546875f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.017977422421608624353488126610933005432),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.18484528905298309555089509029244135703),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.40401251514859546989565001431430884082),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.40277179799147356461954182877921388182),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.21993421441282936476709677700477598816),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.069595742223850248095697771331107571011),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.012681481427699686635516772923547347328),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0012489322866834830413292771335113136034),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.57058739515423112045108068834668269608e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.8207548771933585614380644961342925976e-6)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.9629552288944259229543137757200262073),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.7118380799042118987185957298964772755),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.5569815272165399297600586376727357187),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0546764918220835097855665680632153367),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.26574021300894401276478730940980810831),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.03996289731752081380552901986471233462),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0033398680924544836817826046380586480873),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00013288854760548251757651556792598235735),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.17194794958274081373243161848194745111e-5)
};
T r = zm2 * zm1;
T R = tools::evaluate_polynomial(P, T(0.625 - zm1)) / tools::evaluate_polynomial(Q, T(0.625 - zm1));
result += r * Y + r * R;
BOOST_MATH_INSTRUMENT_CODE(result);
}
else
{
//
// Same form as above.
//
// Max error found (at 128-bit long double precision) 1.831e-35
// Maximum Deviation Found (approximation error) 8.588e-36
// Expected Error Term (theoretical error) 1.458e-36
//
static const float Y = 0.443811893463134765625f;
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.021027558364667626231512090082402429494),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.15128811104498736604523586803722368377),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.26249631480066246699388544451126410278),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.21148748610533489823742352180628489742),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.093964130697489071999873506148104370633),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.024292059227009051652542804957550866827),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0036284453226534839926304745756906117066),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0002939230129315195346843036254392485984),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.11088589183158123733132268042570710338e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.13240510580220763969511741896361984162e-6)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, -2.4240003754444040525462170802796471996),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.4868383476933178722203278602342786002),
BOOST_MATH_BIG_CONSTANT(T, 113, -1.4047068395206343375520721509193698547),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.47583809087867443858344765659065773369),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.09865724264554556400463655444270700132),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.012238223514176587501074150988445109735),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00084625068418239194670614419707491797097),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.2796574430456237061420839429225710602e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.30202973883316730694433702165188835331e-6)
};
// (2 - x) * (1 - x) * (c + R(2 - x))
T r = zm2 * zm1;
T R = tools::evaluate_polynomial(P, T(-zm2)) / tools::evaluate_polynomial(Q, T(-zm2));
result += r * Y + r * R;
BOOST_MATH_INSTRUMENT_CODE(result);
}
}
BOOST_MATH_INSTRUMENT_CODE(result);
return result;
}
template <class T, class Policy, class Lanczos>
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<0>&, const Policy& pol, const Lanczos&)
{
//
// No rational approximations are available because either
// T has no numeric_limits support (so we can't tell how
// many digits it has), or T has more digits than we know
// what to do with.... we do have a Lanczos approximation
// though, and that can be used to keep errors under control.
//
BOOST_MATH_STD_USING // for ADL of std names
T result = 0;
if(z < tools::epsilon<T>())
{
result = -log(z);
}
else if(z < 0.5)
{
// taking the log of tgamma reduces the error, no danger of overflow here:
result = log(gamma_imp(z, pol, Lanczos()));
}
else if(z >= 3)
{
// taking the log of tgamma reduces the error, no danger of overflow here:
result = log(gamma_imp(z, pol, Lanczos()));
}
else if(z >= 1.5)
{
// special case near 2:
T dz = zm2;
result = dz * log((z + Lanczos::g() - T(0.5)) / boost::math::constants::e<T>());
result += boost::math::log1p(dz / (Lanczos::g() + T(1.5)), pol) * T(1.5);
result += boost::math::log1p(Lanczos::lanczos_sum_near_2(dz), pol);
}
else
{
// special case near 1:
T dz = zm1;
result = dz * log((z + Lanczos::g() - T(0.5)) / boost::math::constants::e<T>());
result += boost::math::log1p(dz / (Lanczos::g() + T(0.5)), pol) / 2;
result += boost::math::log1p(Lanczos::lanczos_sum_near_1(dz), pol);
}
return result;
}
}}} // namespaces
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL

View File

@@ -0,0 +1,558 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2013 Nikhar Agrawal
// Copyright 2013 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2013 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_POLYGAMMA_DETAIL_2013_07_30_HPP_
#define _BOOST_POLYGAMMA_DETAIL_2013_07_30_HPP_
#include <cmath>
#include <limits>
#include <boost/cstdint.hpp>
#include <boost/math/policies/policy.hpp>
#include <boost/math/special_functions/bernoulli.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/special_functions/zeta.hpp>
#include <boost/math/special_functions/digamma.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
#include <boost/math/special_functions/pow.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/int.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_convertible.hpp>
#ifdef _MSC_VER
#pragma once
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#endif
namespace boost { namespace math { namespace detail{
template<class T, class Policy>
T polygamma_atinfinityplus(const int n, const T& x, const Policy& pol, const char* function) // for large values of x such as for x> 400
{
// See http://functions.wolfram.com/GammaBetaErf/PolyGamma2/06/02/0001/
BOOST_MATH_STD_USING
//
// sum == current value of accumulated sum.
// term == value of current term to be added to sum.
// part_term == value of current term excluding the Bernoulli number part
//
if(n + x == x)
{
// x is crazy large, just concentrate on the first part of the expression and use logs:
if(n == 1) return 1 / x;
T nlx = n * log(x);
if((nlx < tools::log_max_value<T>()) && (n < (int)max_factorial<T>::value))
return ((n & 1) ? 1 : -1) * boost::math::factorial<T>(n - 1) * pow(x, -n);
else
return ((n & 1) ? 1 : -1) * exp(boost::math::lgamma(T(n), pol) - n * log(x));
}
T term, sum, part_term;
T x_squared = x * x;
//
// Start by setting part_term to:
//
// (n-1)! / x^(n+1)
//
// which is common to both the first term of the series (with k = 1)
// and to the leading part.
// We can then get to the leading term by:
//
// part_term * (n + 2 * x) / 2
//
// and to the first term in the series
// (excluding the Bernoulli number) by:
//
// part_term n * (n + 1) / (2x)
//
// If either the factorial would overflow,
// or the power term underflows, this just gets set to 0 and then we
// know that we have to use logs for the initial terms:
//
part_term = ((n > (int)boost::math::max_factorial<T>::value) && (T(n) * n > tools::log_max_value<T>()))
? T(0) : static_cast<T>(boost::math::factorial<T>(n - 1, pol) * pow(x, -n - 1));
if(part_term == 0)
{
// Either n is very large, or the power term underflows,
// set the initial values of part_term, term and sum via logs:
part_term = static_cast<T>(boost::math::lgamma(n, pol) - (n + 1) * log(x));
sum = exp(part_term + log(n + 2 * x) - boost::math::constants::ln_two<T>());
part_term += log(T(n) * (n + 1)) - boost::math::constants::ln_two<T>() - log(x);
part_term = exp(part_term);
}
else
{
sum = part_term * (n + 2 * x) / 2;
part_term *= (T(n) * (n + 1)) / 2;
part_term /= x;
}
//
// If the leading term is 0, so is the result:
//
if(sum == 0)
return sum;
for(unsigned k = 1;;)
{
term = part_term * boost::math::bernoulli_b2n<T>(k, pol);
sum += term;
//
// Normal termination condition:
//
if(fabs(term / sum) < tools::epsilon<T>())
break;
//
// Increment our counter, and move part_term on to the next value:
//
++k;
part_term *= T(n + 2 * k - 2) * (n - 1 + 2 * k);
part_term /= (2 * k - 1) * 2 * k;
part_term /= x_squared;
//
// Emergency get out termination condition:
//
if(k > policies::get_max_series_iterations<Policy>())
{
return policies::raise_evaluation_error(function, "Series did not converge, closest value was %1%", sum, pol);
}
}
if((n - 1) & 1)
sum = -sum;
return sum;
}
template<class T, class Policy>
T polygamma_attransitionplus(const int n, const T& x, const Policy& pol, const char* function)
{
// See: http://functions.wolfram.com/GammaBetaErf/PolyGamma2/16/01/01/0017/
// Use N = (0.4 * digits) + (4 * n) for target value for x:
BOOST_MATH_STD_USING
const int d4d = static_cast<int>(0.4F * policies::digits_base10<T, Policy>());
const int N = d4d + (4 * n);
const int m = n;
const int iter = N - itrunc(x);
if(iter > (int)policies::get_max_series_iterations<Policy>())
return policies::raise_evaluation_error<T>(function, ("Exceeded maximum series evaluations evaluating at n = " + boost::lexical_cast<std::string>(n) + " and x = %1%").c_str(), x, pol);
const int minus_m_minus_one = -m - 1;
T z(x);
T sum0(0);
T z_plus_k_pow_minus_m_minus_one(0);
// Forward recursion to larger x, need to check for overflow first though:
if(log(z + iter) * minus_m_minus_one > -tools::log_max_value<T>())
{
for(int k = 1; k <= iter; ++k)
{
z_plus_k_pow_minus_m_minus_one = pow(z, minus_m_minus_one);
sum0 += z_plus_k_pow_minus_m_minus_one;
z += 1;
}
sum0 *= boost::math::factorial<T>(n);
}
else
{
for(int k = 1; k <= iter; ++k)
{
T log_term = log(z) * minus_m_minus_one + boost::math::lgamma(T(n + 1), pol);
sum0 += exp(log_term);
z += 1;
}
}
if((n - 1) & 1)
sum0 = -sum0;
return sum0 + polygamma_atinfinityplus(n, z, pol, function);
}
template <class T, class Policy>
T polygamma_nearzero(int n, T x, const Policy& pol, const char* function)
{
BOOST_MATH_STD_USING
//
// If we take this expansion for polygamma: http://functions.wolfram.com/06.15.06.0003.02
// and substitute in this expression for polygamma(n, 1): http://functions.wolfram.com/06.15.03.0009.01
// we get an alternating series for polygamma when x is small in terms of zeta functions of
// integer arguments (which are easy to evaluate, at least when the integer is even).
//
// In order to avoid spurious overflow, save the n! term for later, and rescale at the end:
//
T scale = boost::math::factorial<T>(n, pol);
//
// "factorial_part" contains everything except the zeta function
// evaluations in each term:
//
T factorial_part = 1;
//
// "prefix" is what we'll be adding the accumulated sum to, it will
// be n! / z^(n+1), but since we're scaling by n! it's just
// 1 / z^(n+1) for now:
//
T prefix = pow(x, n + 1);
if(prefix == 0)
return boost::math::policies::raise_overflow_error<T>(function, 0, pol);
prefix = 1 / prefix;
//
// First term in the series is necessarily < zeta(2) < 2, so
// ignore the sum if it will have no effect on the result anyway:
//
if(prefix > 2 / policies::get_epsilon<T, Policy>())
return ((n & 1) ? 1 : -1) *
(tools::max_value<T>() / prefix < scale ? policies::raise_overflow_error<T>(function, 0, pol) : prefix * scale);
//
// As this is an alternating series we could accelerate it using
// "Convergence Acceleration of Alternating Series",
// Henri Cohen, Fernando Rodriguez Villegas, and Don Zagier, Experimental Mathematics, 1999.
// In practice however, it appears not to make any difference to the number of terms
// required except in some edge cases which are filtered out anyway before we get here.
//
T sum = prefix;
for(unsigned k = 0;;)
{
// Get the k'th term:
T term = factorial_part * boost::math::zeta(T(k + n + 1), pol);
sum += term;
// Termination condition:
if(fabs(term) < fabs(sum * boost::math::policies::get_epsilon<T, Policy>()))
break;
//
// Move on k and factorial_part:
//
++k;
factorial_part *= (-x * (n + k)) / k;
//
// Last chance exit:
//
if(k > policies::get_max_series_iterations<Policy>())
return policies::raise_evaluation_error<T>(function, "Series did not converge, best value is %1%", sum, pol);
}
//
// We need to multiply by the scale, at each stage checking for oveflow:
//
if(boost::math::tools::max_value<T>() / scale < sum)
return boost::math::policies::raise_overflow_error<T>(function, 0, pol);
sum *= scale;
return n & 1 ? sum : T(-sum);
}
//
// Helper function which figures out which slot our coefficient is in
// given an angle multiplier for the cosine term of power:
//
template <class Table>
typename Table::value_type::reference dereference_table(Table& table, unsigned row, unsigned power)
{
return table[row][power / 2];
}
template <class T, class Policy>
T poly_cot_pi(int n, T x, T xc, const Policy& pol, const char* function)
{
BOOST_MATH_STD_USING
// Return n'th derivative of cot(pi*x) at x, these are simply
// tabulated for up to n = 9, beyond that it is possible to
// calculate coefficients as follows:
//
// The general form of each derivative is:
//
// pi^n * SUM{k=0, n} C[k,n] * cos^k(pi * x) * csc^(n+1)(pi * x)
//
// With constant C[0,1] = -1 and all other C[k,n] = 0;
// Then for each k < n+1:
// C[k-1, n+1] -= k * C[k, n];
// C[k+1, n+1] += (k-n-1) * C[k, n];
//
// Note that there are many different ways of representing this derivative thanks to
// the many trigomonetric identies available. In particular, the sum of powers of
// cosines could be replaced by a sum of cosine multiple angles, and indeed if you
// plug the derivative into Mathematica this is the form it will give. The two
// forms are related via the Chebeshev polynomials of the first kind and
// T_n(cos(x)) = cos(n x). The polynomial form has the great advantage that
// all the cosine terms are zero at half integer arguments - right where this
// function has it's minumum - thus avoiding cancellation error in this region.
//
// And finally, since every other term in the polynomials is zero, we can save
// space by only storing the non-zero terms. This greatly complexifies
// subscripting the tables in the calculation, but halves the storage space
// (and complexity for that matter).
//
T s = fabs(x) < fabs(xc) ? boost::math::sin_pi(x, pol) : boost::math::sin_pi(xc, pol);
T c = boost::math::cos_pi(x, pol);
switch(n)
{
case 1:
return -constants::pi<T, Policy>() / (s * s);
case 2:
{
return 2 * constants::pi<T, Policy>() * constants::pi<T, Policy>() * c / boost::math::pow<3>(s, pol);
}
case 3:
{
int P[] = { -2, -4 };
return boost::math::pow<3>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<4>(s, pol);
}
case 4:
{
int P[] = { 16, 8 };
return boost::math::pow<4>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<5>(s, pol);
}
case 5:
{
int P[] = { -16, -88, -16 };
return boost::math::pow<5>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<6>(s, pol);
}
case 6:
{
int P[] = { 272, 416, 32 };
return boost::math::pow<6>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<7>(s, pol);
}
case 7:
{
int P[] = { -272, -2880, -1824, -64 };
return boost::math::pow<7>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<8>(s, pol);
}
case 8:
{
int P[] = { 7936, 24576, 7680, 128 };
return boost::math::pow<8>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<9>(s, pol);
}
case 9:
{
int P[] = { -7936, -137216, -185856, -31616, -256 };
return boost::math::pow<9>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<10>(s, pol);
}
case 10:
{
int P[] = { 353792, 1841152, 1304832, 128512, 512 };
return boost::math::pow<10>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<11>(s, pol);
}
case 11:
{
int P[] = { -353792, -9061376, -21253376, -8728576, -518656, -1024};
return boost::math::pow<11>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<12>(s, pol);
}
case 12:
{
int P[] = { 22368256, 175627264, 222398464, 56520704, 2084864, 2048 };
return boost::math::pow<12>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<13>(s, pol);
}
#ifndef BOOST_NO_LONG_LONG
case 13:
{
long long P[] = { -22368256LL, -795300864LL, -2868264960LL, -2174832640LL, -357888000LL, -8361984LL, -4096 };
return boost::math::pow<13>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<14>(s, pol);
}
case 14:
{
long long P[] = { 1903757312LL, 21016670208LL, 41731645440LL, 20261765120LL, 2230947840LL, 33497088LL, 8192 };
return boost::math::pow<14>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<15>(s, pol);
}
case 15:
{
long long P[] = { -1903757312LL, -89702612992LL, -460858269696LL, -559148810240LL, -182172651520LL, -13754155008LL, -134094848LL, -16384 };
return boost::math::pow<15>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<16>(s, pol);
}
case 16:
{
long long P[] = { 209865342976LL, 3099269660672LL, 8885192097792LL, 7048869314560LL, 1594922762240LL, 84134068224LL, 536608768LL, 32768 };
return boost::math::pow<16>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<17>(s, pol);
}
case 17:
{
long long P[] = { -209865342976LL, -12655654469632LL, -87815735738368LL, -155964390375424LL, -84842998005760LL, -13684856848384LL, -511780323328LL, -2146926592LL, -65536 };
return boost::math::pow<17>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<18>(s, pol);
}
case 18:
{
long long P[] = { 29088885112832LL, 553753414467584LL, 2165206642589696LL, 2550316668551168LL, 985278548541440LL, 115620218667008LL, 3100738912256LL, 8588754944LL, 131072 };
return boost::math::pow<18>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<19>(s, pol);
}
case 19:
{
long long P[] = { -29088885112832LL, -2184860175433728LL, -19686087844429824LL, -48165109676113920LL, -39471306959486976LL, -11124607890751488LL, -965271355195392LL, -18733264797696LL, -34357248000LL, -262144 };
return boost::math::pow<19>(constants::pi<T, Policy>(), pol) * tools::evaluate_even_polynomial(P, c) / boost::math::pow<20>(s, pol);
}
case 20:
{
long long P[] = { 4951498053124096LL, 118071834535526400LL, 603968063567560704LL, 990081991141490688LL, 584901762421358592LL, 122829335169859584LL, 7984436548730880LL, 112949304754176LL, 137433710592LL, 524288 };
return boost::math::pow<20>(constants::pi<T, Policy>(), pol) * c * tools::evaluate_even_polynomial(P, c) / boost::math::pow<21>(s, pol);
}
#endif
}
//
// We'll have to compute the coefficients up to n,
// complexity is O(n^2) which we don't worry about for now
// as the values are computed once and then cached.
// However, if the final evaluation would have too many
// terms just bail out right away:
//
if((unsigned)n / 2u > policies::get_max_series_iterations<Policy>())
return policies::raise_evaluation_error<T>(function, "The value of n is so large that we're unable to compute the result in reasonable time, best guess is %1%", 0, pol);
#ifdef BOOST_HAS_THREADS
static boost::detail::lightweight_mutex m;
boost::detail::lightweight_mutex::scoped_lock l(m);
#endif
static int digits = tools::digits<T>();
static std::vector<std::vector<T> > table(1, std::vector<T>(1, T(-1)));
int current_digits = tools::digits<T>();
if(digits != current_digits)
{
// Oh my... our precision has changed!
table = std::vector<std::vector<T> >(1, std::vector<T>(1, T(-1)));
digits = current_digits;
}
int index = n - 1;
if(index >= (int)table.size())
{
for(int i = (int)table.size() - 1; i < index; ++i)
{
int offset = i & 1; // 1 if the first cos power is 0, otherwise 0.
int sin_order = i + 2; // order of the sin term
int max_cos_order = sin_order - 1; // largest order of the polynomial of cos terms
int max_columns = (max_cos_order - offset) / 2; // How many entries there are in the current row.
int next_offset = offset ? 0 : 1;
int next_max_columns = (max_cos_order + 1 - next_offset) / 2; // How many entries there will be in the next row
table.push_back(std::vector<T>(next_max_columns + 1, T(0)));
for(int column = 0; column <= max_columns; ++column)
{
int cos_order = 2 * column + offset; // order of the cosine term in entry "column"
BOOST_ASSERT(column < (int)table[i].size());
BOOST_ASSERT((cos_order + 1) / 2 < (int)table[i + 1].size());
table[i + 1][(cos_order + 1) / 2] += ((cos_order - sin_order) * table[i][column]) / (sin_order - 1);
if(cos_order)
table[i + 1][(cos_order - 1) / 2] += (-cos_order * table[i][column]) / (sin_order - 1);
}
}
}
T sum = boost::math::tools::evaluate_even_polynomial(&table[index][0], c, table[index].size());
if(index & 1)
sum *= c; // First coeffient is order 1, and really an odd polynomial.
if(sum == 0)
return sum;
//
// The remaining terms are computed using logs since the powers and factorials
// get real large real quick:
//
T power_terms = n * log(boost::math::constants::pi<T>());
if(s == 0)
return sum * boost::math::policies::raise_overflow_error<T>(function, 0, pol);
power_terms -= log(fabs(s)) * (n + 1);
power_terms += boost::math::lgamma(T(n));
power_terms += log(fabs(sum));
if(power_terms > boost::math::tools::log_max_value<T>())
return sum * boost::math::policies::raise_overflow_error<T>(function, 0, pol);
return exp(power_terms) * ((s < 0) && ((n + 1) & 1) ? -1 : 1) * boost::math::sign(sum);
}
template <class T, class Policy>
struct polygamma_initializer
{
struct init
{
init()
{
// Forces initialization of our table of coefficients and mutex:
boost::math::polygamma(30, T(-2.5f), Policy());
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename polygamma_initializer<T, Policy>::init polygamma_initializer<T, Policy>::initializer;
template<class T, class Policy>
inline T polygamma_imp(const int n, T x, const Policy &pol)
{
BOOST_MATH_STD_USING
static const char* function = "boost::math::polygamma<%1%>(int, %1%)";
polygamma_initializer<T, Policy>::initializer.force_instantiate();
if(n < 0)
return policies::raise_domain_error<T>(function, "Order must be >= 0, but got %1%", static_cast<T>(n), pol);
if(x < 0)
{
if(floor(x) == x)
{
//
// Result is infinity if x is odd, and a pole error if x is even.
//
if(lltrunc(x) & 1)
return policies::raise_overflow_error<T>(function, 0, pol);
else
return policies::raise_pole_error<T>(function, "Evaluation at negative integer %1%", x, pol);
}
T z = 1 - x;
T result = polygamma_imp(n, z, pol) + constants::pi<T, Policy>() * poly_cot_pi(n, z, x, pol, function);
return n & 1 ? T(-result) : result;
}
//
// Limit for use of small-x-series is chosen
// so that the series doesn't go too divergent
// in the first few terms. Ordinarily this
// would mean setting the limit to ~ 1 / n,
// but we can tolerate a small amount of divergence:
//
T small_x_limit = (std::min)(T(T(5) / n), T(0.25f));
if(x < small_x_limit)
{
return polygamma_nearzero(n, x, pol, function);
}
else if(x > 0.4F * policies::digits_base10<T, Policy>() + 4.0f * n)
{
return polygamma_atinfinityplus(n, x, pol, function);
}
else if(x == 1)
{
return (n & 1 ? 1 : -1) * boost::math::factorial<T>(n, pol) * boost::math::zeta(T(n + 1), pol);
}
else if(x == 0.5f)
{
T result = (n & 1 ? 1 : -1) * boost::math::factorial<T>(n, pol) * boost::math::zeta(T(n + 1), pol);
if(fabs(result) >= ldexp(tools::max_value<T>(), -n - 1))
return boost::math::sign(result) * policies::raise_overflow_error<T>(function, 0, pol);
result *= ldexp(T(1), n + 1) - 1;
return result;
}
else
{
return polygamma_attransitionplus(n, x, pol, function);
}
}
} } } // namespace boost::math::detail
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // _BOOST_POLYGAMMA_DETAIL_2013_07_30_HPP_

View File

@@ -0,0 +1,93 @@
// Copyright John Maddock 2008.
// Use, modification and distribution are subject to 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_SPECIAL_ROUND_FWD_HPP
#define BOOST_MATH_SPECIAL_ROUND_FWD_HPP
#include <boost/config.hpp>
#include <boost/math/tools/promotion.hpp>
#ifdef _MSC_VER
#pragma once
#endif
namespace boost
{
namespace math
{
template <class T, class Policy>
typename tools::promote_args<T>::type trunc(const T& v, const Policy& pol);
template <class T>
typename tools::promote_args<T>::type trunc(const T& v);
template <class T, class Policy>
int itrunc(const T& v, const Policy& pol);
template <class T>
int itrunc(const T& v);
template <class T, class Policy>
long ltrunc(const T& v, const Policy& pol);
template <class T>
long ltrunc(const T& v);
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
boost::long_long_type lltrunc(const T& v, const Policy& pol);
template <class T>
boost::long_long_type lltrunc(const T& v);
#endif
template <class T, class Policy>
typename tools::promote_args<T>::type round(const T& v, const Policy& pol);
template <class T>
typename tools::promote_args<T>::type round(const T& v);
template <class T, class Policy>
int iround(const T& v, const Policy& pol);
template <class T>
int iround(const T& v);
template <class T, class Policy>
long lround(const T& v, const Policy& pol);
template <class T>
long lround(const T& v);
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
boost::long_long_type llround(const T& v, const Policy& pol);
template <class T>
boost::long_long_type llround(const T& v);
#endif
template <class T, class Policy>
T modf(const T& v, T* ipart, const Policy& pol);
template <class T>
T modf(const T& v, T* ipart);
template <class T, class Policy>
T modf(const T& v, int* ipart, const Policy& pol);
template <class T>
T modf(const T& v, int* ipart);
template <class T, class Policy>
T modf(const T& v, long* ipart, const Policy& pol);
template <class T>
T modf(const T& v, long* ipart);
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
T modf(const T& v, boost::long_long_type* ipart, const Policy& pol);
template <class T>
T modf(const T& v, boost::long_long_type* ipart);
#endif
}
}
#undef BOOST_MATH_STD_USING
#define BOOST_MATH_STD_USING BOOST_MATH_STD_USING_CORE\
using boost::math::round;\
using boost::math::iround;\
using boost::math::lround;\
using boost::math::trunc;\
using boost::math::itrunc;\
using boost::math::ltrunc;\
using boost::math::modf;
#endif // BOOST_MATH_SPECIAL_ROUND_FWD_HPP

View File

@@ -0,0 +1,549 @@
// Copyright John Maddock 2007.
// Copyright Paul A. Bristow 2007
// Use, modification and distribution are subject to 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_SF_DETAIL_INV_T_HPP
#define BOOST_MATH_SF_DETAIL_INV_T_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/cbrt.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/trunc.hpp>
namespace boost{ namespace math{ namespace detail{
//
// The main method used is due to Hill:
//
// G. W. Hill, Algorithm 396, Student's t-Quantiles,
// Communications of the ACM, 13(10): 619-620, Oct., 1970.
//
template <class T, class Policy>
T inverse_students_t_hill(T ndf, T u, const Policy& pol)
{
BOOST_MATH_STD_USING
BOOST_ASSERT(u <= 0.5);
T a, b, c, d, q, x, y;
if (ndf > 1e20f)
return -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
a = 1 / (ndf - 0.5f);
b = 48 / (a * a);
c = ((20700 * a / b - 98) * a - 16) * a + 96.36f;
d = ((94.5f / (b + c) - 3) / b + 1) * sqrt(a * constants::pi<T>() / 2) * ndf;
y = pow(d * 2 * u, 2 / ndf);
if (y > (0.05f + a))
{
//
// Asymptotic inverse expansion about normal:
//
x = -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
y = x * x;
if (ndf < 5)
c += 0.3f * (ndf - 4.5f) * (x + 0.6f);
c += (((0.05f * d * x - 5) * x - 7) * x - 2) * x + b;
y = (((((0.4f * y + 6.3f) * y + 36) * y + 94.5f) / c - y - 3) / b + 1) * x;
y = boost::math::expm1(a * y * y, pol);
}
else
{
y = static_cast<T>(((1 / (((ndf + 6) / (ndf * y) - 0.089f * d - 0.822f)
* (ndf + 2) * 3) + 0.5 / (ndf + 4)) * y - 1)
* (ndf + 1) / (ndf + 2) + 1 / y);
}
q = sqrt(ndf * y);
return -q;
}
//
// Tail and body series are due to Shaw:
//
// www.mth.kcl.ac.uk/~shaww/web_page/papers/Tdistribution06.pdf
//
// Shaw, W.T., 2006, "Sampling Student's T distribution - use of
// the inverse cumulative distribution function."
// Journal of Computational Finance, Vol 9 Issue 4, pp 37-73, Summer 2006
//
template <class T, class Policy>
T inverse_students_t_tail_series(T df, T v, const Policy& pol)
{
BOOST_MATH_STD_USING
// Tail series expansion, see section 6 of Shaw's paper.
// w is calculated using Eq 60:
T w = boost::math::tgamma_delta_ratio(df / 2, constants::half<T>(), pol)
* sqrt(df * constants::pi<T>()) * v;
// define some variables:
T np2 = df + 2;
T np4 = df + 4;
T np6 = df + 6;
//
// Calculate the coefficients d(k), these depend only on the
// number of degrees of freedom df, so at least in theory
// we could tabulate these for fixed df, see p15 of Shaw:
//
T d[7] = { 1, };
d[1] = -(df + 1) / (2 * np2);
np2 *= (df + 2);
d[2] = -df * (df + 1) * (df + 3) / (8 * np2 * np4);
np2 *= df + 2;
d[3] = -df * (df + 1) * (df + 5) * (((3 * df) + 7) * df -2) / (48 * np2 * np4 * np6);
np2 *= (df + 2);
np4 *= (df + 4);
d[4] = -df * (df + 1) * (df + 7) *
( (((((15 * df) + 154) * df + 465) * df + 286) * df - 336) * df + 64 )
/ (384 * np2 * np4 * np6 * (df + 8));
np2 *= (df + 2);
d[5] = -df * (df + 1) * (df + 3) * (df + 9)
* (((((((35 * df + 452) * df + 1573) * df + 600) * df - 2020) * df) + 928) * df -128)
/ (1280 * np2 * np4 * np6 * (df + 8) * (df + 10));
np2 *= (df + 2);
np4 *= (df + 4);
np6 *= (df + 6);
d[6] = -df * (df + 1) * (df + 11)
* ((((((((((((945 * df) + 31506) * df + 425858) * df + 2980236) * df + 11266745) * df + 20675018) * df + 7747124) * df - 22574632) * df - 8565600) * df + 18108416) * df - 7099392) * df + 884736)
/ (46080 * np2 * np4 * np6 * (df + 8) * (df + 10) * (df +12));
//
// Now bring everthing together to provide the result,
// this is Eq 62 of Shaw:
//
T rn = sqrt(df);
T div = pow(rn * w, 1 / df);
T power = div * div;
T result = tools::evaluate_polynomial<7, T, T>(d, power);
result *= rn;
result /= div;
return -result;
}
template <class T, class Policy>
T inverse_students_t_body_series(T df, T u, const Policy& pol)
{
BOOST_MATH_STD_USING
//
// Body series for small N:
//
// Start with Eq 56 of Shaw:
//
T v = boost::math::tgamma_delta_ratio(df / 2, constants::half<T>(), pol)
* sqrt(df * constants::pi<T>()) * (u - constants::half<T>());
//
// Workspace for the polynomial coefficients:
//
T c[11] = { 0, 1, };
//
// Figure out what the coefficients are, note these depend
// only on the degrees of freedom (Eq 57 of Shaw):
//
T in = 1 / df;
c[2] = static_cast<T>(0.16666666666666666667 + 0.16666666666666666667 * in);
c[3] = static_cast<T>((0.0083333333333333333333 * in
+ 0.066666666666666666667) * in
+ 0.058333333333333333333);
c[4] = static_cast<T>(((0.00019841269841269841270 * in
+ 0.0017857142857142857143) * in
+ 0.026785714285714285714) * in
+ 0.025198412698412698413);
c[5] = static_cast<T>((((2.7557319223985890653e-6 * in
+ 0.00037477954144620811287) * in
- 0.0011078042328042328042) * in
+ 0.010559964726631393298) * in
+ 0.012039792768959435626);
c[6] = static_cast<T>(((((2.5052108385441718775e-8 * in
- 0.000062705427288760622094) * in
+ 0.00059458674042007375341) * in
- 0.0016095979637646304313) * in
+ 0.0061039211560044893378) * in
+ 0.0038370059724226390893);
c[7] = static_cast<T>((((((1.6059043836821614599e-10 * in
+ 0.000015401265401265401265) * in
- 0.00016376804137220803887) * in
+ 0.00069084207973096861986) * in
- 0.0012579159844784844785) * in
+ 0.0010898206731540064873) * in
+ 0.0032177478835464946576);
c[8] = static_cast<T>(((((((7.6471637318198164759e-13 * in
- 3.9851014346715404916e-6) * in
+ 0.000049255746366361445727) * in
- 0.00024947258047043099953) * in
+ 0.00064513046951456342991) * in
- 0.00076245135440323932387) * in
+ 0.000033530976880017885309) * in
+ 0.0017438262298340009980);
c[9] = static_cast<T>((((((((2.8114572543455207632e-15 * in
+ 1.0914179173496789432e-6) * in
- 0.000015303004486655377567) * in
+ 0.000090867107935219902229) * in
- 0.00029133414466938067350) * in
+ 0.00051406605788341121363) * in
- 0.00036307660358786885787) * in
- 0.00031101086326318780412) * in
+ 0.00096472747321388644237);
c[10] = static_cast<T>(((((((((8.2206352466243297170e-18 * in
- 3.1239569599829868045e-7) * in
+ 4.8903045291975346210e-6) * in
- 0.000033202652391372058698) * in
+ 0.00012645437628698076975) * in
- 0.00028690924218514613987) * in
+ 0.00035764655430568632777) * in
- 0.00010230378073700412687) * in
- 0.00036942667800009661203) * in
+ 0.00054229262813129686486);
//
// The result is then a polynomial in v (see Eq 56 of Shaw):
//
return tools::evaluate_odd_polynomial<11, T, T>(c, v);
}
template <class T, class Policy>
T inverse_students_t(T df, T u, T v, const Policy& pol, bool* pexact = 0)
{
//
// df = number of degrees of freedom.
// u = probablity.
// v = 1 - u.
// l = lanczos type to use.
//
BOOST_MATH_STD_USING
bool invert = false;
T result = 0;
if(pexact)
*pexact = false;
if(u > v)
{
// function is symmetric, invert it:
std::swap(u, v);
invert = true;
}
if((floor(df) == df) && (df < 20))
{
//
// we have integer degrees of freedom, try for the special
// cases first:
//
T tolerance = ldexp(1.0f, (2 * policies::digits<T, Policy>()) / 3);
switch(itrunc(df, Policy()))
{
case 1:
{
//
// df = 1 is the same as the Cauchy distribution, see
// Shaw Eq 35:
//
if(u == 0.5)
result = 0;
else
result = -cos(constants::pi<T>() * u) / sin(constants::pi<T>() * u);
if(pexact)
*pexact = true;
break;
}
case 2:
{
//
// df = 2 has an exact result, see Shaw Eq 36:
//
result =(2 * u - 1) / sqrt(2 * u * v);
if(pexact)
*pexact = true;
break;
}
case 4:
{
//
// df = 4 has an exact result, see Shaw Eq 38 & 39:
//
T alpha = 4 * u * v;
T root_alpha = sqrt(alpha);
T r = 4 * cos(acos(root_alpha) / 3) / root_alpha;
T x = sqrt(r - 4);
result = u - 0.5f < 0 ? (T)-x : x;
if(pexact)
*pexact = true;
break;
}
case 6:
{
//
// We get numeric overflow in this area:
//
if(u < 1e-150)
return (invert ? -1 : 1) * inverse_students_t_hill(df, u, pol);
//
// Newton-Raphson iteration of a polynomial case,
// choice of seed value is taken from Shaw's online
// supplement:
//
T a = 4 * (u - u * u);//1 - 4 * (u - 0.5f) * (u - 0.5f);
T b = boost::math::cbrt(a);
static const T c = static_cast<T>(0.85498797333834849467655443627193);
T p = 6 * (1 + c * (1 / b - 1));
T p0;
do{
T p2 = p * p;
T p4 = p2 * p2;
T p5 = p * p4;
p0 = p;
// next term is given by Eq 41:
p = 2 * (8 * a * p5 - 270 * p2 + 2187) / (5 * (4 * a * p4 - 216 * p - 243));
}while(fabs((p - p0) / p) > tolerance);
//
// Use Eq 45 to extract the result:
//
p = sqrt(p - df);
result = (u - 0.5f) < 0 ? (T)-p : p;
break;
}
#if 0
//
// These are Shaw's "exact" but iterative solutions
// for even df, the numerical accuracy of these is
// rather less than Hill's method, so these are disabled
// for now, which is a shame because they are reasonably
// quick to evaluate...
//
case 8:
{
//
// Newton-Raphson iteration of a polynomial case,
// choice of seed value is taken from Shaw's online
// supplement:
//
static const T c8 = 0.85994765706259820318168359251872L;
T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
T b = pow(a, T(1) / 4);
T p = 8 * (1 + c8 * (1 / b - 1));
T p0 = p;
do{
T p5 = p * p;
p5 *= p5 * p;
p0 = p;
// Next term is given by Eq 42:
p = 2 * (3 * p + (640 * (160 + p * (24 + p * (p + 4)))) / (-5120 + p * (-2048 - 960 * p + a * p5))) / 7;
}while(fabs((p - p0) / p) > tolerance);
//
// Use Eq 45 to extract the result:
//
p = sqrt(p - df);
result = (u - 0.5f) < 0 ? -p : p;
break;
}
case 10:
{
//
// Newton-Raphson iteration of a polynomial case,
// choice of seed value is taken from Shaw's online
// supplement:
//
static const T c10 = 0.86781292867813396759105692122285L;
T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
T b = pow(a, T(1) / 5);
T p = 10 * (1 + c10 * (1 / b - 1));
T p0;
do{
T p6 = p * p;
p6 *= p6 * p6;
p0 = p;
// Next term given by Eq 43:
p = (8 * p) / 9 + (218750 * (21875 + 4 * p * (625 + p * (75 + 2 * p * (5 + p))))) /
(9 * (-68359375 + 8 * p * (-2343750 + p * (-546875 - 175000 * p + 8 * a * p6))));
}while(fabs((p - p0) / p) > tolerance);
//
// Use Eq 45 to extract the result:
//
p = sqrt(p - df);
result = (u - 0.5f) < 0 ? -p : p;
break;
}
#endif
default:
goto calculate_real;
}
}
else
{
calculate_real:
if(df > 0x10000000)
{
result = -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
if((pexact) && (df >= 1e20))
*pexact = true;
}
else if(df < 3)
{
//
// Use a roughly linear scheme to choose between Shaw's
// tail series and body series:
//
T crossover = 0.2742f - df * 0.0242143f;
if(u > crossover)
{
result = boost::math::detail::inverse_students_t_body_series(df, u, pol);
}
else
{
result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
}
}
else
{
//
// Use Hill's method except in the exteme tails
// where we use Shaw's tail series.
// The crossover point is roughly exponential in -df:
//
T crossover = ldexp(1.0f, iround(T(df / -0.654f), typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type()));
if(u > crossover)
{
result = boost::math::detail::inverse_students_t_hill(df, u, pol);
}
else
{
result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
}
}
}
return invert ? (T)-result : result;
}
template <class T, class Policy>
inline T find_ibeta_inv_from_t_dist(T a, T p, T /*q*/, T* py, const Policy& pol)
{
T u = p / 2;
T v = 1 - u;
T df = a * 2;
T t = boost::math::detail::inverse_students_t(df, u, v, pol);
*py = t * t / (df + t * t);
return df / (df + t * t);
}
template <class T, class Policy>
inline T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::false_*)
{
BOOST_MATH_STD_USING
//
// Need to use inverse incomplete beta to get
// required precision so not so fast:
//
T probability = (p > 0.5) ? 1 - p : p;
T t, x, y(0);
x = ibeta_inv(df / 2, T(0.5), 2 * probability, &y, pol);
if(df * y > tools::max_value<T>() * x)
t = policies::raise_overflow_error<T>("boost::math::students_t_quantile<%1%>(%1%,%1%)", 0, pol);
else
t = sqrt(df * y / x);
//
// Figure out sign based on the size of p:
//
if(p < 0.5)
t = -t;
return t;
}
template <class T, class Policy>
T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::true_*)
{
BOOST_MATH_STD_USING
bool invert = false;
if((df < 2) && (floor(df) != df))
return boost::math::detail::fast_students_t_quantile_imp(df, p, pol, static_cast<mpl::false_*>(0));
if(p > 0.5)
{
p = 1 - p;
invert = true;
}
//
// Get an estimate of the result:
//
bool exact;
T t = inverse_students_t(df, p, T(1-p), pol, &exact);
if((t == 0) || exact)
return invert ? -t : t; // can't do better!
//
// Change variables to inverse incomplete beta:
//
T t2 = t * t;
T xb = df / (df + t2);
T y = t2 / (df + t2);
T a = df / 2;
//
// t can be so large that x underflows,
// just return our estimate in that case:
//
if(xb == 0)
return t;
//
// Get incomplete beta and it's derivative:
//
T f1;
T f0 = xb < y ? ibeta_imp(a, constants::half<T>(), xb, pol, false, true, &f1)
: ibeta_imp(constants::half<T>(), a, y, pol, true, true, &f1);
// Get cdf from incomplete beta result:
T p0 = f0 / 2 - p;
// Get pdf from derivative:
T p1 = f1 * sqrt(y * xb * xb * xb / df);
//
// Second derivative divided by p1:
//
// yacas gives:
//
// In> PrettyForm(Simplify(D(t) (1 + t^2/v) ^ (-(v+1)/2)))
//
// | | v + 1 | |
// | -| ----- + 1 | |
// | | 2 | |
// -| | 2 | |
// | | t | |
// | | -- + 1 | |
// | ( v + 1 ) * | v | * t |
// ---------------------------------------------
// v
//
// Which after some manipulation is:
//
// -p1 * t * (df + 1) / (t^2 + df)
//
T p2 = t * (df + 1) / (t * t + df);
// Halley step:
t = fabs(t);
t += p0 / (p1 + p0 * p2 / 2);
return !invert ? -t : t;
}
template <class T, class Policy>
inline T fast_students_t_quantile(T df, T p, const Policy& pol)
{
typedef typename policies::evaluation<T, 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;
typedef mpl::bool_<
(std::numeric_limits<T>::digits <= 53)
&&
(std::numeric_limits<T>::is_specialized)
&&
(std::numeric_limits<T>::radix == 2)
> tag_type;
return policies::checked_narrowing_cast<T, forwarding_policy>(fast_students_t_quantile_imp(static_cast<value_type>(df), static_cast<value_type>(p), pol, static_cast<tag_type*>(0)), "boost::math::students_t_quantile<%1%>(%1%,%1%,%1%)");
}
}}} // namespaces
#endif // BOOST_MATH_SF_DETAIL_INV_T_HPP

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,805 @@
// Copyright John Maddock 2006.
// Use, modification and distribution are subject to 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_SP_UC_FACTORIALS_HPP
#define BOOST_MATH_SP_UC_FACTORIALS_HPP
#ifdef _MSC_VER
#pragma once
#endif
#ifdef BOOST_MSVC
#pragma warning(push) // Temporary until lexical cast fixed.
#pragma warning(disable: 4127 4701)
#endif
#ifndef BOOST_MATH_NO_LEXICAL_CAST
#include <boost/lexical_cast.hpp>
#endif
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <cmath>
#include <boost/math/special_functions/math_fwd.hpp>
#ifdef BOOST_MATH_HAVE_CONSTEXPR_TABLES
#include <array>
#else
#include <boost/array.hpp>
#endif
namespace boost { namespace math
{
// Forward declarations:
template <class T>
struct max_factorial;
// Definitions:
template <>
inline BOOST_MATH_CONSTEXPR_TABLE_FUNCTION float unchecked_factorial<float>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(float))
{
#ifdef BOOST_MATH_HAVE_CONSTEXPR_TABLES
constexpr std::array<float, 35> factorials = { {
#else
static const boost::array<float, 35> factorials = {{
#endif
1.0F,
1.0F,
2.0F,
6.0F,
24.0F,
120.0F,
720.0F,
5040.0F,
40320.0F,
362880.0F,
3628800.0F,
39916800.0F,
479001600.0F,
6227020800.0F,
87178291200.0F,
1307674368000.0F,
20922789888000.0F,
355687428096000.0F,
6402373705728000.0F,
121645100408832000.0F,
0.243290200817664e19F,
0.5109094217170944e20F,
0.112400072777760768e22F,
0.2585201673888497664e23F,
0.62044840173323943936e24F,
0.15511210043330985984e26F,
0.403291461126605635584e27F,
0.10888869450418352160768e29F,
0.304888344611713860501504e30F,
0.8841761993739701954543616e31F,
0.26525285981219105863630848e33F,
0.822283865417792281772556288e34F,
0.26313083693369353016721801216e36F,
0.868331761881188649551819440128e37F,
0.29523279903960414084761860964352e39F,
}};
return factorials[i];
}
template <>
struct max_factorial<float>
{
BOOST_STATIC_CONSTANT(unsigned, value = 34);
};
template <>
inline BOOST_MATH_CONSTEXPR_TABLE_FUNCTION long double unchecked_factorial<long double>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(long double))
{
#ifdef BOOST_MATH_HAVE_CONSTEXPR_TABLES
constexpr std::array<long double, 171> factorials = { {
#else
static const boost::array<long double, 171> factorials = {{
#endif
1L,
1L,
2L,
6L,
24L,
120L,
720L,
5040L,
40320L,
362880.0L,
3628800.0L,
39916800.0L,
479001600.0L,
6227020800.0L,
87178291200.0L,
1307674368000.0L,
20922789888000.0L,
355687428096000.0L,
6402373705728000.0L,
121645100408832000.0L,
0.243290200817664e19L,
0.5109094217170944e20L,
0.112400072777760768e22L,
0.2585201673888497664e23L,
0.62044840173323943936e24L,
0.15511210043330985984e26L,
0.403291461126605635584e27L,
0.10888869450418352160768e29L,
0.304888344611713860501504e30L,
0.8841761993739701954543616e31L,
0.26525285981219105863630848e33L,
0.822283865417792281772556288e34L,
0.26313083693369353016721801216e36L,
0.868331761881188649551819440128e37L,
0.29523279903960414084761860964352e39L,
0.103331479663861449296666513375232e41L,
0.3719933267899012174679994481508352e42L,
0.137637530912263450463159795815809024e44L,
0.5230226174666011117600072241000742912e45L,
0.203978820811974433586402817399028973568e47L,
0.815915283247897734345611269596115894272e48L,
0.3345252661316380710817006205344075166515e50L,
0.1405006117752879898543142606244511569936e52L,
0.6041526306337383563735513206851399750726e53L,
0.265827157478844876804362581101461589032e55L,
0.1196222208654801945619631614956577150644e57L,
0.5502622159812088949850305428800254892962e58L,
0.2586232415111681806429643551536119799692e60L,
0.1241391559253607267086228904737337503852e62L,
0.6082818640342675608722521633212953768876e63L,
0.3041409320171337804361260816606476884438e65L,
0.1551118753287382280224243016469303211063e67L,
0.8065817517094387857166063685640376697529e68L,
0.427488328406002556429801375338939964969e70L,
0.2308436973392413804720927426830275810833e72L,
0.1269640335365827592596510084756651695958e74L,
0.7109985878048634518540456474637249497365e75L,
0.4052691950487721675568060190543232213498e77L,
0.2350561331282878571829474910515074683829e79L,
0.1386831185456898357379390197203894063459e81L,
0.8320987112741390144276341183223364380754e82L,
0.507580213877224798800856812176625227226e84L,
0.3146997326038793752565312235495076408801e86L,
0.1982608315404440064116146708361898137545e88L,
0.1268869321858841641034333893351614808029e90L,
0.8247650592082470666723170306785496252186e91L,
0.5443449390774430640037292402478427526443e93L,
0.3647111091818868528824985909660546442717e95L,
0.2480035542436830599600990418569171581047e97L,
0.1711224524281413113724683388812728390923e99L,
0.1197857166996989179607278372168909873646e101L,
0.8504785885678623175211676442399260102886e102L,
0.6123445837688608686152407038527467274078e104L,
0.4470115461512684340891257138125051110077e106L,
0.3307885441519386412259530282212537821457e108L,
0.2480914081139539809194647711659403366093e110L,
0.188549470166605025498793226086114655823e112L,
0.1451830920282858696340707840863082849837e114L,
0.1132428117820629783145752115873204622873e116L,
0.8946182130782975286851441715398316520698e117L,
0.7156945704626380229481153372318653216558e119L,
0.5797126020747367985879734231578109105412e121L,
0.4753643337012841748421382069894049466438e123L,
0.3945523969720658651189747118012061057144e125L,
0.3314240134565353266999387579130131288001e127L,
0.2817104114380550276949479442260611594801e129L,
0.2422709538367273238176552320344125971528e131L,
0.210775729837952771721360051869938959523e133L,
0.1854826422573984391147968456455462843802e135L,
0.1650795516090846108121691926245361930984e137L,
0.1485715964481761497309522733620825737886e139L,
0.1352001527678402962551665687594951421476e141L,
0.1243841405464130725547532432587355307758e143L,
0.1156772507081641574759205162306240436215e145L,
0.1087366156656743080273652852567866010042e147L,
0.103299784882390592625997020993947270954e149L,
0.9916779348709496892095714015418938011582e150L,
0.9619275968248211985332842594956369871234e152L,
0.942689044888324774562618574305724247381e154L,
0.9332621544394415268169923885626670049072e156L,
0.9332621544394415268169923885626670049072e158L,
0.9425947759838359420851623124482936749562e160L,
0.9614466715035126609268655586972595484554e162L,
0.990290071648618040754671525458177334909e164L,
0.1029901674514562762384858386476504428305e167L,
0.1081396758240290900504101305800329649721e169L,
0.1146280563734708354534347384148349428704e171L,
0.1226520203196137939351751701038733888713e173L,
0.132464181945182897449989183712183259981e175L,
0.1443859583202493582204882102462797533793e177L,
0.1588245541522742940425370312709077287172e179L,
0.1762952551090244663872161047107075788761e181L,
0.1974506857221074023536820372759924883413e183L,
0.2231192748659813646596607021218715118256e185L,
0.2543559733472187557120132004189335234812e187L,
0.2925093693493015690688151804817735520034e189L,
0.339310868445189820119825609358857320324e191L,
0.396993716080872089540195962949863064779e193L,
0.4684525849754290656574312362808384164393e195L,
0.5574585761207605881323431711741977155627e197L,
0.6689502913449127057588118054090372586753e199L,
0.8094298525273443739681622845449350829971e201L,
0.9875044200833601362411579871448208012564e203L,
0.1214630436702532967576624324188129585545e206L,
0.1506141741511140879795014161993280686076e208L,
0.1882677176888926099743767702491600857595e210L,
0.237217324288004688567714730513941708057e212L,
0.3012660018457659544809977077527059692324e214L,
0.3856204823625804217356770659234636406175e216L,
0.4974504222477287440390234150412680963966e218L,
0.6466855489220473672507304395536485253155e220L,
0.8471580690878820510984568758152795681634e222L,
0.1118248651196004307449963076076169029976e225L,
0.1487270706090685728908450891181304809868e227L,
0.1992942746161518876737324194182948445223e229L,
0.269047270731805048359538766214698040105e231L,
0.3659042881952548657689727220519893345429e233L,
0.5012888748274991661034926292112253883237e235L,
0.6917786472619488492228198283114910358867e237L,
0.9615723196941089004197195613529725398826e239L,
0.1346201247571752460587607385894161555836e242L,
0.1898143759076170969428526414110767793728e244L,
0.2695364137888162776588507508037290267094e246L,
0.3854370717180072770521565736493325081944e248L,
0.5550293832739304789551054660550388118e250L,
0.80479260574719919448490292577980627711e252L,
0.1174997204390910823947958271638517164581e255L,
0.1727245890454638911203498659308620231933e257L,
0.2556323917872865588581178015776757943262e259L,
0.380892263763056972698595524350736933546e261L,
0.571338395644585459047893286526105400319e263L,
0.8627209774233240431623188626544191544816e265L,
0.1311335885683452545606724671234717114812e268L,
0.2006343905095682394778288746989117185662e270L,
0.308976961384735088795856467036324046592e272L,
0.4789142901463393876335775239063022722176e274L,
0.7471062926282894447083809372938315446595e276L,
0.1172956879426414428192158071551315525115e279L,
0.1853271869493734796543609753051078529682e281L,
0.2946702272495038326504339507351214862195e283L,
0.4714723635992061322406943211761943779512e285L,
0.7590705053947218729075178570936729485014e287L,
0.1229694218739449434110178928491750176572e290L,
0.2004401576545302577599591653441552787813e292L,
0.3287218585534296227263330311644146572013e294L,
0.5423910666131588774984495014212841843822e296L,
0.9003691705778437366474261723593317460744e298L,
0.1503616514864999040201201707840084015944e301L,
0.2526075744973198387538018869171341146786e303L,
0.4269068009004705274939251888899566538069e305L,
0.7257415615307998967396728211129263114717e307L,
}};
return factorials[i];
}
template <>
struct max_factorial<long double>
{
BOOST_STATIC_CONSTANT(unsigned, value = 170);
};
#ifdef BOOST_MATH_USE_FLOAT128
template <>
inline BOOST_MATH_CONSTEXPR_TABLE_FUNCTION BOOST_MATH_FLOAT128_TYPE unchecked_factorial<BOOST_MATH_FLOAT128_TYPE>(unsigned i)
{
#ifdef BOOST_MATH_HAVE_CONSTEXPR_TABLES
constexpr std::array<BOOST_MATH_FLOAT128_TYPE, 171> factorials = { {
#else
static const boost::array<BOOST_MATH_FLOAT128_TYPE, 171> factorials = { {
#endif
1,
1,
2,
6,
24,
120,
720,
5040,
40320,
362880.0Q,
3628800.0Q,
39916800.0Q,
479001600.0Q,
6227020800.0Q,
87178291200.0Q,
1307674368000.0Q,
20922789888000.0Q,
355687428096000.0Q,
6402373705728000.0Q,
121645100408832000.0Q,
0.243290200817664e19Q,
0.5109094217170944e20Q,
0.112400072777760768e22Q,
0.2585201673888497664e23Q,
0.62044840173323943936e24Q,
0.15511210043330985984e26Q,
0.403291461126605635584e27Q,
0.10888869450418352160768e29Q,
0.304888344611713860501504e30Q,
0.8841761993739701954543616e31Q,
0.26525285981219105863630848e33Q,
0.822283865417792281772556288e34Q,
0.26313083693369353016721801216e36Q,
0.868331761881188649551819440128e37Q,
0.29523279903960414084761860964352e39Q,
0.103331479663861449296666513375232e41Q,
0.3719933267899012174679994481508352e42Q,
0.137637530912263450463159795815809024e44Q,
0.5230226174666011117600072241000742912e45Q,
0.203978820811974433586402817399028973568e47Q,
0.815915283247897734345611269596115894272e48Q,
0.3345252661316380710817006205344075166515e50Q,
0.1405006117752879898543142606244511569936e52Q,
0.6041526306337383563735513206851399750726e53Q,
0.265827157478844876804362581101461589032e55Q,
0.1196222208654801945619631614956577150644e57Q,
0.5502622159812088949850305428800254892962e58Q,
0.2586232415111681806429643551536119799692e60Q,
0.1241391559253607267086228904737337503852e62Q,
0.6082818640342675608722521633212953768876e63Q,
0.3041409320171337804361260816606476884438e65Q,
0.1551118753287382280224243016469303211063e67Q,
0.8065817517094387857166063685640376697529e68Q,
0.427488328406002556429801375338939964969e70Q,
0.2308436973392413804720927426830275810833e72Q,
0.1269640335365827592596510084756651695958e74Q,
0.7109985878048634518540456474637249497365e75Q,
0.4052691950487721675568060190543232213498e77Q,
0.2350561331282878571829474910515074683829e79Q,
0.1386831185456898357379390197203894063459e81Q,
0.8320987112741390144276341183223364380754e82Q,
0.507580213877224798800856812176625227226e84Q,
0.3146997326038793752565312235495076408801e86Q,
0.1982608315404440064116146708361898137545e88Q,
0.1268869321858841641034333893351614808029e90Q,
0.8247650592082470666723170306785496252186e91Q,
0.5443449390774430640037292402478427526443e93Q,
0.3647111091818868528824985909660546442717e95Q,
0.2480035542436830599600990418569171581047e97Q,
0.1711224524281413113724683388812728390923e99Q,
0.1197857166996989179607278372168909873646e101Q,
0.8504785885678623175211676442399260102886e102Q,
0.6123445837688608686152407038527467274078e104Q,
0.4470115461512684340891257138125051110077e106Q,
0.3307885441519386412259530282212537821457e108Q,
0.2480914081139539809194647711659403366093e110Q,
0.188549470166605025498793226086114655823e112Q,
0.1451830920282858696340707840863082849837e114Q,
0.1132428117820629783145752115873204622873e116Q,
0.8946182130782975286851441715398316520698e117Q,
0.7156945704626380229481153372318653216558e119Q,
0.5797126020747367985879734231578109105412e121Q,
0.4753643337012841748421382069894049466438e123Q,
0.3945523969720658651189747118012061057144e125Q,
0.3314240134565353266999387579130131288001e127Q,
0.2817104114380550276949479442260611594801e129Q,
0.2422709538367273238176552320344125971528e131Q,
0.210775729837952771721360051869938959523e133Q,
0.1854826422573984391147968456455462843802e135Q,
0.1650795516090846108121691926245361930984e137Q,
0.1485715964481761497309522733620825737886e139Q,
0.1352001527678402962551665687594951421476e141Q,
0.1243841405464130725547532432587355307758e143Q,
0.1156772507081641574759205162306240436215e145Q,
0.1087366156656743080273652852567866010042e147Q,
0.103299784882390592625997020993947270954e149Q,
0.9916779348709496892095714015418938011582e150Q,
0.9619275968248211985332842594956369871234e152Q,
0.942689044888324774562618574305724247381e154Q,
0.9332621544394415268169923885626670049072e156Q,
0.9332621544394415268169923885626670049072e158Q,
0.9425947759838359420851623124482936749562e160Q,
0.9614466715035126609268655586972595484554e162Q,
0.990290071648618040754671525458177334909e164Q,
0.1029901674514562762384858386476504428305e167Q,
0.1081396758240290900504101305800329649721e169Q,
0.1146280563734708354534347384148349428704e171Q,
0.1226520203196137939351751701038733888713e173Q,
0.132464181945182897449989183712183259981e175Q,
0.1443859583202493582204882102462797533793e177Q,
0.1588245541522742940425370312709077287172e179Q,
0.1762952551090244663872161047107075788761e181Q,
0.1974506857221074023536820372759924883413e183Q,
0.2231192748659813646596607021218715118256e185Q,
0.2543559733472187557120132004189335234812e187Q,
0.2925093693493015690688151804817735520034e189Q,
0.339310868445189820119825609358857320324e191Q,
0.396993716080872089540195962949863064779e193Q,
0.4684525849754290656574312362808384164393e195Q,
0.5574585761207605881323431711741977155627e197Q,
0.6689502913449127057588118054090372586753e199Q,
0.8094298525273443739681622845449350829971e201Q,
0.9875044200833601362411579871448208012564e203Q,
0.1214630436702532967576624324188129585545e206Q,
0.1506141741511140879795014161993280686076e208Q,
0.1882677176888926099743767702491600857595e210Q,
0.237217324288004688567714730513941708057e212Q,
0.3012660018457659544809977077527059692324e214Q,
0.3856204823625804217356770659234636406175e216Q,
0.4974504222477287440390234150412680963966e218Q,
0.6466855489220473672507304395536485253155e220Q,
0.8471580690878820510984568758152795681634e222Q,
0.1118248651196004307449963076076169029976e225Q,
0.1487270706090685728908450891181304809868e227Q,
0.1992942746161518876737324194182948445223e229Q,
0.269047270731805048359538766214698040105e231Q,
0.3659042881952548657689727220519893345429e233Q,
0.5012888748274991661034926292112253883237e235Q,
0.6917786472619488492228198283114910358867e237Q,
0.9615723196941089004197195613529725398826e239Q,
0.1346201247571752460587607385894161555836e242Q,
0.1898143759076170969428526414110767793728e244Q,
0.2695364137888162776588507508037290267094e246Q,
0.3854370717180072770521565736493325081944e248Q,
0.5550293832739304789551054660550388118e250Q,
0.80479260574719919448490292577980627711e252Q,
0.1174997204390910823947958271638517164581e255Q,
0.1727245890454638911203498659308620231933e257Q,
0.2556323917872865588581178015776757943262e259Q,
0.380892263763056972698595524350736933546e261Q,
0.571338395644585459047893286526105400319e263Q,
0.8627209774233240431623188626544191544816e265Q,
0.1311335885683452545606724671234717114812e268Q,
0.2006343905095682394778288746989117185662e270Q,
0.308976961384735088795856467036324046592e272Q,
0.4789142901463393876335775239063022722176e274Q,
0.7471062926282894447083809372938315446595e276Q,
0.1172956879426414428192158071551315525115e279Q,
0.1853271869493734796543609753051078529682e281Q,
0.2946702272495038326504339507351214862195e283Q,
0.4714723635992061322406943211761943779512e285Q,
0.7590705053947218729075178570936729485014e287Q,
0.1229694218739449434110178928491750176572e290Q,
0.2004401576545302577599591653441552787813e292Q,
0.3287218585534296227263330311644146572013e294Q,
0.5423910666131588774984495014212841843822e296Q,
0.9003691705778437366474261723593317460744e298Q,
0.1503616514864999040201201707840084015944e301Q,
0.2526075744973198387538018869171341146786e303Q,
0.4269068009004705274939251888899566538069e305Q,
0.7257415615307998967396728211129263114717e307Q,
} };
return factorials[i];
}
template <>
struct max_factorial<BOOST_MATH_FLOAT128_TYPE>
{
BOOST_STATIC_CONSTANT(unsigned, value = 170);
};
#endif
template <>
inline BOOST_MATH_CONSTEXPR_TABLE_FUNCTION double unchecked_factorial<double>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(double))
{
return static_cast<double>(boost::math::unchecked_factorial<long double>(i));
}
template <>
struct max_factorial<double>
{
BOOST_STATIC_CONSTANT(unsigned,
value = ::boost::math::max_factorial<long double>::value);
};
#ifndef BOOST_MATH_NO_LEXICAL_CAST
template <class T>
struct unchecked_factorial_initializer
{
struct init
{
init()
{
boost::math::unchecked_factorial<T>(3);
}
void force_instantiate()const {}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T>
const typename unchecked_factorial_initializer<T>::init unchecked_factorial_initializer<T>::initializer;
template <class T, int N>
inline T unchecked_factorial_imp(unsigned i, const mpl::int_<N>&)
{
BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
// factorial<unsigned int>(n) is not implemented
// because it would overflow integral type T for too small n
// to be useful. Use instead a floating-point type,
// and convert to an unsigned type if essential, for example:
// unsigned int nfac = static_cast<unsigned int>(factorial<double>(n));
// See factorial documentation for more detail.
unchecked_factorial_initializer<T>::force_instantiate();
static const boost::array<T, 101> factorials = {{
T(boost::math::tools::convert_from_string<T>("1")),
T(boost::math::tools::convert_from_string<T>("1")),
T(boost::math::tools::convert_from_string<T>("2")),
T(boost::math::tools::convert_from_string<T>("6")),
T(boost::math::tools::convert_from_string<T>("24")),
T(boost::math::tools::convert_from_string<T>("120")),
T(boost::math::tools::convert_from_string<T>("720")),
T(boost::math::tools::convert_from_string<T>("5040")),
T(boost::math::tools::convert_from_string<T>("40320")),
T(boost::math::tools::convert_from_string<T>("362880")),
T(boost::math::tools::convert_from_string<T>("3628800")),
T(boost::math::tools::convert_from_string<T>("39916800")),
T(boost::math::tools::convert_from_string<T>("479001600")),
T(boost::math::tools::convert_from_string<T>("6227020800")),
T(boost::math::tools::convert_from_string<T>("87178291200")),
T(boost::math::tools::convert_from_string<T>("1307674368000")),
T(boost::math::tools::convert_from_string<T>("20922789888000")),
T(boost::math::tools::convert_from_string<T>("355687428096000")),
T(boost::math::tools::convert_from_string<T>("6402373705728000")),
T(boost::math::tools::convert_from_string<T>("121645100408832000")),
T(boost::math::tools::convert_from_string<T>("2432902008176640000")),
T(boost::math::tools::convert_from_string<T>("51090942171709440000")),
T(boost::math::tools::convert_from_string<T>("1124000727777607680000")),
T(boost::math::tools::convert_from_string<T>("25852016738884976640000")),
T(boost::math::tools::convert_from_string<T>("620448401733239439360000")),
T(boost::math::tools::convert_from_string<T>("15511210043330985984000000")),
T(boost::math::tools::convert_from_string<T>("403291461126605635584000000")),
T(boost::math::tools::convert_from_string<T>("10888869450418352160768000000")),
T(boost::math::tools::convert_from_string<T>("304888344611713860501504000000")),
T(boost::math::tools::convert_from_string<T>("8841761993739701954543616000000")),
T(boost::math::tools::convert_from_string<T>("265252859812191058636308480000000")),
T(boost::math::tools::convert_from_string<T>("8222838654177922817725562880000000")),
T(boost::math::tools::convert_from_string<T>("263130836933693530167218012160000000")),
T(boost::math::tools::convert_from_string<T>("8683317618811886495518194401280000000")),
T(boost::math::tools::convert_from_string<T>("295232799039604140847618609643520000000")),
T(boost::math::tools::convert_from_string<T>("10333147966386144929666651337523200000000")),
T(boost::math::tools::convert_from_string<T>("371993326789901217467999448150835200000000")),
T(boost::math::tools::convert_from_string<T>("13763753091226345046315979581580902400000000")),
T(boost::math::tools::convert_from_string<T>("523022617466601111760007224100074291200000000")),
T(boost::math::tools::convert_from_string<T>("20397882081197443358640281739902897356800000000")),
T(boost::math::tools::convert_from_string<T>("815915283247897734345611269596115894272000000000")),
T(boost::math::tools::convert_from_string<T>("33452526613163807108170062053440751665152000000000")),
T(boost::math::tools::convert_from_string<T>("1405006117752879898543142606244511569936384000000000")),
T(boost::math::tools::convert_from_string<T>("60415263063373835637355132068513997507264512000000000")),
T(boost::math::tools::convert_from_string<T>("2658271574788448768043625811014615890319638528000000000")),
T(boost::math::tools::convert_from_string<T>("119622220865480194561963161495657715064383733760000000000")),
T(boost::math::tools::convert_from_string<T>("5502622159812088949850305428800254892961651752960000000000")),
T(boost::math::tools::convert_from_string<T>("258623241511168180642964355153611979969197632389120000000000")),
T(boost::math::tools::convert_from_string<T>("12413915592536072670862289047373375038521486354677760000000000")),
T(boost::math::tools::convert_from_string<T>("608281864034267560872252163321295376887552831379210240000000000")),
T(boost::math::tools::convert_from_string<T>("30414093201713378043612608166064768844377641568960512000000000000")),
T(boost::math::tools::convert_from_string<T>("1551118753287382280224243016469303211063259720016986112000000000000")),
T(boost::math::tools::convert_from_string<T>("80658175170943878571660636856403766975289505440883277824000000000000")),
T(boost::math::tools::convert_from_string<T>("4274883284060025564298013753389399649690343788366813724672000000000000")),
T(boost::math::tools::convert_from_string<T>("230843697339241380472092742683027581083278564571807941132288000000000000")),
T(boost::math::tools::convert_from_string<T>("12696403353658275925965100847566516959580321051449436762275840000000000000")),
T(boost::math::tools::convert_from_string<T>("710998587804863451854045647463724949736497978881168458687447040000000000000")),
T(boost::math::tools::convert_from_string<T>("40526919504877216755680601905432322134980384796226602145184481280000000000000")),
T(boost::math::tools::convert_from_string<T>("2350561331282878571829474910515074683828862318181142924420699914240000000000000")),
T(boost::math::tools::convert_from_string<T>("138683118545689835737939019720389406345902876772687432540821294940160000000000000")),
T(boost::math::tools::convert_from_string<T>("8320987112741390144276341183223364380754172606361245952449277696409600000000000000")),
T(boost::math::tools::convert_from_string<T>("507580213877224798800856812176625227226004528988036003099405939480985600000000000000")),
T(boost::math::tools::convert_from_string<T>("31469973260387937525653122354950764088012280797258232192163168247821107200000000000000")),
T(boost::math::tools::convert_from_string<T>("1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000")),
T(boost::math::tools::convert_from_string<T>("126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000")),
T(boost::math::tools::convert_from_string<T>("8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000")),
T(boost::math::tools::convert_from_string<T>("544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000")),
T(boost::math::tools::convert_from_string<T>("36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000")),
T(boost::math::tools::convert_from_string<T>("2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000")),
T(boost::math::tools::convert_from_string<T>("171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000")),
T(boost::math::tools::convert_from_string<T>("11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000")),
T(boost::math::tools::convert_from_string<T>("850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000")),
T(boost::math::tools::convert_from_string<T>("61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000")),
T(boost::math::tools::convert_from_string<T>("4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000")),
T(boost::math::tools::convert_from_string<T>("330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000")),
T(boost::math::tools::convert_from_string<T>("24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000")),
T(boost::math::tools::convert_from_string<T>("1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000")),
T(boost::math::tools::convert_from_string<T>("145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000")),
T(boost::math::tools::convert_from_string<T>("11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000")),
T(boost::math::tools::convert_from_string<T>("894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000")),
T(boost::math::tools::convert_from_string<T>("71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000")),
T(boost::math::tools::convert_from_string<T>("5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000")),
T(boost::math::tools::convert_from_string<T>("475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000")),
T(boost::math::tools::convert_from_string<T>("39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000")),
T(boost::math::tools::convert_from_string<T>("3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000")),
T(boost::math::tools::convert_from_string<T>("281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000")),
T(boost::math::tools::convert_from_string<T>("24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000")),
T(boost::math::tools::convert_from_string<T>("2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000")),
T(boost::math::tools::convert_from_string<T>("185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000")),
T(boost::math::tools::convert_from_string<T>("16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000")),
T(boost::math::tools::convert_from_string<T>("1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000")),
T(boost::math::tools::convert_from_string<T>("93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000")),
}};
return factorials[i];
}
template <class T>
inline T unchecked_factorial_imp(unsigned i, const mpl::int_<0>&)
{
BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
// factorial<unsigned int>(n) is not implemented
// because it would overflow integral type T for too small n
// to be useful. Use instead a floating-point type,
// and convert to an unsigned type if essential, for example:
// unsigned int nfac = static_cast<unsigned int>(factorial<double>(n));
// See factorial documentation for more detail.
#ifdef BOOST_NO_CXX11_THREAD_LOCAL
unchecked_factorial_initializer<T>::force_instantiate();
#endif
static const char* const factorial_strings[] = {
"1",
"1",
"2",
"6",
"24",
"120",
"720",
"5040",
"40320",
"362880",
"3628800",
"39916800",
"479001600",
"6227020800",
"87178291200",
"1307674368000",
"20922789888000",
"355687428096000",
"6402373705728000",
"121645100408832000",
"2432902008176640000",
"51090942171709440000",
"1124000727777607680000",
"25852016738884976640000",
"620448401733239439360000",
"15511210043330985984000000",
"403291461126605635584000000",
"10888869450418352160768000000",
"304888344611713860501504000000",
"8841761993739701954543616000000",
"265252859812191058636308480000000",
"8222838654177922817725562880000000",
"263130836933693530167218012160000000",
"8683317618811886495518194401280000000",
"295232799039604140847618609643520000000",
"10333147966386144929666651337523200000000",
"371993326789901217467999448150835200000000",
"13763753091226345046315979581580902400000000",
"523022617466601111760007224100074291200000000",
"20397882081197443358640281739902897356800000000",
"815915283247897734345611269596115894272000000000",
"33452526613163807108170062053440751665152000000000",
"1405006117752879898543142606244511569936384000000000",
"60415263063373835637355132068513997507264512000000000",
"2658271574788448768043625811014615890319638528000000000",
"119622220865480194561963161495657715064383733760000000000",
"5502622159812088949850305428800254892961651752960000000000",
"258623241511168180642964355153611979969197632389120000000000",
"12413915592536072670862289047373375038521486354677760000000000",
"608281864034267560872252163321295376887552831379210240000000000",
"30414093201713378043612608166064768844377641568960512000000000000",
"1551118753287382280224243016469303211063259720016986112000000000000",
"80658175170943878571660636856403766975289505440883277824000000000000",
"4274883284060025564298013753389399649690343788366813724672000000000000",
"230843697339241380472092742683027581083278564571807941132288000000000000",
"12696403353658275925965100847566516959580321051449436762275840000000000000",
"710998587804863451854045647463724949736497978881168458687447040000000000000",
"40526919504877216755680601905432322134980384796226602145184481280000000000000",
"2350561331282878571829474910515074683828862318181142924420699914240000000000000",
"138683118545689835737939019720389406345902876772687432540821294940160000000000000",
"8320987112741390144276341183223364380754172606361245952449277696409600000000000000",
"507580213877224798800856812176625227226004528988036003099405939480985600000000000000",
"31469973260387937525653122354950764088012280797258232192163168247821107200000000000000",
"1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000",
"126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000",
"8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000",
"544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000",
"36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000",
"2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000",
"171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000",
"11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000",
"850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000",
"61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000",
"4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000",
"330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000",
"24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000",
"1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000",
"145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000",
"11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000",
"894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000",
"71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000",
"5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000",
"475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000",
"39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000",
"3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000",
"281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000",
"24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000",
"2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000",
"185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000",
"16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000",
"1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000",
"135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000",
"12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000",
"1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000",
"108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000",
"10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000",
"991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000",
"96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000",
"9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000",
"933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000",
"93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000",
};
static BOOST_MATH_THREAD_LOCAL T factorials[sizeof(factorial_strings) / sizeof(factorial_strings[0])];
static BOOST_MATH_THREAD_LOCAL int digits = 0;
int current_digits = boost::math::tools::digits<T>();
if(digits != current_digits)
{
digits = current_digits;
for(unsigned k = 0; k < sizeof(factorials) / sizeof(factorials[0]); ++k)
factorials[k] = static_cast<T>(boost::math::tools::convert_from_string<T>(factorial_strings[k]));
}
return factorials[i];
}
template <class T>
inline T unchecked_factorial(unsigned i)
{
typedef typename boost::math::policies::precision<T, boost::math::policies::policy<> >::type tag_type;
return unchecked_factorial_imp<T>(i, tag_type());
}
template <class T>
struct max_factorial
{
BOOST_STATIC_CONSTANT(unsigned, value = 100);
};
#else // BOOST_MATH_NO_LEXICAL_CAST
template <class T>
inline T unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(T))
{
return 1;
}
template <class T>
struct max_factorial
{
BOOST_STATIC_CONSTANT(unsigned, value = 0);
};
#endif
#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
template <class T>
const unsigned max_factorial<T>::value;
#endif
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SP_UC_FACTORIALS_HPP