Added boost header

This commit is contained in:
Christophe Riccio
2012-01-08 01:26:07 +00:00
parent 9c3faaca40
commit c7d752cdf8
8946 changed files with 1732316 additions and 0 deletions

View File

@@ -0,0 +1,114 @@
// boost asinh.hpp header file
// (C) Copyright Eric Ford 2001 & Hubert Holin.
// (C) Copyright John Maddock 2008.
// 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)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_ACOSH_HPP
#define BOOST_ACOSH_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/log1p.hpp>
// This is the inverse of the hyperbolic cosine function.
namespace boost
{
namespace math
{
namespace detail
{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::log;
using ::std::numeric_limits;
#endif
template<typename T, typename Policy>
inline T acosh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if(x < 1)
{
return policies::raise_domain_error<T>(
"boost::math::acosh<%1%>(%1%)",
"acosh requires x >= 1, but got x = %1%.", x, pol);
}
else if ((x - 1) >= tools::root_epsilon<T>())
{
if (x > 1 / tools::root_epsilon<T>())
{
// http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/06/01/0001/
// approximation by laurent series in 1/x at 0+ order from -1 to 0
return( log( x * 2) );
}
else if(x < 1.5f)
{
// This is just a rearrangement of the standard form below
// devised to minimse loss of precision when x ~ 1:
T y = x - 1;
return boost::math::log1p(y + sqrt(y * y + 2 * y), pol);
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcCosh/02/
return( log( x + sqrt(x * x - 1) ) );
}
}
else
{
// see http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/04/01/0001/
T y = x - 1;
// approximation by taylor series in y at 0 up to order 2
T result = sqrt(2 * y) * (1 - y /12 + 3 * y * y / 160);
return result;
}
}
}
template<typename T, typename Policy>
inline typename tools::promote_args<T>::type acosh(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::acosh_imp(static_cast<value_type>(x), forwarding_policy()),
"boost::math::acosh<%1%>(%1%)");
}
template<typename T>
inline typename tools::promote_args<T>::type acosh(T x)
{
return boost::math::acosh(x, policies::policy<>());
}
}
}
#endif /* BOOST_ACOSH_HPP */

View File

@@ -0,0 +1,116 @@
// boost asinh.hpp header file
// (C) Copyright Eric Ford & Hubert Holin 2001.
// (C) Copyright John Maddock 2008.
// 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)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_ASINH_HPP
#define BOOST_ASINH_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/sqrt1pm1.hpp>
#include <boost/math/special_functions/log1p.hpp>
// This is the inverse of the hyperbolic sine function.
namespace boost
{
namespace math
{
namespace detail{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::log;
using ::std::numeric_limits;
#endif
template<typename T, class Policy>
inline T asinh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if (x >= tools::forth_root_epsilon<T>())
{
if (x > 1 / tools::root_epsilon<T>())
{
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/06/01/0001/
// approximation by laurent series in 1/x at 0+ order from -1 to 1
return log(x * 2) + 1/ (4 * x * x);
}
else if(x < 0.5f)
{
// As below, but rearranged to preserve digits:
return boost::math::log1p(x + boost::math::sqrt1pm1(x * x, pol), pol);
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/02/
return( log( x + sqrt(x*x+1) ) );
}
}
else if (x <= -tools::forth_root_epsilon<T>())
{
return(-asinh(-x));
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/03/01/0001/
// approximation by taylor series in x at 0 up to order 2
T result = x;
if (abs(x) >= tools::root_epsilon<T>())
{
T x3 = x*x*x;
// approximation by taylor series in x at 0 up to order 4
result -= x3/static_cast<T>(6);
}
return(result);
}
}
}
template<typename T>
inline typename tools::promote_args<T>::type asinh(T x)
{
return boost::math::asinh(x, policies::policy<>());
}
template<typename T, typename Policy>
inline typename tools::promote_args<T>::type asinh(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::asinh_imp(static_cast<value_type>(x), forwarding_policy()),
"boost::math::asinh<%1%>(%1%)");
}
}
}
#endif /* BOOST_ASINH_HPP */

View File

@@ -0,0 +1,128 @@
// boost atanh.hpp header file
// (C) Copyright Hubert Holin 2001.
// (C) Copyright John Maddock 2008.
// 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)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_ATANH_HPP
#define BOOST_ATANH_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/log1p.hpp>
// This is the inverse of the hyperbolic tangent function.
namespace boost
{
namespace math
{
namespace detail
{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::log;
using ::std::numeric_limits;
#endif
// This is the main fare
template<typename T, typename Policy>
inline T atanh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* function = "boost::math::atanh<%1%>(%1%)";
if(x < -1)
{
return policies::raise_domain_error<T>(
function,
"atanh requires x >= -1, but got x = %1%.", x, pol);
}
else if(x < -1 + tools::epsilon<T>())
{
// -Infinity:
return -policies::raise_overflow_error<T>(function, 0, pol);
}
else if(x > 1 - tools::epsilon<T>())
{
// Infinity:
return policies::raise_overflow_error<T>(function, 0, pol);
}
else if(x > 1)
{
return policies::raise_domain_error<T>(
function,
"atanh requires x <= 1, but got x = %1%.", x, pol);
}
else if(abs(x) >= tools::forth_root_epsilon<T>())
{
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/02/
if(abs(x) < 0.5f)
return (boost::math::log1p(x, pol) - boost::math::log1p(-x, pol)) / 2;
return(log( (1 + x) / (1 - x) ) / 2);
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/06/01/03/01/
// approximation by taylor series in x at 0 up to order 2
T result = x;
if (abs(x) >= tools::root_epsilon<T>())
{
T x3 = x*x*x;
// approximation by taylor series in x at 0 up to order 4
result += x3/static_cast<T>(3);
}
return(result);
}
}
}
template<typename T, typename Policy>
inline typename tools::promote_args<T>::type atanh(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::atanh_imp(static_cast<value_type>(x), forwarding_policy()),
"boost::math::atanh<%1%>(%1%)");
}
template<typename T>
inline typename tools::promote_args<T>::type atanh(T x)
{
return boost::math::atanh(x, policies::policy<>());
}
}
}
#endif /* BOOST_ATANH_HPP */

View File

@@ -0,0 +1,469 @@
// 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 header just defines the function entry points, and adds dispatch
// to the right implementation method. Most of the implementation details
// are in separate headers and copyright Xiaogang Zhang.
//
#ifndef BOOST_MATH_BESSEL_HPP
#define BOOST_MATH_BESSEL_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_jy.hpp>
#include <boost/math/special_functions/detail/bessel_jn.hpp>
#include <boost/math/special_functions/detail/bessel_yn.hpp>
#include <boost/math/special_functions/detail/bessel_ik.hpp>
#include <boost/math/special_functions/detail/bessel_i0.hpp>
#include <boost/math/special_functions/detail/bessel_i1.hpp>
#include <boost/math/special_functions/detail/bessel_kn.hpp>
#include <boost/math/special_functions/detail/iconv.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
#include <boost/math/special_functions/sinc.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/tools/series.hpp>
namespace boost{ namespace math{
namespace detail{
template <class T, class Policy>
struct sph_bessel_j_small_z_series_term
{
typedef T result_type;
sph_bessel_j_small_z_series_term(unsigned v_, T x)
: N(0), v(v_)
{
BOOST_MATH_STD_USING
mult = x / 2;
term = pow(mult, T(v)) / boost::math::tgamma(v+1+T(0.5f), Policy());
mult *= -mult;
}
T operator()()
{
T r = term;
++N;
term *= mult / (N * T(N + v + 0.5f));
return r;
}
private:
unsigned N;
unsigned v;
T mult;
T term;
};
template <class T, class Policy>
inline T sph_bessel_j_small_z_series(unsigned v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
sph_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::sph_bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
return result * sqrt(constants::pi<T>() / 4);
}
template <class T, class Policy>
T cyl_bessel_j_imp(T v, T x, const bessel_no_int_tag& t, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* function = "boost::math::bessel_j<%1%>(%1%,%1%)";
if(x < 0)
{
// better have integer v:
if(floor(v) == v)
{
T r = cyl_bessel_j_imp(v, T(-x), t, pol);
if(iround(v, pol) & 1)
r = -r;
return r;
}
else
return policies::raise_domain_error<T>(
function,
"Got x = %1%, but we need x >= 0", x, pol);
}
if(x == 0)
return (v == 0) ? 1 : (v > 0) ? 0 :
policies::raise_domain_error<T>(
function,
"Got v = %1%, but require v >= 0 or a negative integer: the result would be complex.", v, pol);
if((v >= 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 :-(
//
return bessel_j_small_z_series(v, x, pol);
}
T j, y;
bessel_jy(v, x, &j, &y, need_j, pol);
return j;
}
template <class T, class Policy>
inline T cyl_bessel_j_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names.
int ival = detail::iconv(v, pol);
if((abs(ival) < 200) && (0 == v - ival))
{
return bessel_jn(ival/*iround(v, pol)*/, x, pol);
}
return cyl_bessel_j_imp(v, x, bessel_no_int_tag(), pol);
}
template <class T, class Policy>
inline T cyl_bessel_j_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING
return bessel_jn(v, x, pol);
}
template <class T, class Policy>
inline T sph_bessel_j_imp(unsigned n, T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
if(x < 0)
return policies::raise_domain_error<T>(
"boost::math::sph_bessel_j<%1%>(%1%,%1%)",
"Got x = %1%, but function requires x > 0.", x, pol);
//
// Special case, n == 0 resolves down to the sinus cardinal of x:
//
if(n == 0)
return boost::math::sinc_pi(x, pol);
//
// When x is small we may end up with 0/0, use series evaluation
// instead, especially as it converges rapidly:
//
if(x < 1)
return sph_bessel_j_small_z_series(n, x, pol);
//
// Default case is just a naive evaluation of the definition:
//
return sqrt(constants::pi<T>() / (2 * x))
* cyl_bessel_j_imp(T(T(n)+T(0.5f)), x, bessel_no_int_tag(), pol);
}
template <class T, class Policy>
T cyl_bessel_i_imp(T v, T x, const Policy& pol)
{
//
// This handles all the bessel I functions, note that we don't optimise
// for integer v, other than the v = 0 or 1 special cases, as Millers
// algorithm is at least as inefficient as the general case (the general
// case has better error handling too).
//
BOOST_MATH_STD_USING
if(x < 0)
{
// better have integer v:
if(floor(v) == v)
{
T r = cyl_bessel_i_imp(v, T(-x), pol);
if(iround(v, pol) & 1)
r = -r;
return r;
}
else
return policies::raise_domain_error<T>(
"boost::math::cyl_bessel_i<%1%>(%1%,%1%)",
"Got x = %1%, but we need x >= 0", x, pol);
}
if(x == 0)
{
return (v == 0) ? 1 : 0;
}
if(v == 0.5f)
{
// common special case, note try and avoid overflow in exp(x):
if(x >= tools::log_max_value<T>())
{
T e = exp(x / 2);
return e * (e / sqrt(2 * x * constants::pi<T>()));
}
return sqrt(2 / (x * constants::pi<T>())) * sinh(x);
}
if(policies::digits<T, Policy>() <= 64)
{
if(v == 0)
{
return bessel_i0(x);
}
if(v == 1)
{
return bessel_i1(x);
}
}
if((x / v < 0.25) && (v > 0))
return bessel_i_small_z_series(v, x, pol);
T I, K;
bessel_ik(v, x, &I, &K, need_i, pol);
return I;
}
template <class T, class Policy>
inline T cyl_bessel_k_imp(T v, T x, const bessel_no_int_tag& /* t */, const Policy& pol)
{
static const char* function = "boost::math::cyl_bessel_k<%1%>(%1%,%1%)";
BOOST_MATH_STD_USING
if(x < 0)
{
return policies::raise_domain_error<T>(
function,
"Got x = %1%, but we need x > 0", x, pol);
}
if(x == 0)
{
return (v == 0) ? policies::raise_overflow_error<T>(function, 0, pol)
: policies::raise_domain_error<T>(
function,
"Got x = %1%, but we need x > 0", x, pol);
}
T I, K;
bessel_ik(v, x, &I, &K, need_k, pol);
return K;
}
template <class T, class Policy>
inline T cyl_bessel_k_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING
if((floor(v) == v))
{
return bessel_kn(itrunc(v), x, pol);
}
return cyl_bessel_k_imp(v, x, bessel_no_int_tag(), pol);
}
template <class T, class Policy>
inline T cyl_bessel_k_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
{
return bessel_kn(v, x, pol);
}
template <class T, class Policy>
inline T cyl_neumann_imp(T v, T x, const bessel_no_int_tag&, const Policy& pol)
{
static const char* function = "boost::math::cyl_neumann<%1%>(%1%,%1%)";
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
if(x <= 0)
{
return (v == 0) && (x == 0) ?
policies::raise_overflow_error<T>(function, 0, pol)
: policies::raise_domain_error<T>(
function,
"Got x = %1%, but result is complex for x <= 0", x, pol);
}
T j, y;
bessel_jy(v, x, &j, &y, need_y, pol);
//
// Post evaluation check for internal overflow during evaluation,
// can occur when x is small and v is large, in which case the result
// is -INF:
//
if(!(boost::math::isfinite)(y))
return -policies::raise_overflow_error<T>(function, 0, pol);
return y;
}
template <class T, class Policy>
inline T cyl_neumann_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
if(floor(v) == v)
{
if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
{
T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
if((v < 0) && (itrunc(v, pol) & 1))
r = -r;
BOOST_MATH_INSTRUMENT_VARIABLE(r);
return r;
}
else
{
T r = bessel_yn(itrunc(v, pol), x, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(r);
return r;
}
}
T r = cyl_neumann_imp<T>(v, x, bessel_no_int_tag(), pol);
BOOST_MATH_INSTRUMENT_VARIABLE(r);
return r;
}
template <class T, class Policy>
inline T cyl_neumann_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
{
T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
if((v < 0) && (v & 1))
r = -r;
return r;
}
else
return bessel_yn(v, x, pol);
}
template <class T, class Policy>
inline T sph_neumann_imp(unsigned v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
static const char* function = "boost::math::sph_neumann<%1%>(%1%,%1%)";
//
// Nothing much to do here but check for errors, and
// evaluate the function's definition directly:
//
if(x < 0)
return policies::raise_domain_error<T>(
function,
"Got x = %1%, but function requires x > 0.", x, pol);
if(x < 2 * tools::min_value<T>())
return -policies::raise_overflow_error<T>(function, 0, pol);
T result = cyl_neumann_imp(T(T(v)+0.5f), x, bessel_no_int_tag(), pol);
T tx = sqrt(constants::pi<T>() / (2 * x));
if((tx > 1) && (tools::max_value<T>() / tx < result))
return -policies::raise_overflow_error<T>(function, 0, pol);
return result * tx;
}
} // namespace detail
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_j(T1 v, T2 x, const Policy& pol)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_j_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_bessel_j<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_j(T1 v, T2 x)
{
return cyl_bessel_j(v, x, policies::policy<>());
}
template <class T, class Policy>
inline typename detail::bessel_traits<T, T, Policy>::result_type sph_bessel(unsigned v, T x, const Policy& pol)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename detail::bessel_traits<T, T, Policy>::result_type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_bessel_j_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::sph_bessel<%1%>(%1%,%1%)");
}
template <class T>
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_bessel(unsigned v, T x)
{
return sph_bessel(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_i(T1 v, T2 x, const Policy& pol)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_i_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::cyl_bessel_i<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_i(T1 v, T2 x)
{
return cyl_bessel_i(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_k(T1 v, T2 x, const Policy& pol)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_k_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_bessel_k<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_k(T1 v, T2 x)
{
return cyl_bessel_k(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_neumann(T1 v, T2 x, const Policy& pol)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_neumann_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_neumann<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_neumann(T1 v, T2 x)
{
return cyl_neumann(v, x, policies::policy<>());
}
template <class T, class Policy>
inline typename detail::bessel_traits<T, T, Policy>::result_type sph_neumann(unsigned v, T x, const Policy& pol)
{
BOOST_FPU_EXCEPTION_GUARD
typedef typename detail::bessel_traits<T, T, Policy>::result_type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_neumann_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::sph_neumann<%1%>(%1%,%1%)");
}
template <class T>
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_neumann(unsigned v, T x)
{
return sph_neumann(v, x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_BESSEL_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,81 @@
// 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_BINOMIAL_HPP
#define BOOST_MATH_SF_BINOMIAL_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/beta.hpp>
#include <boost/math/policies/error_handling.hpp>
namespace boost{ namespace math{
template <class T, class Policy>
T binomial_coefficient(unsigned n, unsigned k, const Policy& pol)
{
BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
BOOST_MATH_STD_USING
static const char* function = "boost::math::binomial_coefficient<%1%>(unsigned, unsigned)";
if(k > n)
return policies::raise_domain_error<T>(
function,
"The binomial coefficient is undefined for k > n, but got k = %1%.",
k, pol);
T result;
if((k == 0) || (k == n))
return 1;
if((k == 1) || (k == n-1))
return n;
if(n <= max_factorial<T>::value)
{
// Use fast table lookup:
result = unchecked_factorial<T>(n);
result /= unchecked_factorial<T>(n-k);
result /= unchecked_factorial<T>(k);
}
else
{
// Use the beta function:
if(k < n - k)
result = k * beta(static_cast<T>(k), static_cast<T>(n-k+1), pol);
else
result = (n - k) * beta(static_cast<T>(k+1), static_cast<T>(n-k), pol);
if(result == 0)
return policies::raise_overflow_error<T>(function, 0, pol);
result = 1 / result;
}
// convert to nearest integer:
return ceil(result - 0.5f);
}
//
// Type float can only store the first 35 factorials, in order to
// increase the chance that we can use a table driven implementation
// we'll promote to double:
//
template <>
inline float binomial_coefficient<float, policies::policy<> >(unsigned n, unsigned k, const policies::policy<>& pol)
{
return policies::checked_narrowing_cast<float, policies::policy<> >(binomial_coefficient<double>(n, k, pol), "boost::math::binomial_coefficient<%1%>(unsigned,unsigned)");
}
template <class T>
inline T binomial_coefficient(unsigned n, unsigned k)
{
return binomial_coefficient<T>(n, k, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SF_BINOMIAL_HPP

View File

@@ -0,0 +1,180 @@
// (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_CBRT_HPP
#define BOOST_MATH_SF_CBRT_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/mpl/divides.hpp>
#include <boost/mpl/plus.hpp>
#include <boost/mpl/if.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace boost{ namespace math{
namespace detail
{
struct big_int_type
{
operator boost::uintmax_t()const;
};
template <class T>
struct largest_cbrt_int_type
{
typedef typename mpl::if_<
boost::is_convertible<big_int_type, T>,
boost::uintmax_t,
unsigned int
>::type type;
};
template <class T, class Policy>
T cbrt_imp(T z, const Policy& pol)
{
BOOST_MATH_STD_USING
//
// cbrt approximation for z in the range [0.5,1]
// It's hard to say what number of terms gives the optimum
// trade off between precision and performance, this seems
// to be about the best for double precision.
//
// Maximum Deviation Found: 1.231e-006
// Expected Error Term: -1.231e-006
// Maximum Relative Change in Control Points: 5.982e-004
//
static const T P[] = {
static_cast<T>(0.37568269008611818),
static_cast<T>(1.3304968705558024),
static_cast<T>(-1.4897101632445036),
static_cast<T>(1.2875573098219835),
static_cast<T>(-0.6398703759826468),
static_cast<T>(0.13584489959258635),
};
static const T correction[] = {
static_cast<T>(0.62996052494743658238360530363911), // 2^-2/3
static_cast<T>(0.79370052598409973737585281963615), // 2^-1/3
static_cast<T>(1),
static_cast<T>(1.2599210498948731647672106072782), // 2^1/3
static_cast<T>(1.5874010519681994747517056392723), // 2^2/3
};
if(!(boost::math::isfinite)(z))
{
return policies::raise_domain_error("boost::math::cbrt<%1%>(%1%)", "Argument to function must be finite but got %1%.", z, pol);
}
int i_exp, sign(1);
if(z < 0)
{
z = -z;
sign = -sign;
}
if(z == 0)
return 0;
T guess = frexp(z, &i_exp);
int original_i_exp = i_exp; // save for later
guess = tools::evaluate_polynomial(P, guess);
int i_exp3 = i_exp / 3;
typedef typename largest_cbrt_int_type<T>::type shift_type;
BOOST_STATIC_ASSERT( ::std::numeric_limits<shift_type>::radix == 2);
if(abs(i_exp3) < std::numeric_limits<shift_type>::digits)
{
if(i_exp3 > 0)
guess *= shift_type(1u) << i_exp3;
else
guess /= shift_type(1u) << -i_exp3;
}
else
{
guess = ldexp(guess, i_exp3);
}
i_exp %= 3;
guess *= correction[i_exp + 2];
//
// Now inline Halley iteration.
// We do this here rather than calling tools::halley_iterate since we can
// simplify the expressions algebraically, and don't need most of the error
// checking of the boilerplate version as we know in advance that the function
// is well behaved...
//
typedef typename policies::precision<T, Policy>::type prec;
typedef typename mpl::divides<prec, mpl::int_<3> >::type prec3;
typedef typename mpl::plus<prec3, mpl::int_<3> >::type new_prec;
typedef typename policies::normalise<Policy, policies::digits2<new_prec::value> >::type new_policy;
//
// Epsilon calculation uses compile time arithmetic when it's available for type T,
// otherwise uses ldexp to calculate at runtime:
//
T eps = (new_prec::value > 3) ? policies::get_epsilon<T, new_policy>() : ldexp(T(1), -2 - tools::digits<T>() / 3);
T diff;
if(original_i_exp < std::numeric_limits<T>::max_exponent - 3)
{
//
// Safe from overflow, use the fast method:
//
do
{
T g3 = guess * guess * guess;
diff = (g3 + z + z) / (g3 + g3 + z);
guess *= diff;
}
while(fabs(1 - diff) > eps);
}
else
{
//
// Either we're ready to overflow, or we can't tell because numeric_limits isn't
// available for type T:
//
do
{
T g2 = guess * guess;
diff = (g2 - z / guess) / (2 * guess + z / g2);
guess -= diff;
}
while((guess * eps) < fabs(diff));
}
return sign * guess;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type cbrt(T z, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return static_cast<result_type>(detail::cbrt_imp(value_type(z), pol));
}
template <class T>
inline typename tools::promote_args<T>::type cbrt(T z)
{
return cbrt(z, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SF_CBRT_HPP

View File

@@ -0,0 +1,68 @@
// 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)
#ifndef BOOST_MATH_COS_PI_HPP
#define BOOST_MATH_COS_PI_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/constants/constants.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
T cos_pi_imp(T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
// cos of pi*x:
bool invert = false;
if(fabs(x) < 0.5)
return cos(constants::pi<T>() * x);
if(x < 1)
{
x = -x;
}
T rem = floor(x);
if(itrunc(rem, pol) & 1)
invert = !invert;
rem = x - rem;
if(rem > 0.5f)
{
rem = 1 - rem;
invert = !invert;
}
if(rem == 0.5f)
return 0;
rem = cos(constants::pi<T>() * rem);
return invert ? T(-rem) : rem;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type cos_pi(T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
return boost::math::detail::cos_pi_imp<result_type>(x, pol);
}
template <class T>
inline typename tools::promote_args<T>::type cos_pi(T x)
{
return boost::math::cos_pi(x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,101 @@
// 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_I0_HPP
#define BOOST_MATH_BESSEL_I0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/assert.hpp>
// Modified Bessel function of the first kind of order zero
// 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_i0(T x)
{
static const T P1[] = {
static_cast<T>(-2.2335582639474375249e+15L),
static_cast<T>(-5.5050369673018427753e+14L),
static_cast<T>(-3.2940087627407749166e+13L),
static_cast<T>(-8.4925101247114157499e+11L),
static_cast<T>(-1.1912746104985237192e+10L),
static_cast<T>(-1.0313066708737980747e+08L),
static_cast<T>(-5.9545626019847898221e+05L),
static_cast<T>(-2.4125195876041896775e+03L),
static_cast<T>(-7.0935347449210549190e+00L),
static_cast<T>(-1.5453977791786851041e-02L),
static_cast<T>(-2.5172644670688975051e-05L),
static_cast<T>(-3.0517226450451067446e-08L),
static_cast<T>(-2.6843448573468483278e-11L),
static_cast<T>(-1.5982226675653184646e-14L),
static_cast<T>(-5.2487866627945699800e-18L),
};
static const T Q1[] = {
static_cast<T>(-2.2335582639474375245e+15L),
static_cast<T>(7.8858692566751002988e+12L),
static_cast<T>(-1.2207067397808979846e+10L),
static_cast<T>(1.0377081058062166144e+07L),
static_cast<T>(-4.8527560179962773045e+03L),
static_cast<T>(1.0L),
};
static const T P2[] = {
static_cast<T>(-2.2210262233306573296e-04L),
static_cast<T>(1.3067392038106924055e-02L),
static_cast<T>(-4.4700805721174453923e-01L),
static_cast<T>(5.5674518371240761397e+00L),
static_cast<T>(-2.3517945679239481621e+01L),
static_cast<T>(3.1611322818701131207e+01L),
static_cast<T>(-9.6090021968656180000e+00L),
};
static const T Q2[] = {
static_cast<T>(-5.5194330231005480228e-04L),
static_cast<T>(3.2547697594819615062e-02L),
static_cast<T>(-1.1151759188741312645e+00L),
static_cast<T>(1.3982595353892851542e+01L),
static_cast<T>(-6.0228002066743340583e+01L),
static_cast<T>(8.5539563258012929600e+01L),
static_cast<T>(-3.1446690275135491500e+01L),
static_cast<T>(1.0L),
};
T value, factor, r;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
if (x < 0)
{
x = -x; // even function
}
if (x == 0)
{
return static_cast<T>(1);
}
if (x <= 15) // x in (0, 15]
{
T y = x * x;
value = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
}
else // x in (15, \infty)
{
T y = 1 / x - T(1) / 15;
r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
factor = exp(x) / sqrt(x);
value = factor * r;
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_I0_HPP

View File

@@ -0,0 +1,104 @@
// 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_I1_HPP
#define BOOST_MATH_BESSEL_I1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.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(T x)
{
static const T P1[] = {
static_cast<T>(-1.4577180278143463643e+15L),
static_cast<T>(-1.7732037840791591320e+14L),
static_cast<T>(-6.9876779648010090070e+12L),
static_cast<T>(-1.3357437682275493024e+11L),
static_cast<T>(-1.4828267606612366099e+09L),
static_cast<T>(-1.0588550724769347106e+07L),
static_cast<T>(-5.1894091982308017540e+04L),
static_cast<T>(-1.8225946631657315931e+02L),
static_cast<T>(-4.7207090827310162436e-01L),
static_cast<T>(-9.1746443287817501309e-04L),
static_cast<T>(-1.3466829827635152875e-06L),
static_cast<T>(-1.4831904935994647675e-09L),
static_cast<T>(-1.1928788903603238754e-12L),
static_cast<T>(-6.5245515583151902910e-16L),
static_cast<T>(-1.9705291802535139930e-19L),
};
static const T Q1[] = {
static_cast<T>(-2.9154360556286927285e+15L),
static_cast<T>(9.7887501377547640438e+12L),
static_cast<T>(-1.4386907088588283434e+10L),
static_cast<T>(1.1594225856856884006e+07L),
static_cast<T>(-5.1326864679904189920e+03L),
static_cast<T>(1.0L),
};
static const T P2[] = {
static_cast<T>(1.4582087408985668208e-05L),
static_cast<T>(-8.9359825138577646443e-04L),
static_cast<T>(2.9204895411257790122e-02L),
static_cast<T>(-3.4198728018058047439e-01L),
static_cast<T>(1.3960118277609544334e+00L),
static_cast<T>(-1.9746376087200685843e+00L),
static_cast<T>(8.5591872901933459000e-01L),
static_cast<T>(-6.0437159056137599999e-02L),
};
static const T Q2[] = {
static_cast<T>(3.7510433111922824643e-05L),
static_cast<T>(-2.2835624489492512649e-03L),
static_cast<T>(7.4212010813186530069e-02L),
static_cast<T>(-8.5017476463217924408e-01L),
static_cast<T>(3.2593714889036996297e+00L),
static_cast<T>(-3.8806586721556593450e+00L),
static_cast<T>(1.0L),
};
T value, factor, r, w;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
w = abs(x);
if (x == 0)
{
return static_cast<T>(0);
}
if (w <= 15) // w in (0, 15]
{
T y = x * x;
r = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
factor = w;
value = factor * r;
}
else // w in (15, \infty)
{
T y = 1 / w - T(1) / 15;
r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
factor = exp(w) / sqrt(w);
value = factor * r;
}
if (x < 0)
{
value *= -value; // odd function
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_I1_HPP

View File

@@ -0,0 +1,413 @@
// 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;
// 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;
// S converges slower than f
BOOST_MATH_INSTRUMENT_VARIABLE(Q * delta);
BOOST_MATH_INSTRUMENT_VARIABLE(abs(S) * tolerance);
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);
*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
}
prev = Ku;
current = Ku1;
T scale = 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;
current = 1;
}
next = fact * current + prev;
prev = current;
current = next;
}
Kv = prev;
Kv1 = current;
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((x / v < 0.25) && (v > 0))
{
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) * sign(scale) * 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) * sign(scale) * 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,152 @@
// 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/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)
{
static const T P1[] = {
static_cast<T>(-4.1298668500990866786e+11L),
static_cast<T>(2.7282507878605942706e+10L),
static_cast<T>(-6.2140700423540120665e+08L),
static_cast<T>(6.6302997904833794242e+06L),
static_cast<T>(-3.6629814655107086448e+04L),
static_cast<T>(1.0344222815443188943e+02L),
static_cast<T>(-1.2117036164593528341e-01L)
};
static const T Q1[] = {
static_cast<T>(2.3883787996332290397e+12L),
static_cast<T>(2.6328198300859648632e+10L),
static_cast<T>(1.3985097372263433271e+08L),
static_cast<T>(4.5612696224219938200e+05L),
static_cast<T>(9.3614022392337710626e+02L),
static_cast<T>(1.0L),
static_cast<T>(0.0L)
};
static const T P2[] = {
static_cast<T>(-1.8319397969392084011e+03L),
static_cast<T>(-1.2254078161378989535e+04L),
static_cast<T>(-7.2879702464464618998e+03L),
static_cast<T>(1.0341910641583726701e+04L),
static_cast<T>(1.1725046279757103576e+04L),
static_cast<T>(4.4176707025325087628e+03L),
static_cast<T>(7.4321196680624245801e+02L),
static_cast<T>(4.8591703355916499363e+01L)
};
static const T Q2[] = {
static_cast<T>(-3.5783478026152301072e+05L),
static_cast<T>(2.4599102262586308984e+05L),
static_cast<T>(-8.4055062591169562211e+04L),
static_cast<T>(1.8680990008359188352e+04L),
static_cast<T>(-2.9458766545509337327e+03L),
static_cast<T>(3.3307310774649071172e+02L),
static_cast<T>(-2.5258076240801555057e+01L),
static_cast<T>(1.0L)
};
static const T PC[] = {
static_cast<T>(2.2779090197304684302e+04L),
static_cast<T>(4.1345386639580765797e+04L),
static_cast<T>(2.1170523380864944322e+04L),
static_cast<T>(3.4806486443249270347e+03L),
static_cast<T>(1.5376201909008354296e+02L),
static_cast<T>(8.8961548424210455236e-01L)
};
static const T QC[] = {
static_cast<T>(2.2779090197304684318e+04L),
static_cast<T>(4.1370412495510416640e+04L),
static_cast<T>(2.1215350561880115730e+04L),
static_cast<T>(3.5028735138235608207e+03L),
static_cast<T>(1.5711159858080893649e+02L),
static_cast<T>(1.0L)
};
static const T PS[] = {
static_cast<T>(-8.9226600200800094098e+01L),
static_cast<T>(-1.8591953644342993800e+02L),
static_cast<T>(-1.1183429920482737611e+02L),
static_cast<T>(-2.2300261666214198472e+01L),
static_cast<T>(-1.2441026745835638459e+00L),
static_cast<T>(-8.8033303048680751817e-03L)
};
static const T QS[] = {
static_cast<T>(5.7105024128512061905e+03L),
static_cast<T>(1.1951131543434613647e+04L),
static_cast<T>(7.2642780169211018836e+03L),
static_cast<T>(1.4887231232283756582e+03L),
static_cast<T>(9.0593769594993125859e+01L),
static_cast<T>(1.0L)
};
static const T x1 = static_cast<T>(2.4048255576957727686e+00L),
x2 = static_cast<T>(5.5200781102863106496e+00L),
x11 = static_cast<T>(6.160e+02L),
x12 = static_cast<T>(-1.42444230422723137837e-03L),
x21 = static_cast<T>(1.4130e+03L),
x22 = static_cast<T>(5.46860286310649596604e-04L);
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;
T z = x - 0.25f * pi<T>();
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 = sqrt(2 / (x * pi<T>()));
value = factor * (rc * cos(z) - y * rs * sin(z));
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_J0_HPP

View File

@@ -0,0 +1,157 @@
// 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/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)
{
static const T P1[] = {
static_cast<T>(-1.4258509801366645672e+11L),
static_cast<T>(6.6781041261492395835e+09L),
static_cast<T>(-1.1548696764841276794e+08L),
static_cast<T>(9.8062904098958257677e+05L),
static_cast<T>(-4.4615792982775076130e+03L),
static_cast<T>(1.0650724020080236441e+01L),
static_cast<T>(-1.0767857011487300348e-02L)
};
static const T Q1[] = {
static_cast<T>(4.1868604460820175290e+12L),
static_cast<T>(4.2091902282580133541e+10L),
static_cast<T>(2.0228375140097033958e+08L),
static_cast<T>(5.9117614494174794095e+05L),
static_cast<T>(1.0742272239517380498e+03L),
static_cast<T>(1.0L),
static_cast<T>(0.0L)
};
static const T P2[] = {
static_cast<T>(-1.7527881995806511112e+16L),
static_cast<T>(1.6608531731299018674e+15L),
static_cast<T>(-3.6658018905416665164e+13L),
static_cast<T>(3.5580665670910619166e+11L),
static_cast<T>(-1.8113931269860667829e+09L),
static_cast<T>(5.0793266148011179143e+06L),
static_cast<T>(-7.5023342220781607561e+03L),
static_cast<T>(4.6179191852758252278e+00L)
};
static const T Q2[] = {
static_cast<T>(1.7253905888447681194e+18L),
static_cast<T>(1.7128800897135812012e+16L),
static_cast<T>(8.4899346165481429307e+13L),
static_cast<T>(2.7622777286244082666e+11L),
static_cast<T>(6.4872502899596389593e+08L),
static_cast<T>(1.1267125065029138050e+06L),
static_cast<T>(1.3886978985861357615e+03L),
static_cast<T>(1.0L)
};
static const T PC[] = {
static_cast<T>(-4.4357578167941278571e+06L),
static_cast<T>(-9.9422465050776411957e+06L),
static_cast<T>(-6.6033732483649391093e+06L),
static_cast<T>(-1.5235293511811373833e+06L),
static_cast<T>(-1.0982405543459346727e+05L),
static_cast<T>(-1.6116166443246101165e+03L),
static_cast<T>(0.0L)
};
static const T QC[] = {
static_cast<T>(-4.4357578167941278568e+06L),
static_cast<T>(-9.9341243899345856590e+06L),
static_cast<T>(-6.5853394797230870728e+06L),
static_cast<T>(-1.5118095066341608816e+06L),
static_cast<T>(-1.0726385991103820119e+05L),
static_cast<T>(-1.4550094401904961825e+03L),
static_cast<T>(1.0L)
};
static const T PS[] = {
static_cast<T>(3.3220913409857223519e+04L),
static_cast<T>(8.5145160675335701966e+04L),
static_cast<T>(6.6178836581270835179e+04L),
static_cast<T>(1.8494262873223866797e+04L),
static_cast<T>(1.7063754290207680021e+03L),
static_cast<T>(3.5265133846636032186e+01L),
static_cast<T>(0.0L)
};
static const T QS[] = {
static_cast<T>(7.0871281941028743574e+05L),
static_cast<T>(1.8194580422439972989e+06L),
static_cast<T>(1.4194606696037208929e+06L),
static_cast<T>(4.0029443582266975117e+05L),
static_cast<T>(3.7890229745772202641e+04L),
static_cast<T>(8.6383677696049909675e+02L),
static_cast<T>(1.0L)
};
static const T x1 = static_cast<T>(3.8317059702075123156e+00L),
x2 = static_cast<T>(7.0155866698156187535e+00L),
x11 = static_cast<T>(9.810e+02L),
x12 = static_cast<T>(-3.2527979248768438556e-04L),
x21 = static_cast<T>(1.7960e+03L),
x22 = static_cast<T>(-3.8330184381246462950e-05L);
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;
T z = w - 0.75f * pi<T>();
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 = sqrt(2 / (w * pi<T>()));
value = factor * (rc * cos(z) - y * rs * sin(z));
}
if (x < 0)
{
value *= -1; // odd function
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_J1_HPP

View File

@@ -0,0 +1,124 @@
// 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 = (n & 0x1) ? -1 : 1; // J_{-n}(z) = (-1)^n J_n(z)
n = -n;
}
else
{
factor = 1;
}
//
// Special cases:
//
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);
}
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
if(fabs(x) > asymptotic_bessel_j_limit<T>(n, tag_type()))
return factor * asymptotic_bessel_j_large_x_2<T>(n, x);
BOOST_ASSERT(n > 1);
T scale = 1;
if (n < abs(x)) // forward recurrence
{
prev = bessel_j0(x);
current = bessel_j1(x);
for (int k = 1; k < n; k++)
{
T fact = 2 * k / x;
if((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)
{
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;
for (int k = n; k > 0; k--)
{
T fact = 2 * k / x;
if((tools::max_value<T>() - fabs(prev)) / 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,553 @@
// 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;
//std::cout << "C = " << Cr << " " << Ci << std::endl;
//std::cout << "D = " << Dr << " " << Di << std::endl;
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;
//std::cout << fr << " " << fi << std::endl;
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;
//std::cout << "C = " << Cr << " " << Ci << std::endl;
//std::cout << "D = " << Dr << " " << Di << std::endl;
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;
//std::cout << fr << " " << fi << std::endl;
}
policies::check_series_iterations<T>("boost::math::bessel_jy<%1%>(%1%,%1%) in CF2_jy", k, pol);
*p = fr;
*q = fi;
return 0;
}
enum
{
need_j = 1, 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
kind = need_j|need_y; // need both for reflection formula
}
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 (x == 0)
{
*J = *Y = policies::raise_overflow_error<T>(
function, 0, pol);
return 1;
}
// x is positive until reflection
W = T(2) / (x * pi<T>()); // Wronskian
T Yv_scale = 1;
if((x > 8) && (x < 1000) && 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....
//
T chi = x - fmod(T(v / 2 + 0.25f), T(2)) * boost::math::constants::pi<T>();
T sc = sin(chi);
T cc = cos(chi);
chi = sqrt(2 / (boost::math::constants::pi<T>() * x));
Yv = chi * (p * sc + q * cc);
Jv = chi * (p * cc - q * sc);
}
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 (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;
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):
// define tag type that will dispatch to right limits:
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
T lim, ratio;
switch(kind)
{
case need_j:
lim = asymptotic_bessel_j_limit<T>(v, tag_type());
break;
case need_y:
lim = asymptotic_bessel_y_limit<T>(tag_type());
break;
default:
lim = (std::max)(
asymptotic_bessel_j_limit<T>(v, tag_type()),
asymptotic_bessel_y_limit<T>(tag_type()));
break;
}
if(x > lim)
{
if(kind&need_y)
{
Yu = asymptotic_bessel_y_large_x_2(u, x);
Yu1 = asymptotic_bessel_y_large_x_2(T(u + 1), x);
}
else
Yu = 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
{
CF1_jy(v, x, &fv, &s, pol);
// tiny initial value to prevent overflow
T init = sqrt(tools::min_value<T>());
prev = fv * s * init;
current = s * init;
if(v < max_factorial<T>::value)
{
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:
//
bool over = false;
for (k = n; k > 0; k--) // backward recurrence for J
{
T t = 2 * (u + k) / x;
if(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;
Ju = sign(current) * sqrt(W / (q + gamma * (p - t)));
Jv = Ju * ratio; // normalization
Yu = gamma * Ju;
Yu1 = Yu * (u/x - p - q/gamma);
}
if(kind&need_y)
{
// compute Y:
prev = Yu;
current = Yu1;
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(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(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 * Jv + (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,302 @@
// 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_j_large_x_P(T v, T x)
{
// A&S 9.2.9
T s = 1;
T mu = 4 * v * v;
T ez2 = 8 * x;
ez2 *= ez2;
s -= (mu-1) * (mu-9) / (2 * ez2);
s += (mu-1) * (mu-9) * (mu-25) * (mu - 49) / (24 * ez2 * ez2);
return s;
}
template <class T>
inline T asymptotic_bessel_j_large_x_Q(T v, T x)
{
// A&S 9.2.10
T s = 0;
T mu = 4 * v * v;
T ez = 8*x;
s += (mu-1) / ez;
s -= (mu-1) * (mu-9) * (mu-25) / (6 * ez*ez*ez);
return s;
}
template <class T>
inline T asymptotic_bessel_j_large_x(T v, T x)
{
//
// See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
//
// Also A&S 9.2.5
//
BOOST_MATH_STD_USING // ADL of std names
T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
return sqrt(2 / (constants::pi<T>() * x))
* (asymptotic_bessel_j_large_x_P(v, x) * cos(chi)
- asymptotic_bessel_j_large_x_Q(v, x) * sin(chi));
}
template <class T>
inline T asymptotic_bessel_y_large_x(T v, T x)
{
//
// See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
//
// Also A&S 9.2.5
//
BOOST_MATH_STD_USING // ADL of std names
T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
return sqrt(2 / (constants::pi<T>() * x))
* (asymptotic_bessel_j_large_x_P(v, x) * sin(chi)
- asymptotic_bessel_j_large_x_Q(v, x) * cos(chi));
}
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.
//
T mu = 4 * v * v;
T denom = 4 * x;
T denom_mult = denom * denom;
T s = -constants::pi<T>() * (v / 2 + 0.25f);
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);
//
// Calculate the sine of the phase, using:
// sin(x+p) = sin(x)cos(p) + cos(x)sin(p)
//
T sin_phase = sin(phase) * cos(x) + cos(phase) * 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);
//
// Calculate the sine of the phase, using:
// cos(x+p) = cos(x)cos(p) - sin(x)sin(p)
//
T sin_phase = cos(phase) * cos(x) - sin(phase) * sin(x);
return sin_phase * ampl;
}
//
// Various limits for the J and Y asymptotics
// (the asympotic expansions are safe to use if
// x is less than the limit given).
// We assume that if we don't use these expansions then the
// error will likely be >100eps, so the limits given are chosen
// to lead to < 100eps truncation error.
//
template <class T>
inline T asymptotic_bessel_y_limit(const mpl::int_<0>&)
{
// default case:
BOOST_MATH_STD_USING
return 2.25 / pow(100 * tools::epsilon<T>() / T(0.001f), T(0.2f));
}
template <class T>
inline T asymptotic_bessel_y_limit(const mpl::int_<53>&)
{
// double case:
return 304 /*780*/;
}
template <class T>
inline T asymptotic_bessel_y_limit(const mpl::int_<64>&)
{
// 80-bit extended-double case:
return 1552 /*3500*/;
}
template <class T>
inline T asymptotic_bessel_y_limit(const mpl::int_<113>&)
{
// 128-bit long double case:
return 1245243 /*3128000*/;
}
template <class T, class Policy>
struct bessel_asymptotic_tag
{
typedef typename policies::precision<T, Policy>::type precision_type;
typedef typename mpl::if_<
mpl::or_<
mpl::equal_to<precision_type, mpl::int_<0> >,
mpl::greater<precision_type, mpl::int_<113> > >,
mpl::int_<0>,
typename mpl::if_<
mpl::greater<precision_type, mpl::int_<64> >,
mpl::int_<113>,
typename mpl::if_<
mpl::greater<precision_type, mpl::int_<53> >,
mpl::int_<64>,
mpl::int_<53>
>::type
>::type
>::type type;
};
template <class T>
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<0>&)
{
// default case:
BOOST_MATH_STD_USING
T v2 = (std::max)(T(3), T(v * v));
return v2 / pow(100 * tools::epsilon<T>() / T(2e-5f), T(0.17f));
}
template <class T>
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<53>&)
{
// double case:
T v2 = (std::max)(T(3), v * v);
return v2 * 33 /*73*/;
}
template <class T>
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<64>&)
{
// 80-bit extended-double case:
T v2 = (std::max)(T(3), v * v);
return v2 * 121 /*266*/;
}
template <class T>
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<113>&)
{
// 128-bit long double case:
T v2 = (std::max)(T(3), v * v);
return v2 * 39154 /*85700*/;
}
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,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 s;
prefix = boost::math::lgamma(-v, &s, pol) + p;
prefix = exp(prefix) * s / 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>())) * (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,121 @@
// 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_K0_HPP
#define BOOST_MATH_BESSEL_K0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.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
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T bessel_k0(T x, const Policy& pol)
{
BOOST_MATH_INSTRUMENT_CODE(x);
static const T P1[] = {
static_cast<T>(2.4708152720399552679e+03L),
static_cast<T>(5.9169059852270512312e+03L),
static_cast<T>(4.6850901201934832188e+02L),
static_cast<T>(1.1999463724910714109e+01L),
static_cast<T>(1.3166052564989571850e-01L),
static_cast<T>(5.8599221412826100000e-04L)
};
static const T Q1[] = {
static_cast<T>(2.1312714303849120380e+04L),
static_cast<T>(-2.4994418972832303646e+02L),
static_cast<T>(1.0L)
};
static const T P2[] = {
static_cast<T>(-1.6128136304458193998e+06L),
static_cast<T>(-3.7333769444840079748e+05L),
static_cast<T>(-1.7984434409411765813e+04L),
static_cast<T>(-2.9501657892958843865e+02L),
static_cast<T>(-1.6414452837299064100e+00L)
};
static const T Q2[] = {
static_cast<T>(-1.6128136304458193998e+06L),
static_cast<T>(2.9865713163054025489e+04L),
static_cast<T>(-2.5064972445877992730e+02L),
static_cast<T>(1.0L)
};
static const T P3[] = {
static_cast<T>(1.1600249425076035558e+02L),
static_cast<T>(2.3444738764199315021e+03L),
static_cast<T>(1.8321525870183537725e+04L),
static_cast<T>(7.1557062783764037541e+04L),
static_cast<T>(1.5097646353289914539e+05L),
static_cast<T>(1.7398867902565686251e+05L),
static_cast<T>(1.0577068948034021957e+05L),
static_cast<T>(3.1075408980684392399e+04L),
static_cast<T>(3.6832589957340267940e+03L),
static_cast<T>(1.1394980557384778174e+02L)
};
static const T Q3[] = {
static_cast<T>(9.2556599177304839811e+01L),
static_cast<T>(1.8821890840982713696e+03L),
static_cast<T>(1.4847228371802360957e+04L),
static_cast<T>(5.8824616785857027752e+04L),
static_cast<T>(1.2689839587977598727e+05L),
static_cast<T>(1.5144644673520157801e+05L),
static_cast<T>(9.7418829762268075784e+04L),
static_cast<T>(3.1474655750295278825e+04L),
static_cast<T>(4.4329628889746408858e+03L),
static_cast<T>(2.0013443064949242491e+02L),
static_cast<T>(1.0L)
};
T value, factor, r, r1, r2;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::bessel_k0<%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 (x <= 1) // x in (0, 1]
{
T y = x * x;
r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
factor = log(x);
value = r1 - factor * r2;
}
else // x in (1, \infty)
{
T y = 1 / x;
r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
factor = exp(-x) / sqrt(x);
value = factor * r;
BOOST_MATH_INSTRUMENT_CODE("y = " << y);
BOOST_MATH_INSTRUMENT_CODE("r = " << r);
BOOST_MATH_INSTRUMENT_CODE("factor = " << factor);
BOOST_MATH_INSTRUMENT_CODE("value = " << value);
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_K0_HPP

View File

@@ -0,0 +1,117 @@
// 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_K1_HPP
#define BOOST_MATH_BESSEL_K1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/assert.hpp>
// Modified Bessel function of the second kind of order one
// minimax rational approximations on intervals, see
// Russon and Blair, Chalk River Report AECL-3461, 1969
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T bessel_k1(T x, const Policy& pol)
{
static const T P1[] = {
static_cast<T>(-2.2149374878243304548e+06L),
static_cast<T>(7.1938920065420586101e+05L),
static_cast<T>(1.7733324035147015630e+05L),
static_cast<T>(7.1885382604084798576e+03L),
static_cast<T>(9.9991373567429309922e+01L),
static_cast<T>(4.8127070456878442310e-01L)
};
static const T Q1[] = {
static_cast<T>(-2.2149374878243304548e+06L),
static_cast<T>(3.7264298672067697862e+04L),
static_cast<T>(-2.8143915754538725829e+02L),
static_cast<T>(1.0L)
};
static const T P2[] = {
static_cast<T>(0.0L),
static_cast<T>(-1.3531161492785421328e+06L),
static_cast<T>(-1.4758069205414222471e+05L),
static_cast<T>(-4.5051623763436087023e+03L),
static_cast<T>(-5.3103913335180275253e+01L),
static_cast<T>(-2.2795590826955002390e-01L)
};
static const T Q2[] = {
static_cast<T>(-2.7062322985570842656e+06L),
static_cast<T>(4.3117653211351080007e+04L),
static_cast<T>(-3.0507151578787595807e+02L),
static_cast<T>(1.0L)
};
static const T P3[] = {
static_cast<T>(2.2196792496874548962e+00L),
static_cast<T>(4.4137176114230414036e+01L),
static_cast<T>(3.4122953486801312910e+02L),
static_cast<T>(1.3319486433183221990e+03L),
static_cast<T>(2.8590657697910288226e+03L),
static_cast<T>(3.4540675585544584407e+03L),
static_cast<T>(2.3123742209168871550e+03L),
static_cast<T>(8.1094256146537402173e+02L),
static_cast<T>(1.3182609918569941308e+02L),
static_cast<T>(7.5584584631176030810e+00L),
static_cast<T>(6.4257745859173138767e-02L)
};
static const T Q3[] = {
static_cast<T>(1.7710478032601086579e+00L),
static_cast<T>(3.4552228452758912848e+01L),
static_cast<T>(2.5951223655579051357e+02L),
static_cast<T>(9.6929165726802648634e+02L),
static_cast<T>(1.9448440788918006154e+03L),
static_cast<T>(2.1181000487171943810e+03L),
static_cast<T>(1.2082692316002348638e+03L),
static_cast<T>(3.3031020088765390854e+02L),
static_cast<T>(3.6001069306861518855e+01L),
static_cast<T>(1.0L)
};
T value, factor, r, r1, r2;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::bessel_k1<%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 (x <= 1) // x in (0, 1]
{
T y = x * x;
r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
factor = log(x);
value = (r1 + factor * r2) / x;
}
else // x in (1, \infty)
{
T y = 1 / x;
r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
factor = exp(-x) / sqrt(x);
value = factor * r;
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_K1_HPP

View File

@@ -0,0 +1,85 @@
// 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)
{
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, pol);
}
else if (n == 1)
{
value = bessel_k1(x, pol);
}
else
{
prev = bessel_k0(x, pol);
current = bessel_k1(x, pol);
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,182 @@
// 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
#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/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& pol)
{
static const T P1[] = {
static_cast<T>(1.0723538782003176831e+11L),
static_cast<T>(-8.3716255451260504098e+09L),
static_cast<T>(2.0422274357376619816e+08L),
static_cast<T>(-2.1287548474401797963e+06L),
static_cast<T>(1.0102532948020907590e+04L),
static_cast<T>(-1.8402381979244993524e+01L),
};
static const T Q1[] = {
static_cast<T>(5.8873865738997033405e+11L),
static_cast<T>(8.1617187777290363573e+09L),
static_cast<T>(5.5662956624278251596e+07L),
static_cast<T>(2.3889393209447253406e+05L),
static_cast<T>(6.6475986689240190091e+02L),
static_cast<T>(1.0L),
};
static const T P2[] = {
static_cast<T>(-2.2213976967566192242e+13L),
static_cast<T>(-5.5107435206722644429e+11L),
static_cast<T>(4.3600098638603061642e+10L),
static_cast<T>(-6.9590439394619619534e+08L),
static_cast<T>(4.6905288611678631510e+06L),
static_cast<T>(-1.4566865832663635920e+04L),
static_cast<T>(1.7427031242901594547e+01L),
};
static const T Q2[] = {
static_cast<T>(4.3386146580707264428e+14L),
static_cast<T>(5.4266824419412347550e+12L),
static_cast<T>(3.4015103849971240096e+10L),
static_cast<T>(1.3960202770986831075e+08L),
static_cast<T>(4.0669982352539552018e+05L),
static_cast<T>(8.3030857612070288823e+02L),
static_cast<T>(1.0L),
};
static const T P3[] = {
static_cast<T>(-8.0728726905150210443e+15L),
static_cast<T>(6.7016641869173237784e+14L),
static_cast<T>(-1.2829912364088687306e+11L),
static_cast<T>(-1.9363051266772083678e+11L),
static_cast<T>(2.1958827170518100757e+09L),
static_cast<T>(-1.0085539923498211426e+07L),
static_cast<T>(2.1363534169313901632e+04L),
static_cast<T>(-1.7439661319197499338e+01L),
};
static const T Q3[] = {
static_cast<T>(3.4563724628846457519e+17L),
static_cast<T>(3.9272425569640309819e+15L),
static_cast<T>(2.2598377924042897629e+13L),
static_cast<T>(8.6926121104209825246e+10L),
static_cast<T>(2.4727219475672302327e+08L),
static_cast<T>(5.3924739209768057030e+05L),
static_cast<T>(8.7903362168128450017e+02L),
static_cast<T>(1.0L),
};
static const T PC[] = {
static_cast<T>(2.2779090197304684302e+04L),
static_cast<T>(4.1345386639580765797e+04L),
static_cast<T>(2.1170523380864944322e+04L),
static_cast<T>(3.4806486443249270347e+03L),
static_cast<T>(1.5376201909008354296e+02L),
static_cast<T>(8.8961548424210455236e-01L),
};
static const T QC[] = {
static_cast<T>(2.2779090197304684318e+04L),
static_cast<T>(4.1370412495510416640e+04L),
static_cast<T>(2.1215350561880115730e+04L),
static_cast<T>(3.5028735138235608207e+03L),
static_cast<T>(1.5711159858080893649e+02L),
static_cast<T>(1.0L),
};
static const T PS[] = {
static_cast<T>(-8.9226600200800094098e+01L),
static_cast<T>(-1.8591953644342993800e+02L),
static_cast<T>(-1.1183429920482737611e+02L),
static_cast<T>(-2.2300261666214198472e+01L),
static_cast<T>(-1.2441026745835638459e+00L),
static_cast<T>(-8.8033303048680751817e-03L),
};
static const T QS[] = {
static_cast<T>(5.7105024128512061905e+03L),
static_cast<T>(1.1951131543434613647e+04L),
static_cast<T>(7.2642780169211018836e+03L),
static_cast<T>(1.4887231232283756582e+03L),
static_cast<T>(9.0593769594993125859e+01L),
static_cast<T>(1.0L),
};
static const T x1 = static_cast<T>(8.9357696627916752158e-01L),
x2 = static_cast<T>(3.9576784193148578684e+00L),
x3 = static_cast<T>(7.0860510603017726976e+00L),
x11 = static_cast<T>(2.280e+02L),
x12 = static_cast<T>(2.9519662791675215849e-03L),
x21 = static_cast<T>(1.0130e+03L),
x22 = static_cast<T>(6.4716931485786837568e-04L),
x31 = static_cast<T>(1.8140e+03L),
x32 = static_cast<T>(1.1356030177269762362e-04L)
;
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;
T z = x - 0.25f * pi<T>();
rc = evaluate_rational(PC, QC, y2);
rs = evaluate_rational(PS, QS, y2);
factor = sqrt(2 / (x * pi<T>()));
value = factor * (rc * sin(z) + y * rs * cos(z));
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_Y0_HPP

View File

@@ -0,0 +1,155 @@
// 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
#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/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& pol)
{
static const T P1[] = {
static_cast<T>(4.0535726612579544093e+13L),
static_cast<T>(5.4708611716525426053e+12L),
static_cast<T>(-3.7595974497819597599e+11L),
static_cast<T>(7.2144548214502560419e+09L),
static_cast<T>(-5.9157479997408395984e+07L),
static_cast<T>(2.2157953222280260820e+05L),
static_cast<T>(-3.1714424660046133456e+02L),
};
static const T Q1[] = {
static_cast<T>(3.0737873921079286084e+14L),
static_cast<T>(4.1272286200406461981e+12L),
static_cast<T>(2.7800352738690585613e+10L),
static_cast<T>(1.2250435122182963220e+08L),
static_cast<T>(3.8136470753052572164e+05L),
static_cast<T>(8.2079908168393867438e+02L),
static_cast<T>(1.0L),
};
static const T P2[] = {
static_cast<T>(1.1514276357909013326e+19L),
static_cast<T>(-5.6808094574724204577e+18L),
static_cast<T>(-2.3638408497043134724e+16L),
static_cast<T>(4.0686275289804744814e+15L),
static_cast<T>(-5.9530713129741981618e+13L),
static_cast<T>(3.7453673962438488783e+11L),
static_cast<T>(-1.1957961912070617006e+09L),
static_cast<T>(1.9153806858264202986e+06L),
static_cast<T>(-1.2337180442012953128e+03L),
};
static const T Q2[] = {
static_cast<T>(5.3321844313316185697e+20L),
static_cast<T>(5.6968198822857178911e+18L),
static_cast<T>(3.0837179548112881950e+16L),
static_cast<T>(1.1187010065856971027e+14L),
static_cast<T>(3.0221766852960403645e+11L),
static_cast<T>(6.3550318087088919566e+08L),
static_cast<T>(1.0453748201934079734e+06L),
static_cast<T>(1.2855164849321609336e+03L),
static_cast<T>(1.0L),
};
static const T PC[] = {
static_cast<T>(-4.4357578167941278571e+06L),
static_cast<T>(-9.9422465050776411957e+06L),
static_cast<T>(-6.6033732483649391093e+06L),
static_cast<T>(-1.5235293511811373833e+06L),
static_cast<T>(-1.0982405543459346727e+05L),
static_cast<T>(-1.6116166443246101165e+03L),
static_cast<T>(0.0L),
};
static const T QC[] = {
static_cast<T>(-4.4357578167941278568e+06L),
static_cast<T>(-9.9341243899345856590e+06L),
static_cast<T>(-6.5853394797230870728e+06L),
static_cast<T>(-1.5118095066341608816e+06L),
static_cast<T>(-1.0726385991103820119e+05L),
static_cast<T>(-1.4550094401904961825e+03L),
static_cast<T>(1.0L),
};
static const T PS[] = {
static_cast<T>(3.3220913409857223519e+04L),
static_cast<T>(8.5145160675335701966e+04L),
static_cast<T>(6.6178836581270835179e+04L),
static_cast<T>(1.8494262873223866797e+04L),
static_cast<T>(1.7063754290207680021e+03L),
static_cast<T>(3.5265133846636032186e+01L),
static_cast<T>(0.0L),
};
static const T QS[] = {
static_cast<T>(7.0871281941028743574e+05L),
static_cast<T>(1.8194580422439972989e+06L),
static_cast<T>(1.4194606696037208929e+06L),
static_cast<T>(4.0029443582266975117e+05L),
static_cast<T>(3.7890229745772202641e+04L),
static_cast<T>(8.6383677696049909675e+02L),
static_cast<T>(1.0L),
};
static const T x1 = static_cast<T>(2.1971413260310170351e+00L),
x2 = static_cast<T>(5.4296810407941351328e+00L),
x11 = static_cast<T>(5.620e+02L),
x12 = static_cast<T>(1.8288260310170351490e-03L),
x21 = static_cast<T>(1.3900e+03L),
x22 = static_cast<T>(-6.4592058648672279948e-06L)
;
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;
T z = x - 0.75f * pi<T>();
rc = evaluate_rational(PC, QC, y2);
rs = evaluate_rational(PS, QS, y2);
factor = sqrt(2 / (x * pi<T>()));
value = factor * (rc * sin(z) + y * rs * cos(z));
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_Y1_HPP

View File

@@ -0,0 +1,103 @@
// 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 = (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 (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);
do
{
T fact = 2 * k / x;
if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
{
prev /= current;
factor /= current;
current = 1;
}
value = fact * current - prev;
prev = current;
current = value;
++k;
}
while(k < n);
if(tools::max_value<T>() * factor < value)
return sign(value) * sign(value) * policies::raise_overflow_error<T>(function, 0, pol);
value /= factor;
}
return value;
}
}}} // namespaces
#endif // BOOST_MATH_BESSEL_YN_HPP

View File

@@ -0,0 +1,471 @@
// (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
#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[] = {
-0.000508781949658280665617L,
-0.00836874819741736770379L,
0.0334806625409744615033L,
-0.0126926147662974029034L,
-0.0365637971411762664006L,
0.0219878681111168899165L,
0.00822687874676915743155L,
-0.00538772965071242932965L
};
static const T Q[] = {
1,
-0.970005043303290640362L,
-1.56574558234175846809L,
1.56221558398423026363L,
0.662328840472002992063L,
-0.71228902341542847553L,
-0.0527396382340099713954L,
0.0795283687341571680018L,
-0.00233393759374190016776L,
0.000886216390456424707504L
};
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[] = {
-0.202433508355938759655L,
0.105264680699391713268L,
8.37050328343119927838L,
17.6447298408374015486L,
-18.8510648058714251895L,
-44.6382324441786960818L,
17.445385985570866523L,
21.1294655448340526258L,
-3.67192254707729348546L
};
static const T Q[] = {
1L,
6.24264124854247537712L,
3.9713437953343869095L,
-28.6608180499800029974L,
-20.1432634680485188801L,
48.5609213108739935468L,
10.8268667355460159008L,
-22.6436933413139721736L,
1.72114765761200282724L
};
T g = sqrt(-2 * log(q));
T xs = q - 0.25;
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[] = {
-0.131102781679951906451L,
-0.163794047193317060787L,
0.117030156341995252019L,
0.387079738972604337464L,
0.337785538912035898924L,
0.142869534408157156766L,
0.0290157910005329060432L,
0.00214558995388805277169L,
-0.679465575181126350155e-6L,
0.285225331782217055858e-7L,
-0.681149956853776992068e-9L
};
static const T Q[] = {
1,
3.46625407242567245975L,
5.38168345707006855425L,
4.77846592945843778382L,
2.59301921623620271374L,
0.848854343457902036425L,
0.152264338295331783612L,
0.01105924229346489121L
};
T xs = x - 1.125;
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[] = {
-0.0350353787183177984712L,
-0.00222426529213447927281L,
0.0185573306514231072324L,
0.00950804701325919603619L,
0.00187123492819559223345L,
0.000157544617424960554631L,
0.460469890584317994083e-5L,
-0.230404776911882601748e-9L,
0.266339227425782031962e-11L
};
static const T Q[] = {
1L,
1.3653349817554063097L,
0.762059164553623404043L,
0.220091105764131249824L,
0.0341589143670947727934L,
0.00263861676657015992959L,
0.764675292302794483503e-4L
};
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[] = {
-0.0167431005076633737133L,
-0.00112951438745580278863L,
0.00105628862152492910091L,
0.000209386317487588078668L,
0.149624783758342370182e-4L,
0.449696789927706453732e-6L,
0.462596163522878599135e-8L,
-0.281128735628831791805e-13L,
0.99055709973310326855e-16L
};
static const T Q[] = {
1L,
0.591429344886417493481L,
0.138151865749083321638L,
0.0160746087093676504695L,
0.000964011807005165528527L,
0.275335474764726041141e-4L,
0.282243172016108031869e-6L
};
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[] = {
-0.0024978212791898131227L,
-0.779190719229053954292e-5L,
0.254723037413027451751e-4L,
0.162397777342510920873e-5L,
0.396341011304801168516e-7L,
0.411632831190944208473e-9L,
0.145596286718675035587e-11L,
-0.116765012397184275695e-17L
};
static const T Q[] = {
1L,
0.207123112214422517181L,
0.0169410838120975906478L,
0.000690538265622684595676L,
0.145007359818232637924e-4L,
0.144437756628144157666e-6L,
0.509761276599778486139e-9L
};
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[] = {
-0.000539042911019078575891L,
-0.28398759004727721098e-6L,
0.899465114892291446442e-6L,
0.229345859265920864296e-7L,
0.225561444863500149219e-9L,
0.947846627503022684216e-12L,
0.135880130108924861008e-14L,
-0.348890393399948882918e-21L
};
static const T Q[] = {
1L,
0.0845746234001899436914L,
0.00282092984726264681981L,
0.468292921940894236786e-4L,
0.399968812193862100054e-6L,
0.161809290887904476097e-8L,
0.231558608310259605225e-11L
};
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) ? boost::math::erf(guess, Policy()) : 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;
}
} // 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))
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;
//
// 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))
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;
//
// 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
#endif // BOOST_MATH_SF_ERF_INV_HPP

View File

@@ -0,0 +1,570 @@
// 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/detail/endian.hpp>
#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(...)
{
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 defined(BOOST_BIG_ENDIAN)
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif defined(BOOST_LITTLE_ENDIAN)
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 defined(BOOST_BIG_ENDIAN)
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif defined(BOOST_LITTLE_ENDIAN)
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).
// 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 defined(BOOST_BIG_ENDIAN)
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif defined(BOOST_LITTLE_ENDIAN)
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 defined(BOOST_BIG_ENDIAN)
BOOST_STATIC_CONSTANT(int, offset_ = 0);
#elif defined(BOOST_LITTLE_ENDIAN)
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(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
# 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 tools::max_value<T>();
}
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>())
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)
{
return tools::max_value<result_type>();
}
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)
{
return tools::max_value<result_type>();
}
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,324 @@
// (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>())
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;
if(p == 0)
{
return tools::max_value<result_type>();
}
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),
"boost::math::ibeta_inva<%1%>(%1%,%1%,%1%)");
}
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;
if(q == 1)
{
return tools::max_value<result_type>();
}
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),
"boost::math::ibetac_inva<%1%>(%1%,%1%,%1%)");
}
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;
if(p == 0)
{
return tools::min_value<result_type>();
}
if(p == 1)
{
return tools::max_value<result_type>();
}
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),
"boost::math::ibeta_invb<%1%>(%1%,%1%,%1%)");
}
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)
{
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 tools::max_value<result_type>();
}
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),
"boost::math::ibetac_invb<%1%>(%1%,%1%,%1%)");
}
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,944 @@
// 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(-big, -big);
}
if(x == 0)
{
T big = tools::max_value<T>() / 4;
return boost::math::make_tuple(-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.
//
// 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) && (b == 1))
{
if(py) *py = 1 - p;
return p;
}
//
// 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;
//
// 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) && (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))
{
//
// We have a Student's T distribution:
x = find_ibeta_inv_from_t_dist(a, p, q, &y, pol);
}
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)
{
return ibeta_inv(a, b, p, static_cast<T1*>(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)
{
return ibeta_inv(a, b, p, static_cast<T1*>(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)
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)
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))
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 remove_cv<RT1>::type dummy;
return ibetac_inv(a, b, q, static_cast<dummy*>(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 remove_cv<RT1>::type dummy;
return ibetac_inv(a, b, q, static_cast<dummy*>(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);
}
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,552 @@
// (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);
T s = 1;
z = exp((v + w) / a);
s = boost::math::log1p(z / ap1 * (1 + z / ap2));
z = exp((v + z - s) / a);
s = boost::math::log1p(z / ap1 * (1 + z / ap2));
z = exp((v + z - s) / a);
s = boost::math::log1p(z / ap1 * (1 + z / ap2 * (1 + z / (a + 3))));
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(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)
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))
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 tools::max_value<T>();
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)
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))
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 tools::max_value<T>();
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,769 @@
// 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[] = {
-0.333333333333333333333L,
0.0833333333333333333333L,
-0.0148148148148148148148L,
0.00115740740740740740741L,
0.000352733686067019400353L,
-0.0001787551440329218107L,
0.39192631785224377817e-4L,
-0.218544851067999216147e-5L,
-0.18540622107151599607e-5L,
0.829671134095308600502e-6L,
-0.176659527368260793044e-6L,
0.670785354340149858037e-8L,
0.102618097842403080426e-7L,
-0.438203601845335318655e-8L,
0.914769958223679023418e-9L,
-0.255141939949462497669e-10L,
-0.583077213255042506746e-10L,
0.243619480206674162437e-10L,
-0.502766928011417558909e-11L,
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
-0.00185185185185185185185L,
-0.00347222222222222222222L,
0.00264550264550264550265L,
-0.000990226337448559670782L,
0.000205761316872427983539L,
-0.40187757201646090535e-6L,
-0.18098550334489977837e-4L,
0.764916091608111008464e-5L,
-0.161209008945634460038e-5L,
0.464712780280743434226e-8L,
0.137863344691572095931e-6L,
-0.575254560351770496402e-7L,
0.119516285997781473243e-7L,
-0.175432417197476476238e-10L,
-0.100915437106004126275e-8L,
0.416279299184258263623e-9L,
-0.856390702649298063807e-10L,
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
0.00413359788359788359788L,
-0.00268132716049382716049L,
0.000771604938271604938272L,
0.200938786008230452675e-5L,
-0.000107366532263651605215L,
0.529234488291201254164e-4L,
-0.127606351886187277134e-4L,
0.342357873409613807419e-7L,
0.137219573090629332056e-5L,
-0.629899213838005502291e-6L,
0.142806142060642417916e-6L,
-0.204770984219908660149e-9L,
-0.140925299108675210533e-7L,
0.622897408492202203356e-8L,
-0.136704883966171134993e-8L,
};
workspace[2] = tools::evaluate_polynomial(C2, z);
static const T C3[] = {
0.000649434156378600823045L,
0.000229472093621399176955L,
-0.000469189494395255712128L,
0.000267720632062838852962L,
-0.756180167188397641073e-4L,
-0.239650511386729665193e-6L,
0.110826541153473023615e-4L,
-0.56749528269915965675e-5L,
0.142309007324358839146e-5L,
-0.278610802915281422406e-10L,
-0.169584040919302772899e-6L,
0.809946490538808236335e-7L,
-0.191111684859736540607e-7L,
};
workspace[3] = tools::evaluate_polynomial(C3, z);
static const T C4[] = {
-0.000861888290916711698605L,
0.000784039221720066627474L,
-0.000299072480303190179733L,
-0.146384525788434181781e-5L,
0.664149821546512218666e-4L,
-0.396836504717943466443e-4L,
0.113757269706784190981e-4L,
0.250749722623753280165e-9L,
-0.169541495365583060147e-5L,
0.890750753220530968883e-6L,
-0.229293483400080487057e-6L,
};
workspace[4] = tools::evaluate_polynomial(C4, z);
static const T C5[] = {
-0.000336798553366358150309L,
-0.697281375836585777429e-4L,
0.000277275324495939207873L,
-0.000199325705161888477003L,
0.679778047793720783882e-4L,
0.141906292064396701483e-6L,
-0.135940481897686932785e-4L,
0.801847025633420153972e-5L,
-0.229148117650809517038e-5L,
};
workspace[5] = tools::evaluate_polynomial(C5, z);
static const T C6[] = {
0.000531307936463992223166L,
-0.000592166437353693882865L,
0.000270878209671804482771L,
0.790235323266032787212e-6L,
-0.815396936756196875093e-4L,
0.561168275310624965004e-4L,
-0.183291165828433755673e-4L,
-0.307961345060330478256e-8L,
0.346515536880360908674e-5L,
-0.20291327396058603727e-5L,
0.57887928631490037089e-6L,
};
workspace[6] = tools::evaluate_polynomial(C6, z);
static const T C7[] = {
0.000344367606892377671254L,
0.517179090826059219337e-4L,
-0.000334931610811422363117L,
0.000281269515476323702274L,
-0.000109765822446847310235L,
-0.127410090954844853795e-6L,
0.277444515115636441571e-4L,
-0.182634888057113326614e-4L,
0.578769494973505239894e-5L,
};
workspace[7] = tools::evaluate_polynomial(C7, z);
static const T C8[] = {
-0.000652623918595309418922L,
0.000839498720672087279993L,
-0.000438297098541721005061L,
-0.696909145842055197137e-6L,
0.000166448466420675478374L,
-0.000127835176797692185853L,
0.462995326369130429061e-4L,
};
workspace[8] = tools::evaluate_polynomial(C8, z);
static const T C9[] = {
-0.000596761290192746250124L,
-0.720489541602001055909e-4L,
0.000678230883766732836162L,
-0.0006401475260262758451L,
0.000277501076343287044992L,
};
workspace[9] = tools::evaluate_polynomial(C9, z);
static const T C10[] = {
0.00133244544948006563713L,
-0.0019144384985654775265L,
0.00110893691345966373396L,
};
workspace[10] = tools::evaluate_polynomial(C10, z);
static const T C11[] = {
0.00157972766073083495909L,
0.000162516262783915816899L,
-0.00206334210355432762645L,
0.00213896861856890981541L,
-0.00101085593912630031708L,
};
workspace[11] = tools::evaluate_polynomial(C11, z);
static const T C12[] = {
-0.00407251211951401664727L,
0.00640336283380806979482L,
-0.00404101610816766177474L,
};
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[] = {
-0.333333333333333333333333333333333333L,
0.0833333333333333333333333333333333333L,
-0.0148148148148148148148148148148148148L,
0.00115740740740740740740740740740740741L,
0.0003527336860670194003527336860670194L,
-0.000178755144032921810699588477366255144L,
0.391926317852243778169704095630021556e-4L,
-0.218544851067999216147364295512443661e-5L,
-0.185406221071515996070179883622956325e-5L,
0.829671134095308600501624213166443227e-6L,
-0.17665952736826079304360054245742403e-6L,
0.670785354340149858036939710029613572e-8L,
0.102618097842403080425739573227252951e-7L,
-0.438203601845335318655297462244719123e-8L,
0.914769958223679023418248817633113681e-9L,
-0.255141939949462497668779537993887013e-10L,
-0.583077213255042506746408945040035798e-10L,
0.243619480206674162436940696707789943e-10L,
-0.502766928011417558909054985925744366e-11L,
0.110043920319561347708374174497293411e-12L,
0.337176326240098537882769884169200185e-12L,
-0.13923887224181620659193661848957998e-12L,
0.285348938070474432039669099052828299e-13L,
-0.513911183424257261899064580300494205e-15L,
-0.197522882943494428353962401580710912e-14L,
0.809952115670456133407115668702575255e-15L,
-0.165225312163981618191514820265351162e-15L,
0.253054300974788842327061090060267385e-17L,
0.116869397385595765888230876507793475e-16L,
-0.477003704982048475822167804084816597e-17L,
0.969912605905623712420709685898585354e-18L,
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
-0.00185185185185185185185185185185185185L,
-0.00347222222222222222222222222222222222L,
0.0026455026455026455026455026455026455L,
-0.000990226337448559670781893004115226337L,
0.000205761316872427983539094650205761317L,
-0.401877572016460905349794238683127572e-6L,
-0.180985503344899778370285914867533523e-4L,
0.76491609160811100846374214980916921e-5L,
-0.16120900894563446003775221882217767e-5L,
0.464712780280743434226135033938722401e-8L,
0.137863344691572095931187533077488877e-6L,
-0.575254560351770496402194531835048307e-7L,
0.119516285997781473243076536699698169e-7L,
-0.175432417197476476237547551202312502e-10L,
-0.100915437106004126274577504686681675e-8L,
0.416279299184258263623372347219858628e-9L,
-0.856390702649298063807431562579670208e-10L,
0.606721510160475861512701762169919581e-13L,
0.716249896481148539007961017165545733e-11L,
-0.293318664377143711740636683615595403e-11L,
0.599669636568368872330374527568788909e-12L,
-0.216717865273233141017100472779701734e-15L,
-0.497833997236926164052815522048108548e-13L,
0.202916288237134247736694804325894226e-13L,
-0.413125571381061004935108332558187111e-14L,
0.828651623988309644380188591057589316e-18L,
0.341003088693333279336339355910600992e-15L,
-0.138541953028939715357034547426313703e-15L,
0.281234665322887466568860332727259483e-16L,
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
0.0041335978835978835978835978835978836L,
-0.00268132716049382716049382716049382716L,
0.000771604938271604938271604938271604938L,
0.200938786008230452674897119341563786e-5L,
-0.000107366532263651605215391223621676297L,
0.529234488291201254164217127180090143e-4L,
-0.127606351886187277133779191392360117e-4L,
0.34235787340961380741902003904747389e-7L,
0.137219573090629332055943852926020279e-5L,
-0.629899213838005502290672234278391876e-6L,
0.142806142060642417915846008822771748e-6L,
-0.204770984219908660149195854409200226e-9L,
-0.140925299108675210532930244154315272e-7L,
0.622897408492202203356394293530327112e-8L,
-0.136704883966171134992724380284402402e-8L,
0.942835615901467819547711211663208075e-12L,
0.128722524000893180595479368872770442e-9L,
-0.556459561343633211465414765894951439e-10L,
0.119759355463669810035898150310311343e-10L,
-0.416897822518386350403836626692480096e-14L,
-0.109406404278845944099299008640802908e-11L,
0.4662239946390135746326204922464679e-12L,
-0.990510576390690597844122258212382301e-13L,
0.189318767683735145056885183170630169e-16L,
0.885922187259112726176031067028740667e-14L,
-0.373782039804640545306560251777191937e-14L,
0.786883363903515525774088394065960751e-15L,
};
workspace[2] = tools::evaluate_polynomial(C2, z);
static const T C3[] = {
0.000649434156378600823045267489711934156L,
0.000229472093621399176954732510288065844L,
-0.000469189494395255712128140111679206329L,
0.000267720632062838852962309752433209223L,
-0.756180167188397641072538191879755666e-4L,
-0.239650511386729665193314027333231723e-6L,
0.110826541153473023614770299726861227e-4L,
-0.567495282699159656749963105701560205e-5L,
0.14230900732435883914551894470580433e-5L,
-0.278610802915281422405802158211174452e-10L,
-0.16958404091930277289864168795820267e-6L,
0.809946490538808236335278504852724081e-7L,
-0.191111684859736540606728140872727635e-7L,
0.239286204398081179686413514022282056e-11L,
0.206201318154887984369925818486654549e-8L,
-0.946049666185513217375417988510192814e-9L,
0.215410497757749078380130268468744512e-9L,
-0.138882333681390304603424682490735291e-13L,
-0.218947616819639394064123400466489455e-10L,
0.979099895117168512568262802255883368e-11L,
-0.217821918801809621153859472011393244e-11L,
0.62088195734079014258166361684972205e-16L,
0.212697836327973697696702537114614471e-12L,
-0.934468879151743333127396765626749473e-13L,
0.204536712267828493249215913063207436e-13L,
};
workspace[3] = tools::evaluate_polynomial(C3, z);
static const T C4[] = {
-0.000861888290916711698604702719929057378L,
0.00078403922172006662747403488144228885L,
-0.000299072480303190179733389609932819809L,
-0.146384525788434181781232535690697556e-5L,
0.664149821546512218665853782451862013e-4L,
-0.396836504717943466443123507595386882e-4L,
0.113757269706784190980552042885831759e-4L,
0.250749722623753280165221942390057007e-9L,
-0.169541495365583060147164356781525752e-5L,
0.890750753220530968882898422505515924e-6L,
-0.229293483400080487057216364891158518e-6L,
0.295679413754404904696572852500004588e-10L,
0.288658297427087836297341274604184504e-7L,
-0.141897394378032193894774303903982717e-7L,
0.344635804994648970659527720474194356e-8L,
-0.230245171745280671320192735850147087e-12L,
-0.394092330280464052750697640085291799e-9L,
0.186023389685045019134258533045185639e-9L,
-0.435632300505661804380678327446262424e-10L,
0.127860010162962312660550463349930726e-14L,
0.467927502665791946200382739991760062e-11L,
-0.214924647061348285410535341910721086e-11L,
0.490881561480965216323649688463984082e-12L,
};
workspace[4] = tools::evaluate_polynomial(C4, z);
static const T C5[] = {
-0.000336798553366358150308767592718210002L,
-0.697281375836585777429398828575783308e-4L,
0.00027727532449593920787336425196507501L,
-0.000199325705161888477003360405280844238L,
0.679778047793720783881640176604435742e-4L,
0.141906292064396701483392727105575757e-6L,
-0.135940481897686932784583938837504469e-4L,
0.80184702563342015397192571980419684e-5L,
-0.229148117650809517038048790128781806e-5L,
-0.325247355129845395166230137750005047e-9L,
0.346528464910852649559195496827579815e-6L,
-0.184471871911713432765322367374920978e-6L,
0.482409670378941807563762631738989002e-7L,
-0.179894667217435153025754291716644314e-13L,
-0.630619450001352343517516981425944698e-8L,
0.316241762877456793773762181540969623e-8L,
-0.784092425369742929000839303523267545e-9L,
};
workspace[5] = tools::evaluate_polynomial(C5, z);
static const T C6[] = {
0.00053130793646399222316574854297762391L,
-0.000592166437353693882864836225604401187L,
0.000270878209671804482771279183488328692L,
0.790235323266032787212032944390816666e-6L,
-0.815396936756196875092890088464682624e-4L,
0.561168275310624965003775619041471695e-4L,
-0.183291165828433755673259749374098313e-4L,
-0.307961345060330478256414192546677006e-8L,
0.346515536880360908673728529745376913e-5L,
-0.202913273960586037269527254582695285e-5L,
0.578879286314900370889997586203187687e-6L,
0.233863067382665698933480579231637609e-12L,
-0.88286007463304835250508524317926246e-7L,
0.474359588804081278032150770595852426e-7L,
-0.125454150207103824457130611214783073e-7L,
};
workspace[6] = tools::evaluate_polynomial(C6, z);
static const T C7[] = {
0.000344367606892377671254279625108523655L,
0.517179090826059219337057843002058823e-4L,
-0.000334931610811422363116635090580012327L,
0.000281269515476323702273722110707777978L,
-0.000109765822446847310235396824500789005L,
-0.127410090954844853794579954588107623e-6L,
0.277444515115636441570715073933712622e-4L,
-0.182634888057113326614324442681892723e-4L,
0.578769494973505239894178121070843383e-5L,
0.493875893393627039981813418398565502e-9L,
-0.105953670140260427338098566209633945e-5L,
0.616671437611040747858836254004890765e-6L,
-0.175629733590604619378669693914265388e-6L,
};
workspace[7] = tools::evaluate_polynomial(C7, z);
static const T C8[] = {
-0.000652623918595309418922034919726622692L,
0.000839498720672087279993357516764983445L,
-0.000438297098541721005061087953050560377L,
-0.696909145842055197136911097362072702e-6L,
0.00016644846642067547837384572662326101L,
-0.000127835176797692185853344001461664247L,
0.462995326369130429061361032704489636e-4L,
0.455790986792270771162749294232219616e-8L,
-0.105952711258051954718238500312872328e-4L,
0.678334290486516662273073740749269432e-5L,
-0.210754766662588042469972680229376445e-5L,
};
workspace[8] = tools::evaluate_polynomial(C8, z);
static const T C9[] = {
-0.000596761290192746250124390067179459605L,
-0.720489541602001055908571930225015052e-4L,
0.000678230883766732836161951166000673426L,
-0.000640147526026275845100045652582354779L,
0.000277501076343287044992374518205845463L,
0.181970083804651510461686554030325202e-6L,
-0.847950711706850318239732559632810086e-4L,
0.610519208250153101764709122740859458e-4L,
-0.210739201834048624082975255893773306e-4L,
};
workspace[9] = tools::evaluate_polynomial(C9, z);
static const T C10[] = {
0.00133244544948006563712694993432717968L,
-0.00191443849856547752650089885832852254L,
0.0011089369134596637339607446329267522L,
0.993240412264229896742295262075817566e-6L,
-0.000508745012930931989848393025305956774L,
0.00042735056665392884328432271160040444L,
-0.000168588537679107988033552814662382059L,
};
workspace[10] = tools::evaluate_polynomial(C10, z);
static const T C11[] = {
0.00157972766073083495908785631307733022L,
0.000162516262783915816898635123980270998L,
-0.00206334210355432762645284467690276817L,
0.00213896861856890981541061922797693947L,
-0.00101085593912630031708085801712479376L,
};
workspace[11] = tools::evaluate_polynomial(C11, z);
static const T C12[] = {
-0.00407251211951401664727281097914544601L,
0.00640336283380806979482363809026579583L,
-0.00404101610816766177473974858518094879L,
};
workspace[12] = tools::evaluate_polynomial(C12, z);
workspace[13] = -0.0059475779383993002845382844736066323L;
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;
}
} // namespace detail
} // namespace math
} // namespace math
#endif // BOOST_MATH_DETAIL_IGAMMA_LARGE

View File

@@ -0,0 +1,201 @@
// (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)
#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)
};
register __m128d vx = _mm_load1_pd(&x);
register __m128d sum_even = _mm_load_pd(coeff);
register __m128d sum_odd = _mm_load_pd(coeff+2);
register __m128d nc_odd, nc_even;
register __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)
};
register __m128d vx = _mm_load1_pd(&x);
register __m128d sum_even = _mm_load_pd(coeff);
register __m128d sum_odd = _mm_load_pd(coeff+2);
register __m128d nc_odd, nc_even;
register __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];
}
} // namespace lanczos
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS

View File

@@ -0,0 +1,512 @@
// (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
namespace boost{ namespace math{ namespace detail{
//
// lgamma for small arguments:
//
template <class T, class Policy, class L>
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<64>&, const Policy& /* l */, const L&)
{
// 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.
// L 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>(-0.180355685678449379109e-1L),
static_cast<T>(0.25126649619989678683e-1L),
static_cast<T>(0.494103151567532234274e-1L),
static_cast<T>(0.172491608709613993966e-1L),
static_cast<T>(-0.259453563205438108893e-3L),
static_cast<T>(-0.541009869215204396339e-3L),
static_cast<T>(-0.324588649825948492091e-4L)
};
static const T Q[] = {
static_cast<T>(0.1e1),
static_cast<T>(0.196202987197795200688e1L),
static_cast<T>(0.148019669424231326694e1L),
static_cast<T>(0.541391432071720958364e0L),
static_cast<T>(0.988504251128010129477e-1L),
static_cast<T>(0.82130967464889339326e-2L),
static_cast<T>(0.224936291922115757597e-3L),
static_cast<T>(-0.223352763208617092964e-6L)
};
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>(0.490622454069039543534e-1L),
static_cast<T>(-0.969117530159521214579e-1L),
static_cast<T>(-0.414983358359495381969e0L),
static_cast<T>(-0.406567124211938417342e0L),
static_cast<T>(-0.158413586390692192217e0L),
static_cast<T>(-0.240149820648571559892e-1L),
static_cast<T>(-0.100346687696279557415e-2L)
};
static const T Q[] = {
static_cast<T>(0.1e1L),
static_cast<T>(0.302349829846463038743e1L),
static_cast<T>(0.348739585360723852576e1L),
static_cast<T>(0.191415588274426679201e1L),
static_cast<T>(0.507137738614363510846e0L),
static_cast<T>(0.577039722690451849648e-1L),
static_cast<T>(0.195768102601107189171e-2L)
};
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>(-0.292329721830270012337e-1L),
static_cast<T>(0.144216267757192309184e0L),
static_cast<T>(-0.142440390738631274135e0L),
static_cast<T>(0.542809694055053558157e-1L),
static_cast<T>(-0.850535976868336437746e-2L),
static_cast<T>(0.431171342679297331241e-3L)
};
static const T Q[] = {
static_cast<T>(0.1e1),
static_cast<T>(-0.150169356054485044494e1L),
static_cast<T>(0.846973248876495016101e0L),
static_cast<T>(-0.220095151814995745555e0L),
static_cast<T>(0.25582797155975869989e-1L),
static_cast<T>(-0.100666795539143372762e-2L),
static_cast<T>(-0.827193521891290553639e-6L)
};
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 L>
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<113>&, const Policy& /* l */, const L&)
{
//
// 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[] = {
-0.018035568567844937910504030027467476655L,
0.013841458273109517271750705401202404195L,
0.062031842739486600078866923383017722399L,
0.052518418329052161202007865149435256093L,
0.01881718142472784129191838493267755758L,
0.0025104830367021839316463675028524702846L,
-0.00021043176101831873281848891452678568311L,
-0.00010249622350908722793327719494037981166L,
-0.11381479670982006841716879074288176994e-4L,
-0.49999811718089980992888533630523892389e-6L,
-0.70529798686542184668416911331718963364e-8L
};
static const T Q[] = {
1L,
2.5877485070422317542808137697939233685L,
2.8797959228352591788629602533153837126L,
1.8030885955284082026405495275461180977L,
0.69774331297747390169238306148355428436L,
0.17261566063277623942044077039756583802L,
0.02729301254544230229429621192443000121L,
0.0026776425891195270663133581960016620433L,
0.00015244249160486584591370355730402168106L,
0.43997034032479866020546814475414346627e-5L,
0.46295080708455613044541885534408170934e-7L,
-0.93326638207459533682980757982834180952e-11L,
0.42316456553164995177177407325292867513e-13L
};
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[] = {
0.036454670944013329356512090082402429697L,
-0.066235835556476033710068679907798799959L,
-0.67492399795577182387312206593595565371L,
-1.4345555263962411429855341651960000166L,
-1.4894319559821365820516771951249649563L,
-0.87210277668067964629483299712322411566L,
-0.29602090537771744401524080430529369136L,
-0.0561832587517836908929331992218879676L,
-0.0053236785487328044334381502530383140443L,
-0.00018629360291358130461736386077971890789L,
-0.10164985672213178500790406939467614498e-6L,
0.13680157145361387405588201461036338274e-8L
};
static const T Q[] = {
1,
4.9106336261005990534095838574132225599L,
10.258804800866438510889341082793078432L,
11.88588976846826108836629960537466889L,
8.3455000546999704314454891036700998428L,
3.6428823682421746343233362007194282703L,
0.97465989807254572142266753052776132252L,
0.15121052897097822172763084966793352524L,
0.012017363555383555123769849654484594893L,
0.0003583032812720649835431669893011257277L
};
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[] = {
-0.017977422421608624353488126610933005432L,
0.18484528905298309555089509029244135703L,
-0.40401251514859546989565001431430884082L,
0.40277179799147356461954182877921388182L,
-0.21993421441282936476709677700477598816L,
0.069595742223850248095697771331107571011L,
-0.012681481427699686635516772923547347328L,
0.0012489322866834830413292771335113136034L,
-0.57058739515423112045108068834668269608e-4L,
0.8207548771933585614380644961342925976e-6L
};
static const T Q[] = {
1,
-2.9629552288944259229543137757200262073L,
3.7118380799042118987185957298964772755L,
-2.5569815272165399297600586376727357187L,
1.0546764918220835097855665680632153367L,
-0.26574021300894401276478730940980810831L,
0.03996289731752081380552901986471233462L,
-0.0033398680924544836817826046380586480873L,
0.00013288854760548251757651556792598235735L,
-0.17194794958274081373243161848194745111e-5L
};
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[] = {
-0.021027558364667626231512090082402429494L,
0.15128811104498736604523586803722368377L,
-0.26249631480066246699388544451126410278L,
0.21148748610533489823742352180628489742L,
-0.093964130697489071999873506148104370633L,
0.024292059227009051652542804957550866827L,
-0.0036284453226534839926304745756906117066L,
0.0002939230129315195346843036254392485984L,
-0.11088589183158123733132268042570710338e-4L,
0.13240510580220763969511741896361984162e-6L
};
static const T Q[] = {
1,
-2.4240003754444040525462170802796471996L,
2.4868383476933178722203278602342786002L,
-1.4047068395206343375520721509193698547L,
0.47583809087867443858344765659065773369L,
-0.09865724264554556400463655444270700132L,
0.012238223514176587501074150988445109735L,
-0.00084625068418239194670614419707491797097L,
0.2796574430456237061420839429225710602e-4L,
-0.30202973883316730694433702165188835331e-6L
};
// (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 L>
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<0>&, const Policy& pol, const L&)
{
//
// 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, L()));
}
else if(z >= 3)
{
// taking the log of tgamma reduces the error, no danger of overflow here:
result = log(gamma_imp(z, pol, L()));
}
else if(z >= 1.5)
{
// special case near 2:
T dz = zm2;
result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e<T>());
result += boost::math::log1p(dz / (L::g() + T(1.5)), pol) * T(1.5);
result += boost::math::log1p(L::lanczos_sum_near_2(dz), pol);
}
else
{
// special case near 1:
T dz = zm1;
result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e<T>());
result += boost::math::log1p(dz / (L::g() + T(0.5)), pol) / 2;
result += boost::math::log1p(L::lanczos_sum_near_1(dz), pol);
}
return result;
}
}}} // namespaces
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL

View File

@@ -0,0 +1,80 @@
// 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>
#ifdef _MSC_VER
#pragma once
#endif
namespace boost
{
namespace math
{
template <class T, class Policy>
T trunc(const T& v, const Policy& pol);
template <class T>
T 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>
T round(const T& v, const Policy& pol);
template <class T>
T 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
}
}
#endif // BOOST_MATH_SPECIAL_ROUND_FWD_HPP

View File

@@ -0,0 +1,544 @@
// 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 = ((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] = 0.16666666666666666667 + 0.16666666666666666667 * in;
c[3] = (0.0083333333333333333333 * in
+ 0.066666666666666666667) * in
+ 0.058333333333333333333;
c[4] = ((0.00019841269841269841270 * in
+ 0.0017857142857142857143) * in
+ 0.026785714285714285714) * in
+ 0.025198412698412698413;
c[5] = (((2.7557319223985890653e-6 * in
+ 0.00037477954144620811287) * in
- 0.0011078042328042328042) * in
+ 0.010559964726631393298) * in
+ 0.012039792768959435626;
c[6] = ((((2.5052108385441718775e-8 * in
- 0.000062705427288760622094) * in
+ 0.00059458674042007375341) * in
- 0.0016095979637646304313) * in
+ 0.0061039211560044893378) * in
+ 0.0038370059724226390893;
c[7] = (((((1.6059043836821614599e-10 * in
+ 0.000015401265401265401265) * in
- 0.00016376804137220803887) * in
+ 0.00069084207973096861986) * in
- 0.0012579159844784844785) * in
+ 0.0010898206731540064873) * in
+ 0.0032177478835464946576;
c[8] = ((((((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] = (((((((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] = ((((((((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 = 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 < 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), pol));
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 > q) ? T(0.5f - q) / T(2) : T(p / 2);
T v = 1 - u; // u < 0.5 so no cancellation error
T df = a * 2;
T t = boost::math::detail::inverse_students_t(df, u, v, pol);
T x = df / (df + t * t);
*py = t * t / (df + t * t);
return x;
}
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

View File

@@ -0,0 +1,415 @@
// 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
#include <boost/array.hpp>
#ifdef BOOST_MSVC
#pragma warning(push) // Temporary until lexical cast fixed.
#pragma warning(disable: 4127 4701)
#endif
#include <boost/lexical_cast.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
namespace boost { namespace math
{
// Forward declarations:
template <class T>
struct max_factorial;
// Definitions:
template <>
inline float unchecked_factorial<float>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(float))
{
static const boost::array<float, 35> factorials = {{
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 long double unchecked_factorial<long double>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(long double))
{
static const boost::array<long double, 171> factorials = {{
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);
};
template <>
inline 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);
};
template <class T>
inline T unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(T))
{
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.
static const boost::array<T, 101> factorials = {{
boost::lexical_cast<T>("1"),
boost::lexical_cast<T>("1"),
boost::lexical_cast<T>("2"),
boost::lexical_cast<T>("6"),
boost::lexical_cast<T>("24"),
boost::lexical_cast<T>("120"),
boost::lexical_cast<T>("720"),
boost::lexical_cast<T>("5040"),
boost::lexical_cast<T>("40320"),
boost::lexical_cast<T>("362880"),
boost::lexical_cast<T>("3628800"),
boost::lexical_cast<T>("39916800"),
boost::lexical_cast<T>("479001600"),
boost::lexical_cast<T>("6227020800"),
boost::lexical_cast<T>("87178291200"),
boost::lexical_cast<T>("1307674368000"),
boost::lexical_cast<T>("20922789888000"),
boost::lexical_cast<T>("355687428096000"),
boost::lexical_cast<T>("6402373705728000"),
boost::lexical_cast<T>("121645100408832000"),
boost::lexical_cast<T>("2432902008176640000"),
boost::lexical_cast<T>("51090942171709440000"),
boost::lexical_cast<T>("1124000727777607680000"),
boost::lexical_cast<T>("25852016738884976640000"),
boost::lexical_cast<T>("620448401733239439360000"),
boost::lexical_cast<T>("15511210043330985984000000"),
boost::lexical_cast<T>("403291461126605635584000000"),
boost::lexical_cast<T>("10888869450418352160768000000"),
boost::lexical_cast<T>("304888344611713860501504000000"),
boost::lexical_cast<T>("8841761993739701954543616000000"),
boost::lexical_cast<T>("265252859812191058636308480000000"),
boost::lexical_cast<T>("8222838654177922817725562880000000"),
boost::lexical_cast<T>("263130836933693530167218012160000000"),
boost::lexical_cast<T>("8683317618811886495518194401280000000"),
boost::lexical_cast<T>("295232799039604140847618609643520000000"),
boost::lexical_cast<T>("10333147966386144929666651337523200000000"),
boost::lexical_cast<T>("371993326789901217467999448150835200000000"),
boost::lexical_cast<T>("13763753091226345046315979581580902400000000"),
boost::lexical_cast<T>("523022617466601111760007224100074291200000000"),
boost::lexical_cast<T>("20397882081197443358640281739902897356800000000"),
boost::lexical_cast<T>("815915283247897734345611269596115894272000000000"),
boost::lexical_cast<T>("33452526613163807108170062053440751665152000000000"),
boost::lexical_cast<T>("1405006117752879898543142606244511569936384000000000"),
boost::lexical_cast<T>("60415263063373835637355132068513997507264512000000000"),
boost::lexical_cast<T>("2658271574788448768043625811014615890319638528000000000"),
boost::lexical_cast<T>("119622220865480194561963161495657715064383733760000000000"),
boost::lexical_cast<T>("5502622159812088949850305428800254892961651752960000000000"),
boost::lexical_cast<T>("258623241511168180642964355153611979969197632389120000000000"),
boost::lexical_cast<T>("12413915592536072670862289047373375038521486354677760000000000"),
boost::lexical_cast<T>("608281864034267560872252163321295376887552831379210240000000000"),
boost::lexical_cast<T>("30414093201713378043612608166064768844377641568960512000000000000"),
boost::lexical_cast<T>("1551118753287382280224243016469303211063259720016986112000000000000"),
boost::lexical_cast<T>("80658175170943878571660636856403766975289505440883277824000000000000"),
boost::lexical_cast<T>("4274883284060025564298013753389399649690343788366813724672000000000000"),
boost::lexical_cast<T>("230843697339241380472092742683027581083278564571807941132288000000000000"),
boost::lexical_cast<T>("12696403353658275925965100847566516959580321051449436762275840000000000000"),
boost::lexical_cast<T>("710998587804863451854045647463724949736497978881168458687447040000000000000"),
boost::lexical_cast<T>("40526919504877216755680601905432322134980384796226602145184481280000000000000"),
boost::lexical_cast<T>("2350561331282878571829474910515074683828862318181142924420699914240000000000000"),
boost::lexical_cast<T>("138683118545689835737939019720389406345902876772687432540821294940160000000000000"),
boost::lexical_cast<T>("8320987112741390144276341183223364380754172606361245952449277696409600000000000000"),
boost::lexical_cast<T>("507580213877224798800856812176625227226004528988036003099405939480985600000000000000"),
boost::lexical_cast<T>("31469973260387937525653122354950764088012280797258232192163168247821107200000000000000"),
boost::lexical_cast<T>("1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000"),
boost::lexical_cast<T>("126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000"),
boost::lexical_cast<T>("8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000"),
boost::lexical_cast<T>("544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000"),
boost::lexical_cast<T>("36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000"),
boost::lexical_cast<T>("2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000"),
boost::lexical_cast<T>("171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000"),
boost::lexical_cast<T>("11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000"),
boost::lexical_cast<T>("850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000"),
boost::lexical_cast<T>("61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000"),
boost::lexical_cast<T>("4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000"),
boost::lexical_cast<T>("330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000"),
boost::lexical_cast<T>("24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000"),
boost::lexical_cast<T>("1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000"),
boost::lexical_cast<T>("145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000"),
boost::lexical_cast<T>("11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000"),
boost::lexical_cast<T>("894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000"),
boost::lexical_cast<T>("71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000"),
boost::lexical_cast<T>("5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000"),
boost::lexical_cast<T>("475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000"),
boost::lexical_cast<T>("39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000"),
boost::lexical_cast<T>("3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000"),
boost::lexical_cast<T>("281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000"),
boost::lexical_cast<T>("24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000"),
boost::lexical_cast<T>("2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000"),
boost::lexical_cast<T>("185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000"),
boost::lexical_cast<T>("16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000"),
boost::lexical_cast<T>("1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000"),
boost::lexical_cast<T>("135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000"),
boost::lexical_cast<T>("12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000"),
boost::lexical_cast<T>("1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000"),
boost::lexical_cast<T>("108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000"),
boost::lexical_cast<T>("10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000"),
boost::lexical_cast<T>("991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000"),
boost::lexical_cast<T>("96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000"),
boost::lexical_cast<T>("9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000"),
boost::lexical_cast<T>("933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000"),
boost::lexical_cast<T>("93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"),
}};
return factorials[i];
}
template <class T>
struct max_factorial
{
BOOST_STATIC_CONSTANT(unsigned, value = 100);
};
#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

View File

@@ -0,0 +1,450 @@
// (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_DIGAMMA_HPP
#define BOOST_MATH_SF_DIGAMMA_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/mpl/comparison.hpp>
namespace boost{
namespace math{
namespace detail{
//
// Begin by defining the smallest value for which it is safe to
// use the asymptotic expansion for digamma:
//
inline unsigned digamma_large_lim(const mpl::int_<0>*)
{ return 20; }
inline unsigned digamma_large_lim(const void*)
{ return 10; }
//
// Implementations of the asymptotic expansion come next,
// the coefficients of the series have been evaluated
// in advance at high precision, and the series truncated
// at the first term that's too small to effect the result.
// Note that the series becomes divergent after a while
// so truncation is very important.
//
// This first one gives 34-digit precision for x >= 20:
//
template <class T>
inline T digamma_imp_large(T x, const mpl::int_<0>*)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const T P[] = {
0.083333333333333333333333333333333333333333333333333L,
-0.0083333333333333333333333333333333333333333333333333L,
0.003968253968253968253968253968253968253968253968254L,
-0.0041666666666666666666666666666666666666666666666667L,
0.0075757575757575757575757575757575757575757575757576L,
-0.021092796092796092796092796092796092796092796092796L,
0.083333333333333333333333333333333333333333333333333L,
-0.44325980392156862745098039215686274509803921568627L,
3.0539543302701197438039543302701197438039543302701L,
-26.456212121212121212121212121212121212121212121212L,
281.4601449275362318840579710144927536231884057971L,
-3607.510546398046398046398046398046398046398046398L,
54827.583333333333333333333333333333333333333333333L,
-974936.82385057471264367816091954022988505747126437L,
20052695.796688078946143462272494530559046688078946L,
-472384867.72162990196078431372549019607843137254902L,
12635724795.916666666666666666666666666666666666667L
};
x -= 1;
T result = log(x);
result += 1 / (2 * x);
T z = 1 / (x*x);
result -= z * tools::evaluate_polynomial(P, z);
return result;
}
//
// 19-digit precision for x >= 10:
//
template <class T>
inline T digamma_imp_large(T x, const mpl::int_<64>*)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const T P[] = {
0.083333333333333333333333333333333333333333333333333L,
-0.0083333333333333333333333333333333333333333333333333L,
0.003968253968253968253968253968253968253968253968254L,
-0.0041666666666666666666666666666666666666666666666667L,
0.0075757575757575757575757575757575757575757575757576L,
-0.021092796092796092796092796092796092796092796092796L,
0.083333333333333333333333333333333333333333333333333L,
-0.44325980392156862745098039215686274509803921568627L,
3.0539543302701197438039543302701197438039543302701L,
-26.456212121212121212121212121212121212121212121212L,
281.4601449275362318840579710144927536231884057971L,
};
x -= 1;
T result = log(x);
result += 1 / (2 * x);
T z = 1 / (x*x);
result -= z * tools::evaluate_polynomial(P, z);
return result;
}
//
// 17-digit precision for x >= 10:
//
template <class T>
inline T digamma_imp_large(T x, const mpl::int_<53>*)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const T P[] = {
0.083333333333333333333333333333333333333333333333333L,
-0.0083333333333333333333333333333333333333333333333333L,
0.003968253968253968253968253968253968253968253968254L,
-0.0041666666666666666666666666666666666666666666666667L,
0.0075757575757575757575757575757575757575757575757576L,
-0.021092796092796092796092796092796092796092796092796L,
0.083333333333333333333333333333333333333333333333333L,
-0.44325980392156862745098039215686274509803921568627L
};
x -= 1;
T result = log(x);
result += 1 / (2 * x);
T z = 1 / (x*x);
result -= z * tools::evaluate_polynomial(P, z);
return result;
}
//
// 9-digit precision for x >= 10:
//
template <class T>
inline T digamma_imp_large(T x, const mpl::int_<24>*)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const T P[] = {
0.083333333333333333333333333333333333333333333333333L,
-0.0083333333333333333333333333333333333333333333333333L,
0.003968253968253968253968253968253968253968253968254L
};
x -= 1;
T result = log(x);
result += 1 / (2 * x);
T z = 1 / (x*x);
result -= z * tools::evaluate_polynomial(P, z);
return result;
}
//
// Now follow rational approximations over the range [1,2].
//
// 35-digit precision:
//
template <class T>
T digamma_imp_1_2(T x, const mpl::int_<0>*)
{
//
// Now the approximation, we use the form:
//
// digamma(x) = (x - root) * (Y + R(x-1))
//
// Where root is the location of the positive root of digamma,
// Y is a constant, and R is optimised for low absolute error
// compared to Y.
//
// Max error found at 128-bit long double precision: 5.541e-35
// Maximum Deviation Found (approximation error): 1.965e-35
//
static const float Y = 0.99558162689208984375F;
static const T root1 = 1569415565.0 / 1073741824uL;
static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
static const T root3 = ((111616537.0 / 1073741824uL) / 1073741824uL) / 1073741824uL;
static const T root4 = (((503992070.0 / 1073741824uL) / 1073741824uL) / 1073741824uL) / 1073741824uL;
static const T root5 = 0.52112228569249997894452490385577338504019838794544e-36L;
static const T P[] = {
0.25479851061131551526977464225335883769L,
-0.18684290534374944114622235683619897417L,
-0.80360876047931768958995775910991929922L,
-0.67227342794829064330498117008564270136L,
-0.26569010991230617151285010695543858005L,
-0.05775672694575986971640757748003553385L,
-0.0071432147823164975485922555833274240665L,
-0.00048740753910766168912364555706064993274L,
-0.16454996865214115723416538844975174761e-4L,
-0.20327832297631728077731148515093164955e-6L
};
static const T Q[] = {
1,
2.6210924610812025425088411043163287646L,
2.6850757078559596612621337395886392594L,
1.4320913706209965531250495490639289418L,
0.4410872083455009362557012239501953402L,
0.081385727399251729505165509278152487225L,
0.0089478633066857163432104815183858149496L,
0.00055861622855066424871506755481997374154L,
0.1760168552357342401304462967950178554e-4L,
0.20585454493572473724556649516040874384e-6L,
-0.90745971844439990284514121823069162795e-11L,
0.48857673606545846774761343500033283272e-13L,
};
T g = x - root1;
g -= root2;
g -= root3;
g -= root4;
g -= root5;
T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(x-1));
T result = g * Y + g * r;
return result;
}
//
// 19-digit precision:
//
template <class T>
T digamma_imp_1_2(T x, const mpl::int_<64>*)
{
//
// Now the approximation, we use the form:
//
// digamma(x) = (x - root) * (Y + R(x-1))
//
// Where root is the location of the positive root of digamma,
// Y is a constant, and R is optimised for low absolute error
// compared to Y.
//
// Max error found at 80-bit long double precision: 5.016e-20
// Maximum Deviation Found (approximation error): 3.575e-20
//
static const float Y = 0.99558162689208984375F;
static const T root1 = 1569415565.0 / 1073741824uL;
static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
static const T root3 = 0.9016312093258695918615325266959189453125e-19L;
static const T P[] = {
0.254798510611315515235L,
-0.314628554532916496608L,
-0.665836341559876230295L,
-0.314767657147375752913L,
-0.0541156266153505273939L,
-0.00289268368333918761452L
};
static const T Q[] = {
1,
2.1195759927055347547L,
1.54350554664961128724L,
0.486986018231042975162L,
0.0660481487173569812846L,
0.00298999662592323990972L,
-0.165079794012604905639e-5L,
0.317940243105952177571e-7L
};
T g = x - root1;
g -= root2;
g -= root3;
T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
T result = g * Y + g * r;
return result;
}
//
// 18-digit precision:
//
template <class T>
T digamma_imp_1_2(T x, const mpl::int_<53>*)
{
//
// Now the approximation, we use the form:
//
// digamma(x) = (x - root) * (Y + R(x-1))
//
// Where root is the location of the positive root of digamma,
// Y is a constant, and R is optimised for low absolute error
// compared to Y.
//
// Maximum Deviation Found: 1.466e-18
// At double precision, max error found: 2.452e-17
//
static const float Y = 0.99558162689208984F;
static const T root1 = 1569415565.0 / 1073741824uL;
static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
static const T root3 = 0.9016312093258695918615325266959189453125e-19L;
static const T P[] = {
0.25479851061131551L,
-0.32555031186804491L,
-0.65031853770896507L,
-0.28919126444774784L,
-0.045251321448739056L,
-0.0020713321167745952L
};
static const T Q[] = {
1L,
2.0767117023730469L,
1.4606242909763515L,
0.43593529692665969L,
0.054151797245674225L,
0.0021284987017821144L,
-0.55789841321675513e-6L
};
T g = x - root1;
g -= root2;
g -= root3;
T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
T result = g * Y + g * r;
return result;
}
//
// 9-digit precision:
//
template <class T>
inline T digamma_imp_1_2(T x, const mpl::int_<24>*)
{
//
// Now the approximation, we use the form:
//
// digamma(x) = (x - root) * (Y + R(x-1))
//
// Where root is the location of the positive root of digamma,
// Y is a constant, and R is optimised for low absolute error
// compared to Y.
//
// Maximum Deviation Found: 3.388e-010
// At float precision, max error found: 2.008725e-008
//
static const float Y = 0.99558162689208984f;
static const T root = 1532632.0f / 1048576;
static const T root_minor = static_cast<T>(0.3700660185912626595423257213284682051735604e-6L);
static const T P[] = {
0.25479851023250261e0,
-0.44981331915268368e0,
-0.43916936919946835e0,
-0.61041765350579073e-1
};
static const T Q[] = {
0.1e1,
0.15890202430554952e1,
0.65341249856146947e0,
0.63851690523355715e-1
};
T g = x - root;
g -= root_minor;
T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
T result = g * Y + g * r;
return result;
}
template <class T, class Tag, class Policy>
T digamma_imp(T x, const Tag* t, const Policy& pol)
{
//
// This handles reflection of negative arguments, and all our
// error handling, then forwards to the T-specific approximation.
//
BOOST_MATH_STD_USING // ADL of std functions.
T result = 0;
//
// Check for negative arguments and use reflection:
//
if(x < 0)
{
// Reflect:
x = 1 - x;
// Argument reduction for tan:
T remainder = x - floor(x);
// Shift to negative if > 0.5:
if(remainder > 0.5)
{
remainder -= 1;
}
//
// check for evaluation at a negative pole:
//
if(remainder == 0)
{
return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", 0, (1-x), pol);
}
result = constants::pi<T>() / tan(constants::pi<T>() * remainder);
}
//
// If we're above the lower-limit for the
// asymptotic expansion then use it:
//
if(x >= digamma_large_lim(t))
{
result += digamma_imp_large(x, t);
}
else
{
//
// If x > 2 reduce to the interval [1,2]:
//
while(x > 2)
{
x -= 1;
result += 1/x;
}
//
// If x < 1 use recurrance to shift to > 1:
//
if(x < 1)
{
result = -1/x;
x += 1;
}
result += digamma_imp_1_2(x, t);
}
return result;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type
digamma(T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::precision<T, 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>,
typename mpl::if_<
mpl::less<precision_type, mpl::int_<25> >,
mpl::int_<24>,
typename mpl::if_<
mpl::less<precision_type, mpl::int_<54> >,
mpl::int_<53>,
mpl::int_<64>
>::type
>::type
>::type tag_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::digamma_imp(
static_cast<value_type>(x),
static_cast<const tag_type*>(0), pol), "boost::math::digamma<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type
digamma(T x)
{
return digamma(x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,187 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2006 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)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to ensure
// that the code continues to work no matter how many digits
// type T has.
#ifndef BOOST_MATH_ELLINT_1_HPP
#define BOOST_MATH_ELLINT_1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integrals (complete and incomplete) of the first kind
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math {
template <class T1, class T2, class Policy>
typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const Policy& pol);
namespace detail{
template <typename T, typename Policy>
T ellint_k_imp(T k, const Policy& pol);
// Elliptic integral (Legendre form) of the first kind
template <typename T, typename Policy>
T ellint_f_imp(T phi, T k, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
static const char* function = "boost::math::ellint_f<%1%>(%1%,%1%)";
BOOST_MATH_INSTRUMENT_VARIABLE(phi);
BOOST_MATH_INSTRUMENT_VARIABLE(k);
BOOST_MATH_INSTRUMENT_VARIABLE(function);
if (abs(k) > 1)
{
return policies::raise_domain_error<T>(function,
"Got k = %1%, function requires |k| <= 1", k, pol);
}
bool invert = false;
if(phi < 0)
{
BOOST_MATH_INSTRUMENT_VARIABLE(phi);
phi = fabs(phi);
invert = true;
}
T result;
if(phi >= tools::max_value<T>())
{
// Need to handle infinity as a special case:
result = policies::raise_overflow_error<T>(function, 0, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else if(phi > 1 / tools::epsilon<T>())
{
// Phi is so large that phi%pi is necessarily zero (or garbage),
// just return the second part of the duplication formula:
result = 2 * phi * ellint_k_imp(k, pol) / constants::pi<T>();
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else
{
// Carlson's algorithm works only for |phi| <= pi/2,
// use the integrand's periodicity to normalize phi
//
// Xiaogang's original code used a cast to long long here
// but that fails if T has more digits than a long long,
// so rewritten to use fmod instead:
//
BOOST_MATH_INSTRUMENT_CODE("pi/2 = " << constants::pi<T>() / 2);
T rphi = boost::math::tools::fmod_workaround(phi, T(constants::pi<T>() / 2));
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
T m = floor((2 * phi) / constants::pi<T>());
BOOST_MATH_INSTRUMENT_VARIABLE(m);
int s = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
s = -1;
rphi = constants::pi<T>() / 2 - rphi;
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
}
T sinp = sin(rphi);
T cosp = cos(rphi);
BOOST_MATH_INSTRUMENT_VARIABLE(sinp);
BOOST_MATH_INSTRUMENT_VARIABLE(cosp);
result = s * sinp * ellint_rf_imp(T(cosp * cosp), T(1 - k * k * sinp * sinp), T(1), pol);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
if(m != 0)
{
result += m * ellint_k_imp(k, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
}
return invert ? T(-result) : result;
}
// Complete elliptic integral (Legendre form) of the first kind
template <typename T, typename Policy>
T ellint_k_imp(T k, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_k<%1%>(%1%)";
if (abs(k) > 1)
{
return policies::raise_domain_error<T>(function,
"Got k = %1%, function requires |k| <= 1", k, pol);
}
if (abs(k) == 1)
{
return policies::raise_overflow_error<T>(function, 0, pol);
}
T x = 0;
T y = 1 - k * k;
T z = 1;
T value = ellint_rf_imp(x, y, z, pol);
return value;
}
template <typename T, typename Policy>
inline typename tools::promote_args<T>::type ellint_1(T k, const Policy& pol, const mpl::true_&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_k_imp(static_cast<value_type>(k), pol), "boost::math::ellint_1<%1%>(%1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const mpl::false_&)
{
return boost::math::ellint_1(k, phi, policies::policy<>());
}
}
// Complete elliptic integral (Legendre form) of the first kind
template <typename T>
inline typename tools::promote_args<T>::type ellint_1(T k)
{
return ellint_1(k, policies::policy<>());
}
// Elliptic integral (Legendre form) of the first kind
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_f_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_1<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi)
{
typedef typename policies::is_policy<T2>::type tag_type;
return detail::ellint_1(k, phi, tag_type());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_1_HPP

View File

@@ -0,0 +1,168 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2006 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)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to ensure
// that the code continues to work no matter how many digits
// type T has.
#ifndef BOOST_MATH_ELLINT_2_HPP
#define BOOST_MATH_ELLINT_2_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/ellint_rd.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integrals (complete and incomplete) of the second kind
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math {
template <class T1, class T2, class Policy>
typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol);
namespace detail{
template <typename T, typename Policy>
T ellint_e_imp(T k, const Policy& pol);
// Elliptic integral (Legendre form) of the second kind
template <typename T, typename Policy>
T ellint_e_imp(T phi, T k, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
bool invert = false;
if(phi < 0)
{
phi = fabs(phi);
invert = true;
}
T result;
if(phi >= tools::max_value<T>())
{
// Need to handle infinity as a special case:
result = policies::raise_overflow_error<T>("boost::math::ellint_e<%1%>(%1%,%1%)", 0, pol);
}
else if(phi > 1 / tools::epsilon<T>())
{
// Phi is so large that phi%pi is necessarily zero (or garbage),
// just return the second part of the duplication formula:
result = 2 * phi * ellint_e_imp(k, pol) / constants::pi<T>();
}
else
{
// Carlson's algorithm works only for |phi| <= pi/2,
// use the integrand's periodicity to normalize phi
//
// Xiaogang's original code used a cast to long long here
// but that fails if T has more digits than a long long,
// so rewritten to use fmod instead:
//
T rphi = boost::math::tools::fmod_workaround(phi, T(constants::pi<T>() / 2));
T m = floor((2 * phi) / constants::pi<T>());
int s = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
s = -1;
rphi = constants::pi<T>() / 2 - rphi;
}
T sinp = sin(rphi);
T cosp = cos(rphi);
T x = cosp * cosp;
T t = k * k * sinp * sinp;
T y = 1 - t;
T z = 1;
result = s * sinp * (ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3);
if(m != 0)
result += m * ellint_e_imp(k, pol);
}
return invert ? T(-result) : result;
}
// Complete elliptic integral (Legendre form) of the second kind
template <typename T, typename Policy>
T ellint_e_imp(T k, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::tools;
if (abs(k) > 1)
{
return policies::raise_domain_error<T>("boost::math::ellint_e<%1%>(%1%)",
"Got k = %1%, function requires |k| <= 1", k, pol);
}
if (abs(k) == 1)
{
return static_cast<T>(1);
}
T x = 0;
T t = k * k;
T y = 1 - t;
T z = 1;
T value = ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3;
return value;
}
template <typename T, typename Policy>
inline typename tools::promote_args<T>::type ellint_2(T k, const Policy& pol, const mpl::true_&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%)");
}
// Elliptic integral (Legendre form) of the second kind
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const mpl::false_&)
{
return boost::math::ellint_2(k, phi, policies::policy<>());
}
} // detail
// Complete elliptic integral (Legendre form) of the second kind
template <typename T>
inline typename tools::promote_args<T>::type ellint_2(T k)
{
return ellint_2(k, policies::policy<>());
}
// Elliptic integral (Legendre form) of the second kind
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi)
{
typedef typename policies::is_policy<T2>::type tag_type;
return detail::ellint_2(k, phi, tag_type());
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%,%1%)");
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_2_HPP

View File

@@ -0,0 +1,318 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2006 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)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to correctly
// handle the various corner cases.
//
#ifndef BOOST_MATH_ELLINT_3_HPP
#define BOOST_MATH_ELLINT_3_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/special_functions/ellint_1.hpp>
#include <boost/math/special_functions/ellint_2.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integrals (complete and incomplete) of the third kind
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math {
namespace detail{
template <typename T, typename Policy>
T ellint_pi_imp(T v, T k, T vc, const Policy& pol);
// Elliptic integral (Legendre form) of the third kind
template <typename T, typename Policy>
T ellint_pi_imp(T v, T phi, T k, T vc, const Policy& pol)
{
// Note vc = 1-v presumably without cancellation error.
T value, x, y, z, p, t;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
static const char* function = "boost::math::ellint_3<%1%>(%1%,%1%,%1%)";
if (abs(k) > 1)
{
return policies::raise_domain_error<T>(function,
"Got k = %1%, function requires |k| <= 1", k, pol);
}
T sphi = sin(fabs(phi));
if(v > 1 / (sphi * sphi))
{
// Complex result is a domain error:
return policies::raise_domain_error<T>(function,
"Got v = %1%, but result is complex for v > 1 / sin^2(phi)", v, pol);
}
// Special cases first:
if(v == 0)
{
// A&S 17.7.18 & 19
return (k == 0) ? phi : ellint_f_imp(phi, k, pol);
}
if(phi == constants::pi<T>() / 2)
{
// Have to filter this case out before the next
// special case, otherwise we might get an infinity from
// tan(phi).
// Also note that since we can't represent PI/2 exactly
// in a T, this is a bit of a guess as to the users true
// intent...
//
return ellint_pi_imp(v, k, vc, pol);
}
if(k == 0)
{
// A&S 17.7.20:
if(v < 1)
{
T vcr = sqrt(vc);
return atan(vcr * tan(phi)) / vcr;
}
else if(v == 1)
{
return tan(phi);
}
else
{
// v > 1:
T vcr = sqrt(-vc);
T arg = vcr * tan(phi);
return (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * vcr);
}
}
if(v < 0)
{
//
// If we don't shift to 0 <= v <= 1 we get
// cancellation errors later on. Use
// A&S 17.7.15/16 to shift to v > 0:
//
T k2 = k * k;
T N = (k2 - v) / (1 - v);
T Nm1 = (1 - k2) / (1 - v);
T p2 = sqrt(-v * (k2 - v) / (1 - v));
T delta = sqrt(1 - k2 * sphi * sphi);
T result = ellint_pi_imp(N, phi, k, Nm1, pol);
result *= sqrt(Nm1 * (1 - k2 / N));
result += ellint_f_imp(phi, k, pol) * k2 / p2;
result += atan((p2/2) * sin(2 * phi) / delta);
result /= sqrt((1 - v) * (1 - k2 / v));
return result;
}
#if 0 // disabled but retained for future reference: see below.
if(v > 1)
{
//
// If v > 1 we can use the identity in A&S 17.7.7/8
// to shift to 0 <= v <= 1. Unfortunately this
// identity appears only to function correctly when
// 0 <= phi <= pi/2, but it's when phi is outside that
// range that we really need it: That's when
// Carlson's formula fails, and what's more the periodicity
// reduction used below on phi doesn't work when v > 1.
//
// So we're stuck... the code is archived here in case
// some bright spart can figure out the fix.
//
T k2 = k * k;
T N = k2 / v;
T Nm1 = (v - k2) / v;
T p1 = sqrt((-vc) * (1 - k2 / v));
T delta = sqrt(1 - k2 * sphi * sphi);
//
// These next two terms have a large amount of cancellation
// so it's not clear if this relation is useable even if
// the issues with phi > pi/2 can be fixed:
//
T result = -ellint_pi_imp(N, phi, k, Nm1);
result += ellint_f_imp(phi, k);
//
// This log term gives the complex result when
// n > 1/sin^2(phi)
// However that case is dealt with as an error above,
// so we should always get a real result here:
//
result += log((delta + p1 * tan(phi)) / (delta - p1 * tan(phi))) / (2 * p1);
return result;
}
#endif
// Carlson's algorithm works only for |phi| <= pi/2,
// use the integrand's periodicity to normalize phi
//
// Xiaogang's original code used a cast to long long here
// but that fails if T has more digits than a long long,
// so rewritten to use fmod instead:
//
if(fabs(phi) > 1 / tools::epsilon<T>())
{
if(v > 1)
return policies::raise_domain_error<T>(
function,
"Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol);
//
// Phi is so large that phi%pi is necessarily zero (or garbage),
// just return the second part of the duplication formula:
//
value = 2 * fabs(phi) * ellint_pi_imp(v, k, vc, pol) / constants::pi<T>();
}
else
{
T rphi = boost::math::tools::fmod_workaround(T(fabs(phi)), T(constants::pi<T>() / 2));
T m = floor((2 * fabs(phi)) / constants::pi<T>());
int sign = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
sign = -1;
rphi = constants::pi<T>() / 2 - rphi;
}
T sinp = sin(rphi);
T cosp = cos(rphi);
x = cosp * cosp;
t = sinp * sinp;
y = 1 - k * k * t;
z = 1;
if(v * t < 0.5)
p = 1 - v * t;
else
p = x + vc * t;
value = sign * sinp * (ellint_rf_imp(x, y, z, pol) + v * t * ellint_rj_imp(x, y, z, p, pol) / 3);
if((m > 0) && (vc > 0))
value += m * ellint_pi_imp(v, k, vc, pol);
}
if (phi < 0)
{
value = -value; // odd function
}
return value;
}
// Complete elliptic integral (Legendre form) of the third kind
template <typename T, typename Policy>
T ellint_pi_imp(T v, T k, T vc, const Policy& pol)
{
// Note arg vc = 1-v, possibly without cancellation errors
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_pi<%1%>(%1%,%1%)";
if (abs(k) >= 1)
{
return policies::raise_domain_error<T>(function,
"Got k = %1%, function requires |k| <= 1", k, pol);
}
if(vc <= 0)
{
// Result is complex:
return policies::raise_domain_error<T>(function,
"Got v = %1%, function requires v < 1", v, pol);
}
if(v == 0)
{
return (k == 0) ? boost::math::constants::pi<T>() / 2 : ellint_k_imp(k, pol);
}
if(v < 0)
{
T k2 = k * k;
T N = (k2 - v) / (1 - v);
T Nm1 = (1 - k2) / (1 - v);
T p2 = sqrt(-v * (k2 - v) / (1 - v));
T result = boost::math::detail::ellint_pi_imp(N, k, Nm1, pol);
result *= sqrt(Nm1 * (1 - k2 / N));
result += ellint_k_imp(k, pol) * k2 / p2;
result /= sqrt((1 - v) * (1 - k2 / v));
return result;
}
T x = 0;
T y = 1 - k * k;
T z = 1;
T p = vc;
T value = ellint_rf_imp(x, y, z, pol) + v * ellint_rj_imp(x, y, z, p, pol) / 3;
return value;
}
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const mpl::false_&)
{
return boost::math::ellint_3(k, v, phi, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v, const Policy& pol, const mpl::true_&)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::ellint_pi_imp(
static_cast<value_type>(v),
static_cast<value_type>(k),
static_cast<value_type>(1-v),
pol), "boost::math::ellint_3<%1%>(%1%,%1%)");
}
} // namespace detail
template <class T1, class T2, class T3, class Policy>
inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::ellint_pi_imp(
static_cast<value_type>(v),
static_cast<value_type>(phi),
static_cast<value_type>(k),
static_cast<value_type>(1-v),
pol), "boost::math::ellint_3<%1%>(%1%,%1%,%1%)");
}
template <class T1, class T2, class T3>
typename detail::ellint_3_result<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi)
{
typedef typename policies::is_policy<T3>::type tag_type;
return detail::ellint_3(k, v, phi, tag_type());
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v)
{
return ellint_3(k, v, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_3_HPP

View File

@@ -0,0 +1,115 @@
// 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)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to correctly
// handle the y < 0 case.
//
#ifndef BOOST_MATH_ELLINT_RC_HPP
#define BOOST_MATH_ELLINT_RC_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
// Carlson's degenerate elliptic integral
// R_C(x, y) = R_F(x, y, y) = 0.5 * \int_{0}^{\infty} (t+x)^{-1/2} (t+y)^{-1} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rc_imp(T x, T y, const Policy& pol)
{
T value, S, u, lambda, tolerance, prefix;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rc<%1%>(%1%,%1%)";
if(x < 0)
{
return policies::raise_domain_error<T>(function,
"Argument x must be non-negative but got %1%", x, pol);
}
if(y == 0)
{
return policies::raise_domain_error<T>(function,
"Argument y must not be zero but got %1%", y, pol);
}
// error scales as the 6th power of tolerance
tolerance = pow(4 * tools::epsilon<T>(), T(1) / 6);
// for y < 0, the integral is singular, return Cauchy principal value
if (y < 0)
{
prefix = sqrt(x / (x - y));
x = x - y;
y = -y;
}
else
prefix = 1;
// duplication:
k = 1;
do
{
u = (x + y + y) / 3;
S = y / u - 1; // 1 - x / u = 2 * S
if (2 * abs(S) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
lambda = 2 * sx * sy + y;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
++k;
}while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations<T>(function, k, pol);
// Taylor series expansion to the 5th order
value = (1 + S * S * (T(3) / 10 + S * (T(1) / 7 + S * (T(3) / 8 + S * T(9) / 22)))) / sqrt(u);
return value * prefix;
}
} // namespace detail
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
ellint_rc(T1 x, T2 y, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::ellint_rc_imp(
static_cast<value_type>(x),
static_cast<value_type>(y), pol), "boost::math::ellint_rc<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
ellint_rc(T1 x, T2 y)
{
return ellint_rc(x, y, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_RC_HPP

View File

@@ -0,0 +1,130 @@
// 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)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it slightly to fit into the
// Boost.Math conceptual framework better.
#ifndef BOOST_MATH_ELLINT_RD_HPP
#define BOOST_MATH_ELLINT_RD_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
// Carlson's elliptic integral of the second kind
// R_D(x, y, z) = R_J(x, y, z, z) = 1.5 * \int_{0}^{\infty} [(t+x)(t+y)]^{-1/2} (t+z)^{-3/2} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rd_imp(T x, T y, T z, const Policy& pol)
{
T value, u, lambda, sigma, factor, tolerance;
T X, Y, Z, EA, EB, EC, ED, EE, S1, S2;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)";
if (x < 0)
{
return policies::raise_domain_error<T>(function,
"Argument x must be >= 0, but got %1%", x, pol);
}
if (y < 0)
{
return policies::raise_domain_error<T>(function,
"Argument y must be >= 0, but got %1%", y, pol);
}
if (z <= 0)
{
return policies::raise_domain_error<T>(function,
"Argument z must be > 0, but got %1%", z, pol);
}
if (x + y == 0)
{
return policies::raise_domain_error<T>(function,
"At most one argument can be zero, but got, x + y = %1%", x+y, pol);
}
// error scales as the 6th power of tolerance
tolerance = pow(tools::epsilon<T>() / 3, T(1)/6);
// duplication
sigma = 0;
factor = 1;
k = 1;
do
{
u = (x + y + z + z + z) / 5;
X = (u - x) / u;
Y = (u - y) / u;
Z = (u - z) / u;
if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
T sz = sqrt(z);
lambda = sy * (sx + sz) + sz * sx; //sqrt(x * y) + sqrt(y * z) + sqrt(z * x);
sigma += factor / (sz * (z + lambda));
factor /= 4;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
++k;
}
while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations<T>(function, k, pol);
// Taylor series expansion to the 5th order
EA = X * Y;
EB = Z * Z;
EC = EA - EB;
ED = EA - 6 * EB;
EE = ED + EC + EC;
S1 = ED * (ED * T(9) / 88 - Z * EE * T(9) / 52 - T(3) / 14);
S2 = Z * (EE / 6 + Z * (-EC * T(9) / 22 + Z * EA * T(3) / 26));
value = 3 * sigma + factor * (1 + S1 + S2) / (u * sqrt(u));
return value;
}
} // namespace detail
template <class T1, class T2, class T3, class Policy>
inline typename tools::promote_args<T1, T2, T3>::type
ellint_rd(T1 x, T2 y, T3 z, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::ellint_rd_imp(
static_cast<value_type>(x),
static_cast<value_type>(y),
static_cast<value_type>(z), pol), "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)");
}
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
ellint_rd(T1 x, T2 y, T3 z)
{
return ellint_rd(x, y, z, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_RD_HPP

View File

@@ -0,0 +1,132 @@
// 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)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to handle
// types longer than 80-bit reals.
//
#ifndef BOOST_MATH_ELLINT_RF_HPP
#define BOOST_MATH_ELLINT_RF_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
// Carlson's elliptic integral of the first kind
// R_F(x, y, z) = 0.5 * \int_{0}^{\infty} [(t+x)(t+y)(t+z)]^{-1/2} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rf_imp(T x, T y, T z, const Policy& pol)
{
T value, X, Y, Z, E2, E3, u, lambda, tolerance;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)";
if (x < 0 || y < 0 || z < 0)
{
return policies::raise_domain_error<T>(function,
"domain error, all arguments must be non-negative, "
"only sensible result is %1%.",
std::numeric_limits<T>::quiet_NaN(), pol);
}
if (x + y == 0 || y + z == 0 || z + x == 0)
{
return policies::raise_domain_error<T>(function,
"domain error, at most one argument can be zero, "
"only sensible result is %1%.",
std::numeric_limits<T>::quiet_NaN(), pol);
}
// Carlson scales error as the 6th power of tolerance,
// but this seems not to work for types larger than
// 80-bit reals, this heuristic seems to work OK:
if(policies::digits<T, Policy>() > 64)
{
tolerance = pow(tools::epsilon<T>(), T(1)/4.25f);
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
}
else
{
tolerance = pow(4*tools::epsilon<T>(), T(1)/6);
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
}
// duplication
k = 1;
do
{
u = (x + y + z) / 3;
X = (u - x) / u;
Y = (u - y) / u;
Z = (u - z) / u;
// Termination condition:
if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
T sz = sqrt(z);
lambda = sy * (sx + sz) + sz * sx;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
++k;
}
while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations<T>(function, k, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(k);
// Taylor series expansion to the 5th order
E2 = X * Y - Z * Z;
E3 = X * Y * Z;
value = (1 + E2*(E2/24 - E3*T(3)/44 - T(0.1)) + E3/14) / sqrt(u);
BOOST_MATH_INSTRUMENT_VARIABLE(value);
return value;
}
} // namespace detail
template <class T1, class T2, class T3, class Policy>
inline typename tools::promote_args<T1, T2, T3>::type
ellint_rf(T1 x, T2 y, T3 z, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::ellint_rf_imp(
static_cast<value_type>(x),
static_cast<value_type>(y),
static_cast<value_type>(z), pol), "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)");
}
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
ellint_rf(T1 x, T2 y, T3 z)
{
return ellint_rf(x, y, z, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_RF_HPP

View File

@@ -0,0 +1,180 @@
// 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)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to correctly
// handle the p < 0 case.
//
#ifndef BOOST_MATH_ELLINT_RJ_HPP
#define BOOST_MATH_ELLINT_RJ_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/ellint_rc.hpp>
#include <boost/math/special_functions/ellint_rf.hpp>
// Carlson's elliptic integral of the third kind
// R_J(x, y, z, p) = 1.5 * \int_{0}^{\infty} (t+p)^{-1} [(t+x)(t+y)(t+z)]^{-1/2} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
{
T value, u, lambda, alpha, beta, sigma, factor, tolerance;
T X, Y, Z, P, EA, EB, EC, E2, E3, S1, S2, S3;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rj<%1%>(%1%,%1%,%1%)";
if (x < 0)
{
return policies::raise_domain_error<T>(function,
"Argument x must be non-negative, but got x = %1%", x, pol);
}
if(y < 0)
{
return policies::raise_domain_error<T>(function,
"Argument y must be non-negative, but got y = %1%", y, pol);
}
if(z < 0)
{
return policies::raise_domain_error<T>(function,
"Argument z must be non-negative, but got z = %1%", z, pol);
}
if(p == 0)
{
return policies::raise_domain_error<T>(function,
"Argument p must not be zero, but got p = %1%", p, pol);
}
if (x + y == 0 || y + z == 0 || z + x == 0)
{
return policies::raise_domain_error<T>(function,
"At most one argument can be zero, "
"only possible result is %1%.", std::numeric_limits<T>::quiet_NaN(), pol);
}
// error scales as the 6th power of tolerance
tolerance = pow(T(1) * tools::epsilon<T>() / 3, T(1) / 6);
// for p < 0, the integral is singular, return Cauchy principal value
if (p < 0)
{
//
// We must ensure that (z - y) * (y - x) is positive.
// Since the integral is symmetrical in x, y and z
// we can just permute the values:
//
if(x > y)
std::swap(x, y);
if(y > z)
std::swap(y, z);
if(x > y)
std::swap(x, y);
T q = -p;
T pmy = (z - y) * (y - x) / (y + q); // p - y
BOOST_ASSERT(pmy >= 0);
T p = pmy + y;
value = boost::math::ellint_rj(x, y, z, p, pol);
value *= pmy;
value -= 3 * boost::math::ellint_rf(x, y, z, pol);
value += 3 * sqrt((x * y * z) / (x * z + p * q)) * boost::math::ellint_rc(x * z + p * q, p * q, pol);
value /= (y + q);
return value;
}
// duplication
sigma = 0;
factor = 1;
k = 1;
do
{
u = (x + y + z + p + p) / 5;
X = (u - x) / u;
Y = (u - y) / u;
Z = (u - z) / u;
P = (u - p) / u;
if ((tools::max)(abs(X), abs(Y), abs(Z), abs(P)) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
T sz = sqrt(z);
lambda = sy * (sx + sz) + sz * sx;
alpha = p * (sx + sy + sz) + sx * sy * sz;
alpha *= alpha;
beta = p * (p + lambda) * (p + lambda);
sigma += factor * boost::math::ellint_rc(alpha, beta, pol);
factor /= 4;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
p = (p + lambda) / 4;
++k;
}
while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations<T>(function, k, pol);
// Taylor series expansion to the 5th order
EA = X * Y + Y * Z + Z * X;
EB = X * Y * Z;
EC = P * P;
E2 = EA - 3 * EC;
E3 = EB + 2 * P * (EA - EC);
S1 = 1 + E2 * (E2 * T(9) / 88 - E3 * T(9) / 52 - T(3) / 14);
S2 = EB * (T(1) / 6 + P * (T(-6) / 22 + P * T(3) / 26));
S3 = P * ((EA - EC) / 3 - P * EA * T(3) / 22);
value = 3 * sigma + factor * (S1 + S2 + S3) / (u * sqrt(u));
return value;
}
} // namespace detail
template <class T1, class T2, class T3, class T4, class Policy>
inline typename tools::promote_args<T1, T2, T3, T4>::type
ellint_rj(T1 x, T2 y, T3 z, T4 p, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(
detail::ellint_rj_imp(
static_cast<value_type>(x),
static_cast<value_type>(y),
static_cast<value_type>(z),
static_cast<value_type>(p),
pol), "boost::math::ellint_rj<%1%>(%1%,%1%,%1%,%1%)");
}
template <class T1, class T2, class T3, class T4>
inline typename tools::promote_args<T1, T2, T3, T4>::type
ellint_rj(T1 x, T2 y, T3 z, T4 p)
{
return ellint_rj(x, y, z, p, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_RJ_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,309 @@
// (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_EXPM1_INCLUDED
#define BOOST_MATH_EXPM1_INCLUDED
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <math.h> // platform's ::expm1
#include <boost/limits.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/series.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/mpl/less_equal.hpp>
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
# include <boost/static_assert.hpp>
#else
# include <boost/assert.hpp>
#endif
namespace boost{ namespace math{
namespace detail
{
// Functor expm1_series returns the next term in the Taylor series
// x^k / k!
// each time that operator() is invoked.
//
template <class T>
struct expm1_series
{
typedef T result_type;
expm1_series(T x)
: k(0), m_x(x), m_term(1) {}
T operator()()
{
++k;
m_term *= m_x;
m_term /= k;
return m_term;
}
int count()const
{
return k;
}
private:
int k;
const T m_x;
T m_term;
expm1_series(const expm1_series&);
expm1_series& operator=(const expm1_series&);
};
//
// Algorithm expm1 is part of C99, but is not yet provided by many compilers.
//
// This version uses a Taylor series expansion for 0.5 > |x| > epsilon.
//
template <class T, class Policy>
T expm1_imp(T x, const mpl::int_<0>&, const Policy& pol)
{
BOOST_MATH_STD_USING
T a = fabs(x);
if(a > T(0.5f))
{
if(a >= tools::log_max_value<T>())
{
if(x > 0)
return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", 0, pol);
return -1;
}
return exp(x) - T(1);
}
if(a < tools::epsilon<T>())
return x;
detail::expm1_series<T> s(x);
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) && !BOOST_WORKAROUND(__EDG_VERSION__, <= 245)
T result = tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter);
#else
T zero = 0;
T result = tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter, zero);
#endif
policies::check_series_iterations<T>("boost::math::expm1<%1%>(%1%)", max_iter, pol);
return result;
}
template <class T, class P>
T expm1_imp(T x, const mpl::int_<53>&, const P& pol)
{
BOOST_MATH_STD_USING
T a = fabs(x);
if(a > T(0.5L))
{
if(a >= tools::log_max_value<T>())
{
if(x > 0)
return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", 0, pol);
return -1;
}
return exp(x) - T(1);
}
if(a < tools::epsilon<T>())
return x;
static const float Y = 0.10281276702880859e1f;
static const T n[] = { -0.28127670288085937e-1, 0.51278186299064534e0, -0.6310029069350198e-1, 0.11638457975729296e-1, -0.52143390687521003e-3, 0.21491399776965688e-4 };
static const T d[] = { 1, -0.45442309511354755e0, 0.90850389570911714e-1, -0.10088963629815502e-1, 0.63003407478692265e-3, -0.17976570003654402e-4 };
T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
return result;
}
template <class T, class P>
T expm1_imp(T x, const mpl::int_<64>&, const P& pol)
{
BOOST_MATH_STD_USING
T a = fabs(x);
if(a > T(0.5L))
{
if(a >= tools::log_max_value<T>())
{
if(x > 0)
return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", 0, pol);
return -1;
}
return exp(x) - T(1);
}
if(a < tools::epsilon<T>())
return x;
static const float Y = 0.10281276702880859375e1f;
static const T n[] = {
-0.281276702880859375e-1L,
0.512980290285154286358e0L,
-0.667758794592881019644e-1L,
0.131432469658444745835e-1L,
-0.72303795326880286965e-3L,
0.447441185192951335042e-4L,
-0.714539134024984593011e-6L
};
static const T d[] = {
1,
-0.461477618025562520389e0L,
0.961237488025708540713e-1L,
-0.116483957658204450739e-1L,
0.873308008461557544458e-3L,
-0.387922804997682392562e-4L,
0.807473180049193557294e-6L
};
T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
return result;
}
template <class T, class P>
T expm1_imp(T x, const mpl::int_<113>&, const P& pol)
{
BOOST_MATH_STD_USING
T a = fabs(x);
if(a > T(0.5L))
{
if(a >= tools::log_max_value<T>())
{
if(x > 0)
return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", 0, pol);
return -1;
}
return exp(x) - T(1);
}
if(a < tools::epsilon<T>())
return x;
static const float Y = 0.10281276702880859375e1f;
static const T n[] = {
-0.28127670288085937499999999999999999854e-1L,
0.51278156911210477556524452177540792214e0L,
-0.63263178520747096729500254678819588223e-1L,
0.14703285606874250425508446801230572252e-1L,
-0.8675686051689527802425310407898459386e-3L,
0.88126359618291165384647080266133492399e-4L,
-0.25963087867706310844432390015463138953e-5L,
0.14226691087800461778631773363204081194e-6L,
-0.15995603306536496772374181066765665596e-8L,
0.45261820069007790520447958280473183582e-10L
};
static const T d[] = {
1,
-0.45441264709074310514348137469214538853e0L,
0.96827131936192217313133611655555298106e-1L,
-0.12745248725908178612540554584374876219e-1L,
0.11473613871583259821612766907781095472e-2L,
-0.73704168477258911962046591907690764416e-4L,
0.34087499397791555759285503797256103259e-5L,
-0.11114024704296196166272091230695179724e-6L,
0.23987051614110848595909588343223896577e-8L,
-0.29477341859111589208776402638429026517e-10L,
0.13222065991022301420255904060628100924e-12L
};
T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
return result;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type expm1(T x, const Policy& /* pol */)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::precision<result_type, Policy>::type precision_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
typedef typename mpl::if_c<
::std::numeric_limits<result_type>::is_specialized == 0,
mpl::int_<0>, // no numeric_limits, use generic solution
typename mpl::if_<
typename mpl::less_equal<precision_type, mpl::int_<53> >::type,
mpl::int_<53>, // double
typename mpl::if_<
typename mpl::less_equal<precision_type, mpl::int_<64> >::type,
mpl::int_<64>, // 80-bit long double
typename mpl::if_<
typename mpl::less_equal<precision_type, mpl::int_<113> >::type,
mpl::int_<113>, // 128-bit long double
mpl::int_<0> // too many bits, use generic version.
>::type
>::type
>::type
>::type tag_type;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::expm1_imp(
static_cast<value_type>(x),
tag_type(), forwarding_policy()), "boost::math::expm1<%1%>(%1%)");
}
#ifdef expm1
# ifndef BOOST_HAS_expm1
# define BOOST_HAS_expm1
# endif
# undef expm1
#endif
#if defined(BOOST_HAS_EXPM1) && !(defined(__osf__) && defined(__DECCXX_VER))
# ifdef BOOST_MATH_USE_C99
inline float expm1(float x, const policies::policy<>&){ return ::expm1f(x); }
# ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
inline long double expm1(long double x, const policies::policy<>&){ return ::expm1l(x); }
# endif
# else
inline float expm1(float x, const policies::policy<>&){ return ::expm1(x); }
# endif
inline double expm1(double x, const policies::policy<>&){ return ::expm1(x); }
#endif
template <class T>
inline typename tools::promote_args<T>::type expm1(T x)
{
return expm1(x, policies::policy<>());
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
inline float expm1(float z)
{
return expm1<float>(z);
}
inline double expm1(double z)
{
return expm1<double>(z);
}
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
inline long double expm1(long double z)
{
return expm1<long double>(z);
}
#endif
#endif
} // namespace math
} // namespace boost
#endif // BOOST_MATH_HYPOT_INCLUDED

View File

@@ -0,0 +1,240 @@
// Copyright John Maddock 2006, 2010.
// 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_FACTORIALS_HPP
#define BOOST_MATH_SP_FACTORIALS_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/detail/unchecked_factorial.hpp>
#include <boost/array.hpp>
#ifdef BOOST_MSVC
#pragma warning(push) // Temporary until lexical cast fixed.
#pragma warning(disable: 4127 4701)
#endif
#include <boost/lexical_cast.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <boost/config/no_tr1/cmath.hpp>
namespace boost { namespace math
{
template <class T, class Policy>
inline T factorial(unsigned i, const Policy& pol)
{
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.
BOOST_MATH_STD_USING // Aid ADL for floor.
if(i <= max_factorial<T>::value)
return unchecked_factorial<T>(i);
T result = boost::math::tgamma(static_cast<T>(i+1), pol);
if(result > tools::max_value<T>())
return result; // Overflowed value! (But tgamma will have signalled the error already).
return floor(result + 0.5f);
}
template <class T>
inline T factorial(unsigned i)
{
return factorial<T>(i, policies::policy<>());
}
/*
// Can't have these in a policy enabled world?
template<>
inline float factorial<float>(unsigned i)
{
if(i <= max_factorial<float>::value)
return unchecked_factorial<float>(i);
return tools::overflow_error<float>(BOOST_CURRENT_FUNCTION);
}
template<>
inline double factorial<double>(unsigned i)
{
if(i <= max_factorial<double>::value)
return unchecked_factorial<double>(i);
return tools::overflow_error<double>(BOOST_CURRENT_FUNCTION);
}
*/
template <class T, class Policy>
T double_factorial(unsigned i, const Policy& pol)
{
BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
BOOST_MATH_STD_USING // ADL lookup of std names
if(i & 1)
{
// odd i:
if(i < max_factorial<T>::value)
{
unsigned n = (i - 1) / 2;
return ceil(unchecked_factorial<T>(i) / (ldexp(T(1), (int)n) * unchecked_factorial<T>(n)) - 0.5f);
}
//
// Fallthrough: i is too large to use table lookup, try the
// gamma function instead.
//
T result = boost::math::tgamma(static_cast<T>(i) / 2 + 1, pol) / sqrt(constants::pi<T>());
if(ldexp(tools::max_value<T>(), -static_cast<int>(i+1) / 2) > result)
return ceil(result * ldexp(T(1), static_cast<int>(i+1) / 2) - 0.5f);
}
else
{
// even i:
unsigned n = i / 2;
T result = factorial<T>(n, pol);
if(ldexp(tools::max_value<T>(), -(int)n) > result)
return result * ldexp(T(1), (int)n);
}
//
// If we fall through to here then the result is infinite:
//
return policies::raise_overflow_error<T>("boost::math::double_factorial<%1%>(unsigned)", 0, pol);
}
template <class T>
inline T double_factorial(unsigned i)
{
return double_factorial<T>(i, policies::policy<>());
}
namespace detail{
template <class T, class Policy>
T rising_factorial_imp(T x, int n, const Policy& pol)
{
BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
if(x < 0)
{
//
// For x less than zero, we really have a falling
// factorial, modulo a possible change of sign.
//
// Note that the falling factorial isn't defined
// for negative n, so we'll get rid of that case
// first:
//
bool inv = false;
if(n < 0)
{
x += n;
n = -n;
inv = true;
}
T result = ((n&1) ? -1 : 1) * falling_factorial(-x, n, pol);
if(inv)
result = 1 / result;
return result;
}
if(n == 0)
return 1;
//
// We don't optimise this for small n, because
// tgamma_delta_ratio is alreay optimised for that
// use case:
//
return 1 / boost::math::tgamma_delta_ratio(x, static_cast<T>(n), pol);
}
template <class T, class Policy>
inline T falling_factorial_imp(T x, unsigned n, const Policy& pol)
{
BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
BOOST_MATH_STD_USING // ADL of std names
if(x == 0)
return 0;
if(x < 0)
{
//
// For x < 0 we really have a rising factorial
// modulo a possible change of sign:
//
return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol);
}
if(n == 0)
return 1;
if(x < n-1)
{
//
// x+1-n will be negative and tgamma_delta_ratio won't
// handle it, split the product up into three parts:
//
T xp1 = x + 1;
unsigned n2 = itrunc((T)floor(xp1), pol);
if(n2 == xp1)
return 0;
T result = boost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol);
x -= n2;
result *= x;
++n2;
if(n2 < n)
result *= falling_factorial(x - 1, n - n2, pol);
return result;
}
//
// Simple case: just the ratio of two
// (positive argument) gamma functions.
// Note that we don't optimise this for small n,
// because tgamma_delta_ratio is alreay optimised
// for that use case:
//
return boost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol);
}
} // namespace detail
template <class RT>
inline typename tools::promote_args<RT>::type
falling_factorial(RT x, unsigned n)
{
typedef typename tools::promote_args<RT>::type result_type;
return detail::falling_factorial_imp(
static_cast<result_type>(x), n, policies::policy<>());
}
template <class RT, class Policy>
inline typename tools::promote_args<RT>::type
falling_factorial(RT x, unsigned n, const Policy& pol)
{
typedef typename tools::promote_args<RT>::type result_type;
return detail::falling_factorial_imp(
static_cast<result_type>(x), n, pol);
}
template <class RT>
inline typename tools::promote_args<RT>::type
rising_factorial(RT x, int n)
{
typedef typename tools::promote_args<RT>::type result_type;
return detail::rising_factorial_imp(
static_cast<result_type>(x), n, policies::policy<>());
}
template <class RT, class Policy>
inline typename tools::promote_args<RT>::type
rising_factorial(RT x, int n, const Policy& pol)
{
typedef typename tools::promote_args<RT>::type result_type;
return detail::rising_factorial_imp(
static_cast<result_type>(x), n, pol);
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SP_FACTORIALS_HPP

View File

@@ -0,0 +1,533 @@
// Copyright John Maddock 2005-2008.
// Copyright (c) 2006-2008 Johan Rade
// 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_FPCLASSIFY_HPP
#define BOOST_MATH_FPCLASSIFY_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <math.h>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/limits.hpp>
#include <boost/math/tools/real_cast.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/detail/fp_traits.hpp>
/*!
\file fpclassify.hpp
\brief Classify floating-point value as normal, subnormal, zero, infinite, or NaN.
\version 1.0
\author John Maddock
*/
/*
1. If the platform is C99 compliant, then the native floating point
classification functions are used. However, note that we must only
define the functions which call std::fpclassify etc if that function
really does exist: otherwise a compiler may reject the code even though
the template is never instantiated.
2. If the platform is not C99 compliant, and the binary format for
a floating point type (float, double or long double) can be determined
at compile time, then the following algorithm is used:
If all exponent bits, the flag bit (if there is one),
and all significand bits are 0, then the number is zero.
If all exponent bits and the flag bit (if there is one) are 0,
and at least one significand bit is 1, then the number is subnormal.
If all exponent bits are 1 and all significand bits are 0,
then the number is infinity.
If all exponent bits are 1 and at least one significand bit is 1,
then the number is a not-a-number.
Otherwise the number is normal.
This algorithm works for the IEEE 754 representation,
and also for several non IEEE 754 formats.
Most formats have the structure
sign bit + exponent bits + significand bits.
A few have the structure
sign bit + exponent bits + flag bit + significand bits.
The flag bit is 0 for zero and subnormal numbers,
and 1 for normal numbers and NaN.
It is 0 (Motorola 68K) or 1 (Intel) for infinity.
To get the bits, the four or eight most significant bytes are copied
into an uint32_t or uint64_t and bit masks are applied.
This covers all the exponent bits and the flag bit (if there is one),
but not always all the significand bits.
Some of the functions below have two implementations,
depending on whether all the significand bits are copied or not.
3. If the platform is not C99 compliant, and the binary format for
a floating point type (float, double or long double) can not be determined
at compile time, then comparison with std::numeric_limits values
is used.
*/
#if defined(_MSC_VER) || defined(__BORLANDC__)
#include <float.h>
#endif
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::abs; using ::fabs; }
#endif
namespace boost{
//
// This must not be located in any namespace under boost::math
// otherwise we can get into an infinite loop if isnan is
// a #define for "isnan" !
//
namespace math_detail{
template <class T>
inline bool is_nan_helper(T t, const boost::true_type&)
{
#ifdef isnan
return isnan(t);
#elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
return false;
#else // BOOST_HAS_FPCLASSIFY
return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
#endif
}
template <class T>
inline bool is_nan_helper(T, const boost::false_type&)
{
return false;
}
}
namespace math{
namespace detail{
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
template <class T>
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
{
return (std::fpclassify)(t);
}
#endif
template <class T>
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
{
BOOST_MATH_INSTRUMENT_VARIABLE(t);
// whenever possible check for Nan's first:
#if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
return FP_NAN;
#elif defined(isnan)
if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
return FP_NAN;
#elif defined(_MSC_VER) || defined(__BORLANDC__)
if(::_isnan(boost::math::tools::real_cast<double>(t)))
return FP_NAN;
#endif
// std::fabs broken on a few systems especially for long long!!!!
T at = (t < T(0)) ? -t : t;
// Use a process of exclusion to figure out
// what kind of type we have, this relies on
// IEEE conforming reals that will treat
// Nan's as unordered. Some compilers
// don't do this once optimisations are
// turned on, hence the check for nan's above.
if(at <= (std::numeric_limits<T>::max)())
{
if(at >= (std::numeric_limits<T>::min)())
return FP_NORMAL;
return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
}
else if(at > (std::numeric_limits<T>::max)())
return FP_INFINITE;
return FP_NAN;
}
template <class T>
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
{
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<T>::is_specialized)
return fp_classify_imp(t, mpl::true_());
#endif
//
// An unknown type with no numeric_limits support,
// so what are we supposed to do we do here?
//
BOOST_MATH_INSTRUMENT_VARIABLE(t);
return t == 0 ? FP_ZERO : FP_NORMAL;
}
template<class T>
int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_all_bits_tag)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_MATH_INSTRUMENT_VARIABLE(x);
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
BOOST_MATH_INSTRUMENT_VARIABLE(a);
a &= traits::exponent | traits::flag | traits::significand;
BOOST_MATH_INSTRUMENT_VARIABLE((traits::exponent | traits::flag | traits::significand));
BOOST_MATH_INSTRUMENT_VARIABLE(a);
if(a <= traits::significand) {
if(a == 0)
return FP_ZERO;
else
return FP_SUBNORMAL;
}
if(a < traits::exponent) return FP_NORMAL;
a &= traits::significand;
if(a == 0) return FP_INFINITE;
return FP_NAN;
}
template<class T>
int fpclassify_imp BOOST_NO_MACRO_EXPAND(T x, ieee_copy_leading_bits_tag)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_MATH_INSTRUMENT_VARIABLE(x);
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a &= traits::exponent | traits::flag | traits::significand;
if(a <= traits::significand) {
if(x == 0)
return FP_ZERO;
else
return FP_SUBNORMAL;
}
if(a < traits::exponent) return FP_NORMAL;
a &= traits::significand;
traits::set_bits(x,a);
if(x == 0) return FP_INFINITE;
return FP_NAN;
}
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
template <>
inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
{
return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
}
#endif
} // namespace detail
template <class T>
inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
{
typedef typename detail::fp_traits<T>::type traits;
typedef typename traits::method method;
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(method()))
return detail::fpclassify_imp(t, detail::generic_tag<true>());
return detail::fpclassify_imp(t, method());
#else
return detail::fpclassify_imp(t, method());
#endif
}
namespace detail {
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
template<class T>
inline bool isfinite_impl(T x, native_tag const&)
{
return (std::isfinite)(x);
}
#endif
template<class T>
inline bool isfinite_impl(T x, generic_tag<true> const&)
{
return x >= -(std::numeric_limits<T>::max)()
&& x <= (std::numeric_limits<T>::max)();
}
template<class T>
inline bool isfinite_impl(T x, generic_tag<false> const&)
{
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<T>::is_specialized)
return isfinite_impl(x, mpl::true_());
#endif
(void)x; // warning supression.
return true;
}
template<class T>
inline bool isfinite_impl(T x, ieee_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a &= traits::exponent;
return a != traits::exponent;
}
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
template <>
inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
{
return boost::math::detail::isfinite_impl(t, generic_tag<true>());
}
#endif
}
template<class T>
inline bool (isfinite)(T x)
{ //!< \brief return true if floating-point type t is finite.
typedef typename detail::fp_traits<T>::type traits;
typedef typename traits::method method;
typedef typename boost::is_floating_point<T>::type fp_tag;
return detail::isfinite_impl(x, method());
}
//------------------------------------------------------------------------------
namespace detail {
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
template<class T>
inline bool isnormal_impl(T x, native_tag const&)
{
return (std::isnormal)(x);
}
#endif
template<class T>
inline bool isnormal_impl(T x, generic_tag<true> const&)
{
if(x < 0) x = -x;
return x >= (std::numeric_limits<T>::min)()
&& x <= (std::numeric_limits<T>::max)();
}
template<class T>
inline bool isnormal_impl(T x, generic_tag<false> const&)
{
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<T>::is_specialized)
return isnormal_impl(x, mpl::true_());
#endif
return !(x == 0);
}
template<class T>
inline bool isnormal_impl(T x, ieee_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a &= traits::exponent | traits::flag;
return (a != 0) && (a < traits::exponent);
}
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
template <>
inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
{
return boost::math::detail::isnormal_impl(t, generic_tag<true>());
}
#endif
}
template<class T>
inline bool (isnormal)(T x)
{
typedef typename detail::fp_traits<T>::type traits;
typedef typename traits::method method;
typedef typename boost::is_floating_point<T>::type fp_tag;
return detail::isnormal_impl(x, method());
}
//------------------------------------------------------------------------------
namespace detail {
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
template<class T>
inline bool isinf_impl(T x, native_tag const&)
{
return (std::isinf)(x);
}
#endif
template<class T>
inline bool isinf_impl(T x, generic_tag<true> const&)
{
(void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false
return std::numeric_limits<T>::has_infinity
&& ( x == std::numeric_limits<T>::infinity()
|| x == -std::numeric_limits<T>::infinity());
}
template<class T>
inline bool isinf_impl(T x, generic_tag<false> const&)
{
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<T>::is_specialized)
return isinf_impl(x, mpl::true_());
#endif
(void)x; // warning supression.
return false;
}
template<class T>
inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a &= traits::exponent | traits::significand;
return a == traits::exponent;
}
template<class T>
inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a &= traits::exponent | traits::significand;
if(a != traits::exponent)
return false;
traits::set_bits(x,0);
return x == 0;
}
#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
template <>
inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
{
return boost::math::detail::isinf_impl(t, generic_tag<true>());
}
#endif
} // namespace detail
template<class T>
inline bool (isinf)(T x)
{
typedef typename detail::fp_traits<T>::type traits;
typedef typename traits::method method;
typedef typename boost::is_floating_point<T>::type fp_tag;
return detail::isinf_impl(x, method());
}
//------------------------------------------------------------------------------
namespace detail {
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
template<class T>
inline bool isnan_impl(T x, native_tag const&)
{
return (std::isnan)(x);
}
#endif
template<class T>
inline bool isnan_impl(T x, generic_tag<true> const&)
{
return std::numeric_limits<T>::has_infinity
? !(x <= std::numeric_limits<T>::infinity())
: x != x;
}
template<class T>
inline bool isnan_impl(T x, generic_tag<false> const&)
{
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<T>::is_specialized)
return isnan_impl(x, mpl::true_());
#endif
(void)x; // warning supression
return false;
}
template<class T>
inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a &= traits::exponent | traits::significand;
return a > traits::exponent;
}
template<class T>
inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a &= traits::exponent | traits::significand;
if(a < traits::exponent)
return false;
a &= traits::significand;
traits::set_bits(x,a);
return x != 0;
}
} // namespace detail
template<class T> bool (isnan)(T x)
{ //!< \brief return true if floating-point type t is NaN (Not A Number).
typedef typename detail::fp_traits<T>::type traits;
typedef typename traits::method method;
typedef typename boost::is_floating_point<T>::type fp_tag;
return detail::isnan_impl(x, method());
}
#ifdef isnan
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
#endif
} // namespace math
} // namespace boost
#endif // BOOST_MATH_FPCLASSIFY_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
// (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_HERMITE_HPP
#define BOOST_MATH_SPECIAL_HERMITE_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
namespace boost{
namespace math{
// Recurrance relation for Hermite polynomials:
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
hermite_next(unsigned n, T1 x, T2 Hn, T3 Hnm1)
{
return (2 * x * Hn - 2 * n * Hnm1);
}
namespace detail{
// Implement Hermite polynomials via recurrance:
template <class T>
T hermite_imp(unsigned n, T x)
{
T p0 = 1;
T p1 = 2 * x;
if(n == 0)
return p0;
unsigned c = 1;
while(c < n)
{
std::swap(p0, p1);
p1 = hermite_next(c, x, p0, p1);
++c;
}
return p1;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type
hermite(unsigned n, T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::hermite_imp(n, static_cast<value_type>(x)), "boost::math::hermite<%1%>(unsigned, %1%)");
}
template <class T>
inline typename tools::promote_args<T>::type
hermite(unsigned n, T x)
{
return boost::math::hermite(n, x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_HERMITE_HPP

View File

@@ -0,0 +1,86 @@
// (C) Copyright John Maddock 2005-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_HYPOT_INCLUDED
#define BOOST_MATH_HYPOT_INCLUDED
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#include <algorithm> // for swap
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::sqrt; using ::fabs; }
#endif
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
T hypot_imp(T x, T y, const Policy& pol)
{
//
// Normalize x and y, so that both are positive and x >= y:
//
using std::fabs; using std::sqrt; // ADL of std names
x = fabs(x);
y = fabs(y);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4127)
#endif
// special case, see C99 Annex F:
if(std::numeric_limits<T>::has_infinity
&& ((x == std::numeric_limits<T>::infinity())
|| (y == std::numeric_limits<T>::infinity())))
return policies::raise_overflow_error<T>("boost::math::hypot<%1%>(%1%,%1%)", 0, pol);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(y > x)
(std::swap)(x, y);
if(x * tools::epsilon<T>() >= y)
return x;
T rat = y / x;
return x * sqrt(1 + rat*rat);
} // template <class T> T hypot(T x, T y)
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
hypot(T1 x, T2 y)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
return detail::hypot_imp(
static_cast<result_type>(x), static_cast<result_type>(y), policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
hypot(T1 x, T2 y, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
return detail::hypot_imp(
static_cast<result_type>(x), static_cast<result_type>(y), pol);
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_HYPOT_INCLUDED

View File

@@ -0,0 +1,139 @@
// (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_LAGUERRE_HPP
#define BOOST_MATH_SPECIAL_LAGUERRE_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
namespace boost{
namespace math{
// Recurrance relation for Laguerre polynomials:
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
laguerre_next(unsigned n, T1 x, T2 Ln, T3 Lnm1)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
return ((2 * n + 1 - result_type(x)) * result_type(Ln) - n * result_type(Lnm1)) / (n + 1);
}
namespace detail{
// Implement Laguerre polynomials via recurrance:
template <class T>
T laguerre_imp(unsigned n, T x)
{
T p0 = 1;
T p1 = 1 - x;
if(n == 0)
return p0;
unsigned c = 1;
while(c < n)
{
std::swap(p0, p1);
p1 = laguerre_next(c, x, p0, p1);
++c;
}
return p1;
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type
laguerre(unsigned n, T x, const Policy&, const mpl::true_&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::laguerre_imp(n, static_cast<value_type>(x)), "boost::math::laguerre<%1%>(unsigned, %1%)");
}
template <class T>
inline typename tools::promote_args<T>::type
laguerre(unsigned n, unsigned m, T x, const mpl::false_&)
{
return boost::math::laguerre(n, m, x, policies::policy<>());
}
} // namespace detail
template <class T>
inline typename tools::promote_args<T>::type
laguerre(unsigned n, T x)
{
return laguerre(n, x, policies::policy<>());
}
// Recurrence for associated polynomials:
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
laguerre_next(unsigned n, unsigned l, T1 x, T2 Pl, T3 Plm1)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
return ((2 * n + l + 1 - result_type(x)) * result_type(Pl) - (n + l) * result_type(Plm1)) / (n+1);
}
namespace detail{
// Laguerre Associated Polynomial:
template <class T, class Policy>
T laguerre_imp(unsigned n, unsigned m, T x, const Policy& pol)
{
// Special cases:
if(m == 0)
return boost::math::laguerre(n, x, pol);
T p0 = 1;
if(n == 0)
return p0;
T p1 = m + 1 - x;
unsigned c = 1;
while(c < n)
{
std::swap(p0, p1);
p1 = laguerre_next(c, m, x, p0, p1);
++c;
}
return p1;
}
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type
laguerre(unsigned n, unsigned m, T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::laguerre_imp(n, m, static_cast<value_type>(x), pol), "boost::math::laguerre<%1%>(unsigned, unsigned, %1%)");
}
template <class T1, class T2>
inline typename laguerre_result<T1, T2>::type
laguerre(unsigned n, T1 m, T2 x)
{
typedef typename policies::is_policy<T2>::type tag_type;
return detail::laguerre(n, m, x, tag_type());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_LAGUERRE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,194 @@
// (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_LEGENDRE_HPP
#define BOOST_MATH_SPECIAL_LEGENDRE_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/tools/config.hpp>
namespace boost{
namespace math{
// Recurrance relation for legendre P and Q polynomials:
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
legendre_next(unsigned l, T1 x, T2 Pl, T3 Plm1)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
return ((2 * l + 1) * result_type(x) * result_type(Pl) - l * result_type(Plm1)) / (l + 1);
}
namespace detail{
// Implement Legendre P and Q polynomials via recurrance:
template <class T, class Policy>
T legendre_imp(unsigned l, T x, const Policy& pol, bool second = false)
{
static const char* function = "boost::math::legrendre_p<%1%>(unsigned, %1%)";
// Error handling:
if((x < -1) || (x > 1))
return policies::raise_domain_error<T>(
function,
"The Legendre Polynomial is defined for"
" -1 <= x <= 1, but got x = %1%.", x, pol);
T p0, p1;
if(second)
{
// A solution of the second kind (Q):
p0 = (boost::math::log1p(x, pol) - boost::math::log1p(-x, pol)) / 2;
p1 = x * p0 - 1;
}
else
{
// A solution of the first kind (P):
p0 = 1;
p1 = x;
}
if(l == 0)
return p0;
unsigned n = 1;
while(n < l)
{
std::swap(p0, p1);
p1 = boost::math::legendre_next(n, x, p0, p1);
++n;
}
return p1;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type
legendre_p(int l, T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
static const char* function = "boost::math::legendre_p<%1%>(unsigned, %1%)";
if(l < 0)
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(-l-1, static_cast<value_type>(x), pol, false), function);
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(l, static_cast<value_type>(x), pol, false), function);
}
template <class T>
inline typename tools::promote_args<T>::type
legendre_p(int l, T x)
{
return boost::math::legendre_p(l, x, policies::policy<>());
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type
legendre_q(unsigned l, T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(l, static_cast<value_type>(x), pol, true), "boost::math::legendre_q<%1%>(unsigned, %1%)");
}
template <class T>
inline typename tools::promote_args<T>::type
legendre_q(unsigned l, T x)
{
return boost::math::legendre_q(l, x, policies::policy<>());
}
// Recurrence for associated polynomials:
template <class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type
legendre_next(unsigned l, unsigned m, T1 x, T2 Pl, T3 Plm1)
{
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
return ((2 * l + 1) * result_type(x) * result_type(Pl) - (l + m) * result_type(Plm1)) / (l + 1 - m);
}
namespace detail{
// Legendre P associated polynomial:
template <class T, class Policy>
T legendre_p_imp(int l, int m, T x, T sin_theta_power, const Policy& pol)
{
// Error handling:
if((x < -1) || (x > 1))
return policies::raise_domain_error<T>(
"boost::math::legendre_p<%1%>(int, int, %1%)",
"The associated Legendre Polynomial is defined for"
" -1 <= x <= 1, but got x = %1%.", x, pol);
// Handle negative arguments first:
if(l < 0)
return legendre_p_imp(-l-1, m, x, sin_theta_power, pol);
if(m < 0)
{
int sign = (m&1) ? -1 : 1;
return sign * boost::math::tgamma_ratio(static_cast<T>(l+m+1), static_cast<T>(l+1-m), pol) * legendre_p_imp(l, -m, x, sin_theta_power, pol);
}
// Special cases:
if(m > l)
return 0;
if(m == 0)
return boost::math::legendre_p(l, x, pol);
T p0 = boost::math::double_factorial<T>(2 * m - 1, pol) * sin_theta_power;
if(m&1)
p0 *= -1;
if(m == l)
return p0;
T p1 = x * (2 * m + 1) * p0;
int n = m + 1;
while(n < l)
{
std::swap(p0, p1);
p1 = boost::math::legendre_next(n, m, x, p0, p1);
++n;
}
return p1;
}
template <class T, class Policy>
inline T legendre_p_imp(int l, int m, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
// TODO: we really could use that mythical "pow1p" function here:
return legendre_p_imp(l, m, x, static_cast<T>(pow(1 - x*x, T(abs(m))/2)), pol);
}
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type
legendre_p(int l, int m, T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_p_imp(l, m, static_cast<value_type>(x), pol), "bost::math::legendre_p<%1%>(int, int, %1%)");
}
template <class T>
inline typename tools::promote_args<T>::type
legendre_p(int l, int m, T x)
{
return boost::math::legendre_p(l, m, x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_LEGENDRE_HPP

View File

@@ -0,0 +1,471 @@
// (C) Copyright John Maddock 2005-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_LOG1P_INCLUDED
#define BOOST_MATH_LOG1P_INCLUDED
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <math.h> // platform's ::log1p
#include <boost/limits.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/series.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
# include <boost/static_assert.hpp>
#else
# include <boost/assert.hpp>
#endif
namespace boost{ namespace math{
namespace detail
{
// Functor log1p_series returns the next term in the Taylor series
// pow(-1, k-1)*pow(x, k) / k
// each time that operator() is invoked.
//
template <class T>
struct log1p_series
{
typedef T result_type;
log1p_series(T x)
: k(0), m_mult(-x), m_prod(-1){}
T operator()()
{
m_prod *= m_mult;
return m_prod / ++k;
}
int count()const
{
return k;
}
private:
int k;
const T m_mult;
T m_prod;
log1p_series(const log1p_series&);
log1p_series& operator=(const log1p_series&);
};
// Algorithm log1p is part of C99, but is not yet provided by many compilers.
//
// This version uses a Taylor series expansion for 0.5 > x > epsilon, which may
// require up to std::numeric_limits<T>::digits+1 terms to be calculated.
// It would be much more efficient to use the equivalence:
// log(1+x) == (log(1+x) * x) / ((1-x) - 1)
// Unfortunately many optimizing compilers make such a mess of this, that
// it performs no better than log(1+x): which is to say not very well at all.
//
template <class T, class Policy>
T log1p_imp(T const & x, const Policy& pol, const mpl::int_<0>&)
{ // The function returns the natural logarithm of 1 + x.
typedef typename tools::promote_args<T>::type result_type;
BOOST_MATH_STD_USING
static const char* function = "boost::math::log1p<%1%>(%1%)";
if(x < -1)
return policies::raise_domain_error<T>(
function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<T>(
function, 0, pol);
result_type a = abs(result_type(x));
if(a > result_type(0.5f))
return log(1 + result_type(x));
// Note that without numeric_limits specialisation support,
// epsilon just returns zero, and our "optimisation" will always fail:
if(a < tools::epsilon<result_type>())
return x;
detail::log1p_series<result_type> s(x);
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) && !BOOST_WORKAROUND(__EDG_VERSION__, <= 245)
result_type result = tools::sum_series(s, policies::get_epsilon<result_type, Policy>(), max_iter);
#else
result_type zero = 0;
result_type result = tools::sum_series(s, policies::get_epsilon<result_type, Policy>(), max_iter, zero);
#endif
policies::check_series_iterations<T>(function, max_iter, pol);
return result;
}
template <class T, class Policy>
T log1p_imp(T const& x, const Policy& pol, const mpl::int_<53>&)
{ // The function returns the natural logarithm of 1 + x.
BOOST_MATH_STD_USING
static const char* function = "boost::math::log1p<%1%>(%1%)";
if(x < -1)
return policies::raise_domain_error<T>(
function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<T>(
function, 0, pol);
T a = fabs(x);
if(a > 0.5f)
return log(1 + x);
// Note that without numeric_limits specialisation support,
// epsilon just returns zero, and our "optimisation" will always fail:
if(a < tools::epsilon<T>())
return x;
// Maximum Deviation Found: 1.846e-017
// Expected Error Term: 1.843e-017
// Maximum Relative Change in Control Points: 8.138e-004
// Max Error found at double precision = 3.250766e-016
static const T P[] = {
0.15141069795941984e-16L,
0.35495104378055055e-15L,
0.33333333333332835L,
0.99249063543365859L,
1.1143969784156509L,
0.58052937949269651L,
0.13703234928513215L,
0.011294864812099712L
};
static const T Q[] = {
1L,
3.7274719063011499L,
5.5387948649720334L,
4.159201143419005L,
1.6423855110312755L,
0.31706251443180914L,
0.022665554431410243L,
-0.29252538135177773e-5L
};
T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
result *= x;
return result;
}
template <class T, class Policy>
T log1p_imp(T const& x, const Policy& pol, const mpl::int_<64>&)
{ // The function returns the natural logarithm of 1 + x.
BOOST_MATH_STD_USING
static const char* function = "boost::math::log1p<%1%>(%1%)";
if(x < -1)
return policies::raise_domain_error<T>(
function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<T>(
function, 0, pol);
T a = fabs(x);
if(a > 0.5f)
return log(1 + x);
// Note that without numeric_limits specialisation support,
// epsilon just returns zero, and our "optimisation" will always fail:
if(a < tools::epsilon<T>())
return x;
// Maximum Deviation Found: 8.089e-20
// Expected Error Term: 8.088e-20
// Maximum Relative Change in Control Points: 9.648e-05
// Max Error found at long double precision = 2.242324e-19
static const T P[] = {
-0.807533446680736736712e-19L,
-0.490881544804798926426e-18L,
0.333333333333333373941L,
1.17141290782087994162L,
1.62790522814926264694L,
1.13156411870766876113L,
0.408087379932853785336L,
0.0706537026422828914622L,
0.00441709903782239229447L
};
static const T Q[] = {
1L,
4.26423872346263928361L,
7.48189472704477708962L,
6.94757016732904280913L,
3.6493508622280767304L,
1.06884863623790638317L,
0.158292216998514145947L,
0.00885295524069924328658L,
-0.560026216133415663808e-6L
};
T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
result *= x;
return result;
}
template <class T, class Policy>
T log1p_imp(T const& x, const Policy& pol, const mpl::int_<24>&)
{ // The function returns the natural logarithm of 1 + x.
BOOST_MATH_STD_USING
static const char* function = "boost::math::log1p<%1%>(%1%)";
if(x < -1)
return policies::raise_domain_error<T>(
function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<T>(
function, 0, pol);
T a = fabs(x);
if(a > 0.5f)
return log(1 + x);
// Note that without numeric_limits specialisation support,
// epsilon just returns zero, and our "optimisation" will always fail:
if(a < tools::epsilon<T>())
return x;
// Maximum Deviation Found: 6.910e-08
// Expected Error Term: 6.910e-08
// Maximum Relative Change in Control Points: 2.509e-04
// Max Error found at double precision = 6.910422e-08
// Max Error found at float precision = 8.357242e-08
static const T P[] = {
-0.671192866803148236519e-7L,
0.119670999140731844725e-6L,
0.333339469182083148598L,
0.237827183019664122066L
};
static const T Q[] = {
1L,
1.46348272586988539733L,
0.497859871350117338894L,
-0.00471666268910169651936L
};
T result = 1 - x / 2 + tools::evaluate_polynomial(P, x) / tools::evaluate_polynomial(Q, x);
result *= x;
return result;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type log1p(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::precision<result_type, Policy>::type precision_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
typedef typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<0> >,
mpl::int_<0>,
typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<53> >,
mpl::int_<53>, // double
typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<64> >,
mpl::int_<64>, // 80-bit long double
mpl::int_<0> // too many bits, use generic version.
>::type
>::type
>::type tag_type;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::log1p_imp(static_cast<value_type>(x), forwarding_policy(), tag_type()), "boost::math::log1p<%1%>(%1%)");
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// These overloads work around a type deduction bug:
inline float log1p(float z)
{
return log1p<float>(z);
}
inline double log1p(double z)
{
return log1p<double>(z);
}
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
inline long double log1p(long double z)
{
return log1p<long double>(z);
}
#endif
#endif
#ifdef log1p
# ifndef BOOST_HAS_LOG1P
# define BOOST_HAS_LOG1P
# endif
# undef log1p
#endif
#if defined(BOOST_HAS_LOG1P) && !(defined(__osf__) && defined(__DECCXX_VER))
# ifdef BOOST_MATH_USE_C99
template <class Policy>
inline float log1p(float x, const Policy& pol)
{
if(x < -1)
return policies::raise_domain_error<float>(
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<float>(
"log1p<%1%>(%1%)", 0, pol);
return ::log1pf(x);
}
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
template <class Policy>
inline long double log1p(long double x, const Policy& pol)
{
if(x < -1)
return policies::raise_domain_error<long double>(
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<long double>(
"log1p<%1%>(%1%)", 0, pol);
return ::log1pl(x);
}
#endif
#else
template <class Policy>
inline float log1p(float x, const Policy& pol)
{
if(x < -1)
return policies::raise_domain_error<float>(
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<float>(
"log1p<%1%>(%1%)", 0, pol);
return ::log1p(x);
}
#endif
template <class Policy>
inline double log1p(double x, const Policy& pol)
{
if(x < -1)
return policies::raise_domain_error<double>(
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<double>(
"log1p<%1%>(%1%)", 0, pol);
return ::log1p(x);
}
#elif defined(_MSC_VER) && (BOOST_MSVC >= 1400)
//
// You should only enable this branch if you are absolutely sure
// that your compilers optimizer won't mess this code up!!
// Currently tested with VC8 and Intel 9.1.
//
template <class Policy>
inline double log1p(double x, const Policy& pol)
{
if(x < -1)
return policies::raise_domain_error<double>(
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<double>(
"log1p<%1%>(%1%)", 0, pol);
double u = 1+x;
if(u == 1.0)
return x;
else
return ::log(u)*(x/(u-1.0));
}
template <class Policy>
inline float log1p(float x, const Policy& pol)
{
return static_cast<float>(boost::math::log1p(static_cast<double>(x), pol));
}
#ifndef _WIN32_WCE
//
// For some reason this fails to compile under WinCE...
// Needs more investigation.
//
template <class Policy>
inline long double log1p(long double x, const Policy& pol)
{
if(x < -1)
return policies::raise_domain_error<long double>(
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<long double>(
"log1p<%1%>(%1%)", 0, pol);
long double u = 1+x;
if(u == 1.0)
return x;
else
return ::logl(u)*(x/(u-1.0));
}
#endif
#endif
template <class T>
inline typename tools::promote_args<T>::type log1p(T x)
{
return boost::math::log1p(x, policies::policy<>());
}
//
// Compute log(1+x)-x:
//
template <class T, class Policy>
inline typename tools::promote_args<T>::type
log1pmx(T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
BOOST_MATH_STD_USING
static const char* function = "boost::math::log1pmx<%1%>(%1%)";
if(x < -1)
return policies::raise_domain_error<T>(
function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol);
if(x == -1)
return -policies::raise_overflow_error<T>(
function, 0, pol);
result_type a = abs(result_type(x));
if(a > result_type(0.95f))
return log(1 + result_type(x)) - result_type(x);
// Note that without numeric_limits specialisation support,
// epsilon just returns zero, and our "optimisation" will always fail:
if(a < tools::epsilon<result_type>())
return -x * x / 2;
boost::math::detail::log1p_series<T> s(x);
s();
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, policies::get_epsilon<T, Policy>(), max_iter, zero);
#else
T result = boost::math::tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter);
#endif
policies::check_series_iterations<T>(function, max_iter, pol);
return result;
}
template <class T>
inline typename tools::promote_args<T>::type log1pmx(T x)
{
return log1pmx(x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_LOG1P_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,70 @@
// Copyright John Maddock 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_MODF_HPP
#define BOOST_MATH_MODF_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/trunc.hpp>
namespace boost{ namespace math{
template <class T, class Policy>
inline T modf(const T& v, T* ipart, const Policy& pol)
{
*ipart = trunc(v, pol);
return v - *ipart;
}
template <class T>
inline T modf(const T& v, T* ipart)
{
return modf(v, ipart, policies::policy<>());
}
template <class T, class Policy>
inline T modf(const T& v, int* ipart, const Policy& pol)
{
*ipart = itrunc(v, pol);
return v - *ipart;
}
template <class T>
inline T modf(const T& v, int* ipart)
{
return modf(v, ipart, policies::policy<>());
}
template <class T, class Policy>
inline T modf(const T& v, long* ipart, const Policy& pol)
{
*ipart = ltrunc(v, pol);
return v - *ipart;
}
template <class T>
inline T modf(const T& v, long* ipart)
{
return modf(v, ipart, policies::policy<>());
}
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
inline T modf(const T& v, boost::long_long_type* ipart, const Policy& pol)
{
*ipart = lltrunc(v, pol);
return v - *ipart;
}
template <class T>
inline T modf(const T& v, boost::long_long_type* ipart)
{
return modf(v, ipart, policies::policy<>());
}
#endif
}} // namespaces
#endif // BOOST_MATH_MODF_HPP

View File

@@ -0,0 +1,320 @@
// (C) 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_NEXT_HPP
#define BOOST_MATH_SPECIAL_NEXT_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <boost/math/special_functions/trunc.hpp>
#ifdef BOOST_MSVC
#include <float.h>
#endif
namespace boost{ namespace math{
namespace detail{
template <class T>
inline T get_smallest_value(mpl::true_ const&)
{
return std::numeric_limits<T>::denorm_min();
}
template <class T>
inline T get_smallest_value(mpl::false_ const&)
{
return tools::min_value<T>();
}
template <class T>
inline T get_smallest_value()
{
#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)
return get_smallest_value<T>(mpl::bool_<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == 1)>());
#else
return get_smallest_value<T>(mpl::bool_<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present)>());
#endif
}
}
template <class T, class Policy>
T float_next(const T& val, const Policy& pol)
{
BOOST_MATH_STD_USING
int expon;
static const char* function = "float_next<%1%>(%1%)";
if(!(boost::math::isfinite)(val))
{
if(val < 0)
return -tools::max_value<T>();
return policies::raise_domain_error<T>(
function,
"Argument must be finite, but got %1%", val, pol);
}
if(val >= tools::max_value<T>())
return policies::raise_overflow_error<T>(function, 0, pol);
if(val == 0)
return detail::get_smallest_value<T>();
if(-0.5f == frexp(val, &expon))
--expon; // reduce exponent when val is a power of two, and negative.
T diff = ldexp(T(1), expon - tools::digits<T>());
if(diff == 0)
diff = detail::get_smallest_value<T>();
return val + diff;
}
#ifdef BOOST_MSVC
template <class Policy>
inline double float_next(const double& val, const Policy& pol)
{
static const char* function = "float_next<%1%>(%1%)";
if(!(boost::math::isfinite)(val) && (val > 0))
return policies::raise_domain_error<double>(
function,
"Argument must be finite, but got %1%", val, pol);
if(val >= tools::max_value<double>())
return policies::raise_overflow_error<double>(function, 0, pol);
return ::_nextafter(val, tools::max_value<double>());
}
#endif
template <class T>
inline T float_next(const T& val)
{
return float_next(val, policies::policy<>());
}
template <class T, class Policy>
T float_prior(const T& val, const Policy& pol)
{
BOOST_MATH_STD_USING
int expon;
static const char* function = "float_prior<%1%>(%1%)";
if(!(boost::math::isfinite)(val))
{
if(val > 0)
return tools::max_value<T>();
return policies::raise_domain_error<T>(
function,
"Argument must be finite, but got %1%", val, pol);
}
if(val <= -tools::max_value<T>())
return -policies::raise_overflow_error<T>(function, 0, pol);
if(val == 0)
return -detail::get_smallest_value<T>();
T remain = frexp(val, &expon);
if(remain == 0.5)
--expon; // when val is a power of two we must reduce the exponent
T diff = ldexp(T(1), expon - tools::digits<T>());
if(diff == 0)
diff = detail::get_smallest_value<T>();
return val - diff;
}
#ifdef BOOST_MSVC
template <class Policy>
inline double float_prior(const double& val, const Policy& pol)
{
static const char* function = "float_prior<%1%>(%1%)";
if(!(boost::math::isfinite)(val) && (val < 0))
return policies::raise_domain_error<double>(
function,
"Argument must be finite, but got %1%", val, pol);
if(val <= -tools::max_value<double>())
return -policies::raise_overflow_error<double>(function, 0, pol);
return ::_nextafter(val, -tools::max_value<double>());
}
#endif
template <class T>
inline T float_prior(const T& val)
{
return float_prior(val, policies::policy<>());
}
template <class T, class Policy>
inline T nextafter(const T& val, const T& direction, const Policy& pol)
{
return val < direction ? boost::math::float_next(val, pol) : val == direction ? val : boost::math::float_prior(val, pol);
}
template <class T>
inline T nextafter(const T& val, const T& direction)
{
return nextafter(val, direction, policies::policy<>());
}
template <class T, class Policy>
T float_distance(const T& a, const T& b, const Policy& pol)
{
BOOST_MATH_STD_USING
//
// Error handling:
//
static const char* function = "float_distance<%1%>(%1%, %1%)";
if(!(boost::math::isfinite)(a))
return policies::raise_domain_error<T>(
function,
"Argument a must be finite, but got %1%", a, pol);
if(!(boost::math::isfinite)(b))
return policies::raise_domain_error<T>(
function,
"Argument b must be finite, but got %1%", b, pol);
//
// Special cases:
//
if(a > b)
return -float_distance(b, a);
if(a == b)
return 0;
if(a == 0)
return 1 + fabs(float_distance(static_cast<T>(boost::math::sign(b) * detail::get_smallest_value<T>()), b, pol));
if(b == 0)
return 1 + fabs(float_distance(static_cast<T>(boost::math::sign(a) * detail::get_smallest_value<T>()), a, pol));
if(boost::math::sign(a) != boost::math::sign(b))
return 2 + fabs(float_distance(static_cast<T>(boost::math::sign(b) * detail::get_smallest_value<T>()), b, pol))
+ fabs(float_distance(static_cast<T>(boost::math::sign(a) * detail::get_smallest_value<T>()), a, pol));
//
// By the time we get here, both a and b must have the same sign, we want
// b > a and both postive for the following logic:
//
if(a < 0)
return float_distance(static_cast<T>(-b), static_cast<T>(-a));
BOOST_ASSERT(a >= 0);
BOOST_ASSERT(b >= a);
int expon;
//
// Note that if a is a denorm then the usual formula fails
// because we actually have fewer than tools::digits<T>()
// significant bits in the representation:
//
frexp(((boost::math::fpclassify)(a) == FP_SUBNORMAL) ? tools::min_value<T>() : a, &expon);
T upper = ldexp(T(1), expon);
T result = 0;
expon = tools::digits<T>() - expon;
//
// If b is greater than upper, then we *must* split the calculation
// as the size of the ULP changes with each order of magnitude change:
//
if(b > upper)
{
result = float_distance(upper, b);
}
//
// Use compensated double-double addition to avoid rounding
// errors in the subtraction:
//
T mb = -(std::min)(upper, b);
T x = a + mb;
T z = x - a;
T y = (a - (x - z)) + (mb - z);
if(x < 0)
{
x = -x;
y = -y;
}
result += ldexp(x, expon) + ldexp(y, expon);
//
// Result must be an integer:
//
BOOST_ASSERT(result == floor(result));
return result;
}
template <class T>
T float_distance(const T& a, const T& b)
{
return boost::math::float_distance(a, b, policies::policy<>());
}
template <class T, class Policy>
T float_advance(T val, int distance, const Policy& pol)
{
//
// Error handling:
//
static const char* function = "float_advance<%1%>(%1%, int)";
if(!(boost::math::isfinite)(val))
return policies::raise_domain_error<T>(
function,
"Argument val must be finite, but got %1%", val, pol);
if(val < 0)
return -float_advance(-val, -distance, pol);
if(distance == 0)
return val;
if(distance == 1)
return float_next(val, pol);
if(distance == -1)
return float_prior(val, pol);
BOOST_MATH_STD_USING
int expon;
frexp(val, &expon);
T limit = ldexp((distance < 0 ? T(0.5f) : T(1)), expon);
if(val <= tools::min_value<T>())
{
limit = sign(T(distance)) * tools::min_value<T>();
}
T limit_distance = float_distance(val, limit);
while(fabs(limit_distance) < abs(distance))
{
distance -= itrunc(limit_distance);
val = limit;
if(distance < 0)
{
limit /= 2;
expon--;
}
else
{
limit *= 2;
expon++;
}
limit_distance = float_distance(val, limit);
}
if((0.5f == frexp(val, &expon)) && (distance < 0))
--expon;
T diff = 0;
if(val != 0)
diff = distance * ldexp(T(1), expon - tools::digits<T>());
if(diff == 0)
diff = distance * detail::get_smallest_value<T>();
return val += diff;
}
template <class T>
inline T float_advance(const T& val, int distance)
{
return boost::math::float_advance(val, distance, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_SPECIAL_NEXT_HPP

View File

@@ -0,0 +1,543 @@
#ifndef BOOST_MATH_NONFINITE_NUM_FACETS_HPP
#define BOOST_MATH_NONFINITE_NUM_FACETS_HPP
// Copyright (c) 2006 Johan Rade
// Copyright 2011 Paul A. Bristow (comments)
// 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)
/*
\file
\brief non_finite_num facets for C99 standard output of infinity and NaN.
\details See fuller documentation at Boost.Math Facets
for Floating-Point Infinities and NaNs.
*/
#include <cstring>
#include <ios>
#include <limits>
#include <locale>
#include <boost/version.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/special_functions/sign.hpp>
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable : 4127) // conditional expression is constant.
# pragma warning(disable : 4706) // assignment within conditional expression.
# pragma warning(disable : 4224) // formal parameter 'version' was previously defined as a type.
#endif
namespace boost {
namespace math {
// flags (enums can be ORed together) -----------------------------------
const int legacy = 0x1; //!< get facet will recognize most string representations of infinity and NaN.
const int signed_zero = 0x2; //!< put facet will distinguish between positive and negative zero.
const int trap_infinity = 0x4; /*!< put facet will throw an exception of type std::ios_base::failure
when an attempt is made to format positive or negative infinity.
get will set the fail bit of the stream when an attempt is made
to parse a string that represents positive or negative sign infinity.
*/
const int trap_nan = 0x8; /*!< put facet will throw an exception of type std::ios_base::failure
when an attempt is made to format positive or negative NaN.
get will set the fail bit of the stream when an attempt is made
to parse a string that represents positive or negative sign infinity.
*/
// class nonfinite_num_put -----------------------------------------------------
template<
class CharType,
class OutputIterator = std::ostreambuf_iterator<CharType>
>
class nonfinite_num_put : public std::num_put<CharType, OutputIterator>
{
public:
explicit nonfinite_num_put(int flags = 0) : flags_(flags) {}
protected:
virtual OutputIterator do_put(
OutputIterator it, std::ios_base& iosb,
CharType fill, double val) const
{
put_and_reset_width(it, iosb, fill, val);
return it;
}
virtual OutputIterator do_put(
OutputIterator it, std::ios_base& iosb,
CharType fill, long double val) const
{
put_and_reset_width(it, iosb, fill, val);
return it;
}
private:
template<class ValType> void put_and_reset_width(
OutputIterator& it, std::ios_base& iosb,
CharType fill, ValType val) const
{
put_impl(it, iosb, fill, val);
iosb.width(0);
}
template<class ValType> void put_impl(
OutputIterator& it, std::ios_base& iosb,
CharType fill, ValType val) const
{
switch((boost::math::fpclassify)(val)) {
case FP_INFINITE:
if(flags_ & trap_infinity)
throw std::ios_base::failure("Infinity");
else if((boost::math::signbit)(val))
put_num_and_fill(it, iosb, "-", "inf", fill);
else if(iosb.flags() & std::ios_base::showpos)
put_num_and_fill(it, iosb, "+", "inf", fill);
else
put_num_and_fill(it, iosb, "", "inf", fill);
break;
case FP_NAN:
if(flags_ & trap_nan)
throw std::ios_base::failure("NaN");
else if((boost::math::signbit)(val))
put_num_and_fill(it, iosb, "-", "nan", fill);
else if(iosb.flags() & std::ios_base::showpos)
put_num_and_fill(it, iosb, "+", "nan", fill);
else
put_num_and_fill(it, iosb, "", "nan", fill);
break;
case FP_ZERO:
if(flags_ & signed_zero) {
if((boost::math::signbit)(val))
put_num_and_fill(it, iosb, "-", "0", fill);
else if(iosb.flags() & std::ios_base::showpos)
put_num_and_fill(it, iosb, "+", "0", fill);
else
put_num_and_fill(it, iosb, "", "0", fill);
}
else
put_num_and_fill(it, iosb, "", "0", fill);
break;
default:
it = std::num_put<CharType, OutputIterator>::do_put(
it, iosb, fill, val);
break;
}
}
void put_num_and_fill(
OutputIterator& it, std::ios_base& iosb, const char* prefix,
const char* body, CharType fill) const
{
int width = (int)std::strlen(prefix) + (int)std::strlen(body);
std::ios_base::fmtflags adjust
= iosb.flags() & std::ios_base::adjustfield;
const std::ctype<CharType>& ct
= std::use_facet<std::ctype<CharType> >(iosb.getloc());
if(adjust != std::ios_base::internal && adjust != std::ios_base::left)
put_fill(it, iosb, fill, width);
while(*prefix)
*it = ct.widen(*(prefix++));
if(adjust == std::ios_base::internal)
put_fill(it, iosb, fill, width);
if(iosb.flags() & std::ios_base::uppercase) {
while(*body)
*it = ct.toupper(ct.widen(*(body++)));
}
else {
while(*body)
*it = ct.widen(*(body++));
}
if(adjust == std::ios_base::left)
put_fill(it, iosb, fill, width);
}
void put_fill(
OutputIterator& it, std::ios_base& iosb,
CharType fill, int width) const
{
for(std::streamsize i = iosb.width() - static_cast<std::streamsize>(width); i > 0; --i)
*it = fill;
}
private:
const int flags_;
};
// class nonfinite_num_get ------------------------------------------------------
template<
class CharType,
class InputIterator = std::istreambuf_iterator<CharType>
>
class nonfinite_num_get : public std::num_get<CharType, InputIterator>
{
public:
explicit nonfinite_num_get(int flags = 0) : flags_(flags)
{}
protected: // float, double and long double versions of do_get.
virtual InputIterator do_get(
InputIterator it, InputIterator end, std::ios_base& iosb,
std::ios_base::iostate& state, float& val) const
{
get_and_check_eof(it, end, iosb, state, val);
return it;
}
virtual InputIterator do_get(
InputIterator it, InputIterator end, std::ios_base& iosb,
std::ios_base::iostate& state, double& val) const
{
get_and_check_eof(it, end, iosb, state, val);
return it;
}
virtual InputIterator do_get(
InputIterator it, InputIterator end, std::ios_base& iosb,
std::ios_base::iostate& state, long double& val) const
{
get_and_check_eof(it, end, iosb, state, val);
return it;
}
//..............................................................................
private:
template<class ValType> static ValType positive_nan()
{
// On some platforms quiet_NaN() may be negative.
return (boost::math::copysign)(
std::numeric_limits<ValType>::quiet_NaN(), static_cast<ValType>(1)
);
// static_cast<ValType>(1) added Paul A. Bristow 5 Apr 11
}
template<class ValType> void get_and_check_eof
(
InputIterator& it, InputIterator end, std::ios_base& iosb,
std::ios_base::iostate& state, ValType& val
) const
{
get_signed(it, end, iosb, state, val);
if(it == end)
state |= std::ios_base::eofbit;
}
template<class ValType> void get_signed
(
InputIterator& it, InputIterator end, std::ios_base& iosb,
std::ios_base::iostate& state, ValType& val
) const
{
const std::ctype<CharType>& ct
= std::use_facet<std::ctype<CharType> >(iosb.getloc());
char c = peek_char(it, end, ct);
bool negative = (c == '-');
if(negative || c == '+')
{
++it;
c = peek_char(it, end, ct);
if(c == '-' || c == '+')
{ // Without this check, "++5" etc would be accepted.
state |= std::ios_base::failbit;
return;
}
}
get_unsigned(it, end, iosb, ct, state, val);
if(negative)
{
val = (boost::math::changesign)(val);
}
} // void get_signed
template<class ValType> void get_unsigned
( //! Get an unsigned floating-point value into val,
//! but checking for letters indicating non-finites.
InputIterator& it, InputIterator end, std::ios_base& iosb,
const std::ctype<CharType>& ct,
std::ios_base::iostate& state, ValType& val
) const
{
switch(peek_char(it, end, ct))
{
case 'i':
get_i(it, end, ct, state, val);
break;
case 'n':
get_n(it, end, ct, state, val);
break;
case 'q':
case 's':
get_q(it, end, ct, state, val);
break;
default: // Got a normal floating-point value into val.
it = std::num_get<CharType, InputIterator>::do_get(
it, end, iosb, state, val);
if((flags_ & legacy) && val == static_cast<ValType>(1)
&& peek_char(it, end, ct) == '#')
get_one_hash(it, end, ct, state, val);
break;
}
} // get_unsigned
//..........................................................................
template<class ValType> void get_i
( // Get the rest of all strings starting with 'i', expect "inf", "infinity".
InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
std::ios_base::iostate& state, ValType& val
) const
{
if(!std::numeric_limits<ValType>::has_infinity
|| (flags_ & trap_infinity))
{
state |= std::ios_base::failbit;
return;
}
++it;
if(!match_string(it, end, ct, "nf"))
{
state |= std::ios_base::failbit;
return;
}
if(peek_char(it, end, ct) != 'i')
{
val = std::numeric_limits<ValType>::infinity(); // "inf"
return;
}
++it;
if(!match_string(it, end, ct, "nity"))
{ // Expected "infinity"
state |= std::ios_base::failbit;
return;
}
val = std::numeric_limits<ValType>::infinity(); // "infinity"
} // void get_i
template<class ValType> void get_n
( // Get expected strings after 'n', "nan", "nanq", "nans", "nan(...)"
InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
std::ios_base::iostate& state, ValType& val
) const
{
if(!std::numeric_limits<ValType>::has_quiet_NaN
|| (flags_ & trap_nan)) {
state |= std::ios_base::failbit;
return;
}
++it;
if(!match_string(it, end, ct, "an"))
{
state |= std::ios_base::failbit;
return;
}
switch(peek_char(it, end, ct)) {
case 'q':
case 's':
if(flags_ && legacy)
++it;
break; // "nanq", "nans"
case '(': // Optional payload field in (...) follows.
{
++it;
char c;
while((c = peek_char(it, end, ct))
&& c != ')' && c != ' ' && c != '\n' && c != '\t')
++it;
if(c != ')')
{ // Optional payload field terminator missing!
state |= std::ios_base::failbit;
return;
}
++it;
break; // "nan(...)"
}
default:
break; // "nan"
}
val = positive_nan<ValType>();
} // void get_n
template<class ValType> void get_q
( // Get expected rest of string starting with 'q': "qnan".
InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
std::ios_base::iostate& state, ValType& val
) const
{
if(!std::numeric_limits<ValType>::has_quiet_NaN
|| (flags_ & trap_nan) || !(flags_ & legacy))
{
state |= std::ios_base::failbit;
return;
}
++it;
if(!match_string(it, end, ct, "nan"))
{
state |= std::ios_base::failbit;
return;
}
val = positive_nan<ValType>(); // "QNAN"
} // void get_q
template<class ValType> void get_one_hash
( // Get expected string after having read "1.#": "1.#IND", "1.#QNAN", "1.#SNAN".
InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
std::ios_base::iostate& state, ValType& val
) const
{
++it;
switch(peek_char(it, end, ct))
{
case 'i': // from IND (indeterminate), considered same a QNAN.
get_one_hash_i(it, end, ct, state, val); // "1.#IND"
return;
case 'q': // from QNAN
case 's': // from SNAN - treated the same as QNAN.
if(std::numeric_limits<ValType>::has_quiet_NaN
&& !(flags_ & trap_nan))
{
++it;
if(match_string(it, end, ct, "nan"))
{ // "1.#QNAN", "1.#SNAN"
// ++it; // removed as caused assert() cannot increment iterator).
// (match_string consumes string, so not needed?).
// https://svn.boost.org/trac/boost/ticket/5467
// Change in nonfinite_num_facet.hpp Paul A. Bristow 11 Apr 11 makes legacy_test.cpp work OK.
val = positive_nan<ValType>(); // "1.#QNAN"
return;
}
}
break;
default:
break;
}
state |= std::ios_base::failbit;
} // void get_one_hash
template<class ValType> void get_one_hash_i
( // Get expected strings after 'i', "1.#INF", 1.#IND".
InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
std::ios_base::iostate& state, ValType& val
) const
{
++it;
if(peek_char(it, end, ct) == 'n')
{
++it;
switch(peek_char(it, end, ct))
{
case 'f': // "1.#INF"
if(std::numeric_limits<ValType>::has_infinity
&& !(flags_ & trap_infinity))
{
++it;
val = std::numeric_limits<ValType>::infinity();
return;
}
break;
case 'd': // 1.#IND"
if(std::numeric_limits<ValType>::has_quiet_NaN
&& !(flags_ & trap_nan))
{
++it;
val = positive_nan<ValType>();
return;
}
break;
default:
break;
}
}
state |= std::ios_base::failbit;
} // void get_one_hash_i
//..........................................................................
char peek_char
( //! \return next char in the input buffer, ensuring lowercase (but do not 'consume' char).
InputIterator& it, InputIterator end,
const std::ctype<CharType>& ct
) const
{
if(it == end) return 0;
return ct.narrow(ct.tolower(*it), 0); // Always tolower to ensure case insensitive.
}
bool match_string
( //! Match remaining chars to expected string (case insensitive),
//! consuming chars that match OK.
//! \return true if matched expected string, else false.
InputIterator& it, InputIterator end,
const std::ctype<CharType>& ct,
const char* s
) const
{
while(it != end && *s && *s == ct.narrow(ct.tolower(*it), 0))
{
++s;
++it; //
}
return !*s;
} // bool match_string
private:
const int flags_;
}; //
//------------------------------------------------------------------------------
} // namespace math
} // namespace boost
#ifdef _MSC_VER
# pragma warning(pop)
#endif
#endif

View File

@@ -0,0 +1,140 @@
// Boost pow.hpp header file
// Computes a power with exponent known at compile-time
// (C) Copyright Bruno Lalande 2008.
// 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)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_MATH_POW_HPP
#define BOOST_MATH_POW_HPP
#include <boost/math/policies/policy.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/mpl/greater_equal.hpp>
namespace boost {
namespace math {
namespace detail {
template <int N, int M = N%2>
struct positive_power
{
template <typename T>
static T result(T base)
{
T power = positive_power<N/2>::result(base);
return power * power;
}
};
template <int N>
struct positive_power<N, 1>
{
template <typename T>
static T result(T base)
{
T power = positive_power<N/2>::result(base);
return base * power * power;
}
};
template <>
struct positive_power<1, 1>
{
template <typename T>
static T result(T base){ return base; }
};
template <int N, bool>
struct power_if_positive
{
template <typename T, class Policy>
static T result(T base, const Policy&)
{ return positive_power<N>::result(base); }
};
template <int N>
struct power_if_positive<N, false>
{
template <typename T, class Policy>
static T result(T base, const Policy& policy)
{
if (base == 0)
{
return policies::raise_overflow_error<T>(
"boost::math::pow(%1%)",
"Attempted to compute a negative power of 0",
policy
);
}
return T(1) / positive_power<-N>::result(base);
}
};
template <>
struct power_if_positive<0, true>
{
template <typename T, class Policy>
static T result(T base, const Policy& policy)
{
if (base == 0)
{
return policies::raise_indeterminate_result_error<T>(
"boost::math::pow(%1%)",
"The result of pow<0>(%1%) is undetermined",
base,
T(1),
policy
);
}
return T(1);
}
};
template <int N>
struct select_power_if_positive
{
typedef typename mpl::greater_equal<
mpl::int_<N>,
mpl::int_<0>
>::type is_positive;
typedef power_if_positive<N, is_positive::value> type;
};
} // namespace detail
template <int N, typename T, class Policy>
inline typename tools::promote_args<T>::type pow(T base, const Policy& policy)
{
typedef typename tools::promote_args<T>::type result_type;
return detail::select_power_if_positive<N>::type::result(static_cast<result_type>(base), policy);
}
template <int N, typename T>
inline typename tools::promote_args<T>::type pow(T base)
{ return pow<N>(base, policies::policy<>()); }
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,61 @@
// (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_POWM1
#define BOOST_MATH_POWM1
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/assert.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
inline T powm1_imp(const T a, const T z, const Policy& pol)
{
BOOST_MATH_STD_USING
if((fabs(a) < 1) || (fabs(z) < 1))
{
T p = log(a) * z;
if(fabs(p) < 2)
return boost::math::expm1(p, pol);
// otherwise fall though:
}
return pow(a, z) - 1;
}
} // detail
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
powm1(const T1 a, const T2 z)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
return detail::powm1_imp(static_cast<result_type>(a), static_cast<result_type>(z), policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
powm1(const T1 a, const T2 z, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
return detail::powm1_imp(static_cast<result_type>(a), static_cast<result_type>(z), pol);
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_POWM1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,92 @@
// Copyright John Maddock 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_ROUND_HPP
#define BOOST_MATH_ROUND_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
namespace boost{ namespace math{
template <class T, class Policy>
inline T round(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
if(!(boost::math::isfinite)(v))
return policies::raise_rounding_error("boost::math::round<%1%>(%1%)", 0, v, v, pol);
return v < 0 ? static_cast<T>(ceil(v - 0.5f)) : static_cast<T>(floor(v + 0.5f));
}
template <class T>
inline T round(const T& v)
{
return round(v, policies::policy<>());
}
//
// The following functions will not compile unless T has an
// implicit convertion to the integer types. For user-defined
// number types this will likely not be the case. In that case
// these functions should either be specialized for the UDT in
// question, or else overloads should be placed in the same
// namespace as the UDT: these will then be found via argument
// dependent lookup. See our concept archetypes for examples.
//
template <class T, class Policy>
inline int iround(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
T r = boost::math::round(v, pol);
if((r > (std::numeric_limits<int>::max)()) || (r < (std::numeric_limits<int>::min)()))
return static_cast<int>(policies::raise_rounding_error("boost::math::iround<%1%>(%1%)", 0, v, 0, pol));
return static_cast<int>(r);
}
template <class T>
inline int iround(const T& v)
{
return iround(v, policies::policy<>());
}
template <class T, class Policy>
inline long lround(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
T r = boost::math::round(v, pol);
if((r > (std::numeric_limits<long>::max)()) || (r < (std::numeric_limits<long>::min)()))
return static_cast<long int>(policies::raise_rounding_error("boost::math::lround<%1%>(%1%)", 0, v, 0L, pol));
return static_cast<long int>(r);
}
template <class T>
inline long lround(const T& v)
{
return lround(v, policies::policy<>());
}
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
inline boost::long_long_type llround(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
T r = boost::math::round(v, pol);
if((r > (std::numeric_limits<boost::long_long_type>::max)()) || (r < (std::numeric_limits<boost::long_long_type>::min)()))
return static_cast<boost::long_long_type>(policies::raise_rounding_error("boost::math::llround<%1%>(%1%)", 0, v, 0LL, pol));
return static_cast<boost::long_long_type>(r);
}
template <class T>
inline boost::long_long_type llround(const T& v)
{
return llround(v, policies::policy<>());
}
#endif
}} // namespaces
#endif // BOOST_MATH_ROUND_HPP

View File

@@ -0,0 +1,145 @@
// (C) Copyright John Maddock 2006.
// (C) Copyright Johan Rade 2006.
// (C) Copyright Paul A. Bristow 2011 (added changesign).
// 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_TOOLS_SIGN_HPP
#define BOOST_MATH_TOOLS_SIGN_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/detail/fp_traits.hpp>
namespace boost{ namespace math{
namespace detail {
// signbit
#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
template<class T>
inline int signbit_impl(T x, native_tag const&)
{
return (std::signbit)(x);
}
#endif
template<class T>
inline int signbit_impl(T x, generic_tag<true> const&)
{
return x < 0;
}
template<class T>
inline int signbit_impl(T x, generic_tag<false> const&)
{
return x < 0;
}
template<class T>
inline int signbit_impl(T x, ieee_copy_all_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
return a & traits::sign ? 1 : 0;
}
template<class T>
inline int signbit_impl(T x, ieee_copy_leading_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
return a & traits::sign ? 1 : 0;
}
// Changesign
template<class T>
inline T (changesign_impl)(T x, generic_tag<true> const&)
{
return -x;
}
template<class T>
inline T (changesign_impl)(T x, generic_tag<false> const&)
{
return -x;
}
template<class T>
inline T changesign_impl(T x, ieee_copy_all_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::sign_change_type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a ^= traits::sign;
traits::set_bits(x,a);
return x;
}
template<class T>
inline T (changesign_impl)(T x, ieee_copy_leading_bits_tag const&)
{
typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::sign_change_type traits;
BOOST_DEDUCED_TYPENAME traits::bits a;
traits::get_bits(x,a);
a ^= traits::sign;
traits::set_bits(x,a);
return x;
}
} // namespace detail
template<class T> int (signbit)(T x)
{
typedef typename detail::fp_traits<T>::type traits;
typedef typename traits::method method;
typedef typename boost::is_floating_point<T>::type fp_tag;
return detail::signbit_impl(x, method());
}
template <class T>
inline int sign BOOST_NO_MACRO_EXPAND(const T& z)
{
return (z == 0) ? 0 : (boost::math::signbit)(z) ? -1 : 1;
}
template<class T> T (changesign)(const T& x)
{ //!< \brief return unchanged binary pattern of x, except for change of sign bit.
typedef typename detail::fp_traits<T>::sign_change_type traits;
typedef typename traits::method method;
typedef typename boost::is_floating_point<T>::type fp_tag;
return detail::changesign_impl(x, method());
}
template <class T>
inline T copysign BOOST_NO_MACRO_EXPAND(const T& x, const T& y)
{
BOOST_MATH_STD_USING
return (boost::math::signbit)(x) != (boost::math::signbit)(y) ? (boost::math::changesign)(x) : x;
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_TOOLS_SIGN_HPP

View File

@@ -0,0 +1,70 @@
// 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)
#ifndef BOOST_MATH_SIN_PI_HPP
#define BOOST_MATH_SIN_PI_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/constants/constants.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
T sin_pi_imp(T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
if(x < 0)
return -sin_pi(-x);
// sin of pi*x:
bool invert;
if(x < 0.5)
return sin(constants::pi<T>() * x);
if(x < 1)
{
invert = true;
x = -x;
}
else
invert = false;
T rem = floor(x);
if(itrunc(rem, pol) & 1)
invert = !invert;
rem = x - rem;
if(rem > 0.5f)
rem = 1 - rem;
if(rem == 0.5f)
return static_cast<T>(invert ? -1 : 1);
rem = sin(constants::pi<T>() * rem);
return invert ? T(-rem) : rem;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type sin_pi(T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
return boost::math::detail::sin_pi_imp<result_type>(x, pol);
}
template <class T>
inline typename tools::promote_args<T>::type sin_pi(T x)
{
return boost::math::sin_pi(x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,177 @@
// boost sinc.hpp header file
// (C) Copyright Hubert Holin 2001.
// 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)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_SINC_HPP
#define BOOST_SINC_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/policy.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/limits.hpp>
#include <string>
#include <stdexcept>
#include <boost/config.hpp>
// These are the the "Sinus Cardinal" functions.
namespace boost
{
namespace math
{
namespace detail
{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::sin;
using ::std::numeric_limits;
#endif /* defined(__GNUC__) && (__GNUC__ < 3) */
// This is the "Sinus Cardinal" of index Pi.
template<typename T>
inline T sinc_pi_imp(const T x)
{
#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
using ::abs;
using ::sin;
using ::sqrt;
#else /* BOOST_NO_STDC_NAMESPACE */
using ::std::abs;
using ::std::sin;
using ::std::sqrt;
#endif /* BOOST_NO_STDC_NAMESPACE */
// Note: this code is *not* thread safe!
static T const taylor_0_bound = tools::epsilon<T>();
static T const taylor_2_bound = sqrt(taylor_0_bound);
static T const taylor_n_bound = sqrt(taylor_2_bound);
if (abs(x) >= taylor_n_bound)
{
return(sin(x)/x);
}
else
{
// approximation by taylor series in x at 0 up to order 0
T result = static_cast<T>(1);
if (abs(x) >= taylor_0_bound)
{
T x2 = x*x;
// approximation by taylor series in x at 0 up to order 2
result -= x2/static_cast<T>(6);
if (abs(x) >= taylor_2_bound)
{
// approximation by taylor series in x at 0 up to order 4
result += (x2*x2)/static_cast<T>(120);
}
}
return(result);
}
}
} // namespace detail
template <class T>
inline typename tools::promote_args<T>::type sinc_pi(T x)
{
typedef typename tools::promote_args<T>::type result_type;
return detail::sinc_pi_imp(static_cast<result_type>(x));
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type sinc_pi(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
return detail::sinc_pi_imp(static_cast<result_type>(x));
}
#ifdef BOOST_NO_TEMPLATE_TEMPLATES
#else /* BOOST_NO_TEMPLATE_TEMPLATES */
template<typename T, template<typename> class U>
inline U<T> sinc_pi(const U<T> x)
{
#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL) || defined(__GNUC__)
using namespace std;
#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
using ::abs;
using ::sin;
using ::sqrt;
#else /* BOOST_NO_STDC_NAMESPACE */
using ::std::abs;
using ::std::sin;
using ::std::sqrt;
#endif /* BOOST_NO_STDC_NAMESPACE */
using ::std::numeric_limits;
static T const taylor_0_bound = tools::epsilon<T>();
static T const taylor_2_bound = sqrt(taylor_0_bound);
static T const taylor_n_bound = sqrt(taylor_2_bound);
if (abs(x) >= taylor_n_bound)
{
return(sin(x)/x);
}
else
{
// approximation by taylor series in x at 0 up to order 0
#ifdef __MWERKS__
U<T> result = static_cast<U<T> >(1);
#else
U<T> result = U<T>(1);
#endif
if (abs(x) >= taylor_0_bound)
{
U<T> x2 = x*x;
// approximation by taylor series in x at 0 up to order 2
result -= x2/static_cast<T>(6);
if (abs(x) >= taylor_2_bound)
{
// approximation by taylor series in x at 0 up to order 4
result += (x2*x2)/static_cast<T>(120);
}
}
return(result);
}
}
template<typename T, template<typename> class U, class Policy>
inline U<T> sinc_pi(const U<T> x, const Policy&)
{
return sinc_pi(x);
}
#endif /* BOOST_NO_TEMPLATE_TEMPLATES */
}
}
#endif /* BOOST_SINC_HPP */

View File

@@ -0,0 +1,167 @@
// boost sinhc.hpp header file
// (C) Copyright Hubert Holin 2001.
// 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)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_SINHC_HPP
#define BOOST_SINHC_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/limits.hpp>
#include <string>
#include <stdexcept>
#include <boost/config.hpp>
// These are the the "Hyperbolic Sinus Cardinal" functions.
namespace boost
{
namespace math
{
namespace detail
{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::sinh;
using ::std::numeric_limits;
#endif /* defined(__GNUC__) && (__GNUC__ < 3) */
// This is the "Hyperbolic Sinus Cardinal" of index Pi.
template<typename T>
inline T sinhc_pi_imp(const T x)
{
#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
using ::abs;
using ::sinh;
using ::sqrt;
#else /* BOOST_NO_STDC_NAMESPACE */
using ::std::abs;
using ::std::sinh;
using ::std::sqrt;
#endif /* BOOST_NO_STDC_NAMESPACE */
static T const taylor_0_bound = tools::epsilon<T>();
static T const taylor_2_bound = sqrt(taylor_0_bound);
static T const taylor_n_bound = sqrt(taylor_2_bound);
if (abs(x) >= taylor_n_bound)
{
return(sinh(x)/x);
}
else
{
// approximation by taylor series in x at 0 up to order 0
T result = static_cast<T>(1);
if (abs(x) >= taylor_0_bound)
{
T x2 = x*x;
// approximation by taylor series in x at 0 up to order 2
result += x2/static_cast<T>(6);
if (abs(x) >= taylor_2_bound)
{
// approximation by taylor series in x at 0 up to order 4
result += (x2*x2)/static_cast<T>(120);
}
}
return(result);
}
}
} // namespace detail
template <class T>
inline typename tools::promote_args<T>::type sinhc_pi(T x)
{
typedef typename tools::promote_args<T>::type result_type;
return detail::sinhc_pi_imp(static_cast<result_type>(x));
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type sinhc_pi(T x, const Policy&)
{
return boost::math::sinhc_pi(x);
}
#ifdef BOOST_NO_TEMPLATE_TEMPLATES
#else /* BOOST_NO_TEMPLATE_TEMPLATES */
template<typename T, template<typename> class U>
inline U<T> sinhc_pi(const U<T> x)
{
#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL) || defined(__GNUC__)
using namespace std;
#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
using ::abs;
using ::sinh;
using ::sqrt;
#else /* BOOST_NO_STDC_NAMESPACE */
using ::std::abs;
using ::std::sinh;
using ::std::sqrt;
#endif /* BOOST_NO_STDC_NAMESPACE */
using ::std::numeric_limits;
static T const taylor_0_bound = tools::epsilon<T>();
static T const taylor_2_bound = sqrt(taylor_0_bound);
static T const taylor_n_bound = sqrt(taylor_2_bound);
if (abs(x) >= taylor_n_bound)
{
return(sinh(x)/x);
}
else
{
// approximation by taylor series in x at 0 up to order 0
#ifdef __MWERKS__
U<T> result = static_cast<U<T> >(1);
#else
U<T> result = U<T>(1);
#endif
if (abs(x) >= taylor_0_bound)
{
U<T> x2 = x*x;
// approximation by taylor series in x at 0 up to order 2
result += x2/static_cast<T>(6);
if (abs(x) >= taylor_2_bound)
{
// approximation by taylor series in x at 0 up to order 4
result += (x2*x2)/static_cast<T>(120);
}
}
return(result);
}
}
#endif /* BOOST_NO_TEMPLATE_TEMPLATES */
}
}
#endif /* BOOST_SINHC_HPP */

View File

@@ -0,0 +1,204 @@
// (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_SPHERICAL_HARMONIC_HPP
#define BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/legendre.hpp>
#include <boost/math/tools/workaround.hpp>
#include <complex>
namespace boost{
namespace math{
namespace detail{
//
// Calculates the prefix term that's common to the real
// and imaginary parts. Does *not* fix up the sign of the result
// though.
//
template <class T, class Policy>
inline T spherical_harmonic_prefix(unsigned n, unsigned m, T theta, const Policy& pol)
{
BOOST_MATH_STD_USING
if(m > n)
return 0;
T sin_theta = sin(theta);
T x = cos(theta);
T leg = detail::legendre_p_imp(n, m, x, static_cast<T>(pow(fabs(sin_theta), T(m))), pol);
T prefix = boost::math::tgamma_delta_ratio(static_cast<T>(n - m + 1), static_cast<T>(2 * m), pol);
prefix *= (2 * n + 1) / (4 * constants::pi<T>());
prefix = sqrt(prefix);
return prefix * leg;
}
//
// Real Part:
//
template <class T, class Policy>
T spherical_harmonic_r(unsigned n, int m, T theta, T phi, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std functions
bool sign = false;
if(m < 0)
{
// Reflect and adjust sign if m < 0:
sign = m&1;
m = abs(m);
}
if(m&1)
{
// Check phase if theta is outside [0, PI]:
T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
if(mod < 0)
mod += 2 * constants::pi<T>();
if(mod > constants::pi<T>())
sign = !sign;
}
// Get the value and adjust sign as required:
T prefix = spherical_harmonic_prefix(n, m, theta, pol);
prefix *= cos(m * phi);
return sign ? T(-prefix) : prefix;
}
template <class T, class Policy>
T spherical_harmonic_i(unsigned n, int m, T theta, T phi, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std functions
bool sign = false;
if(m < 0)
{
// Reflect and adjust sign if m < 0:
sign = !(m&1);
m = abs(m);
}
if(m&1)
{
// Check phase if theta is outside [0, PI]:
T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
if(mod < 0)
mod += 2 * constants::pi<T>();
if(mod > constants::pi<T>())
sign = !sign;
}
// Get the value and adjust sign as required:
T prefix = spherical_harmonic_prefix(n, m, theta, pol);
prefix *= sin(m * phi);
return sign ? T(-prefix) : prefix;
}
template <class T, class U, class Policy>
std::complex<T> spherical_harmonic(unsigned n, int m, U theta, U phi, const Policy& pol)
{
BOOST_MATH_STD_USING
//
// Sort out the signs:
//
bool r_sign = false;
bool i_sign = false;
if(m < 0)
{
// Reflect and adjust sign if m < 0:
r_sign = m&1;
i_sign = !(m&1);
m = abs(m);
}
if(m&1)
{
// Check phase if theta is outside [0, PI]:
U mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi<U>());
if(mod < 0)
mod += 2 * constants::pi<U>();
if(mod > constants::pi<U>())
{
r_sign = !r_sign;
i_sign = !i_sign;
}
}
//
// Calculate the value:
//
U prefix = spherical_harmonic_prefix(n, m, theta, pol);
U r = prefix * cos(m * phi);
U i = prefix * sin(m * phi);
//
// Add in the signs:
//
if(r_sign)
r = -r;
if(i_sign)
i = -i;
static const char* function = "boost::math::spherical_harmonic<%1%>(int, int, %1%, %1%)";
return std::complex<T>(policies::checked_narrowing_cast<T, Policy>(r, function), policies::checked_narrowing_cast<T, Policy>(i, function));
}
} // namespace detail
template <class T1, class T2, class Policy>
inline std::complex<typename tools::promote_args<T1, T2>::type>
spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return detail::spherical_harmonic<result_type, value_type>(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol);
}
template <class T1, class T2>
inline std::complex<typename tools::promote_args<T1, T2>::type>
spherical_harmonic(unsigned n, int m, T1 theta, T2 phi)
{
return boost::math::spherical_harmonic(n, m, theta, phi, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_r(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "bost::math::spherical_harmonic_r<%1%>(unsigned, int, %1%, %1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi)
{
return boost::math::spherical_harmonic_r(n, m, theta, phi, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
{
typedef typename tools::promote_args<T1, T2>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_i(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "boost::math::spherical_harmonic_i<%1%>(unsigned, int, %1%, %1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi)
{
return boost::math::spherical_harmonic_i(n, m, theta, phi, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP

View File

@@ -0,0 +1,48 @@
// (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_SQRT1PM1
#define BOOST_MATH_SQRT1PM1
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
//
// This algorithm computes sqrt(1+x)-1 for small x:
//
namespace boost{ namespace math{
template <class T, class Policy>
inline typename tools::promote_args<T>::type sqrt1pm1(const T& val, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
BOOST_MATH_STD_USING
if(fabs(result_type(val)) > 0.75)
return sqrt(1 + result_type(val)) - 1;
return boost::math::expm1(boost::math::log1p(val, pol) / 2, pol);
}
template <class T>
inline typename tools::promote_args<T>::type sqrt1pm1(const T& val)
{
return sqrt1pm1(val, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SQRT1PM1

View File

@@ -0,0 +1,92 @@
// Copyright John Maddock 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_TRUNC_HPP
#define BOOST_MATH_TRUNC_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
namespace boost{ namespace math{
template <class T, class Policy>
inline T trunc(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
if(!(boost::math::isfinite)(v))
return policies::raise_rounding_error("boost::math::trunc<%1%>(%1%)", 0, v, v, pol);
return (v >= 0) ? static_cast<T>(floor(v)) : static_cast<T>(ceil(v));
}
template <class T>
inline T trunc(const T& v)
{
return trunc(v, policies::policy<>());
}
//
// The following functions will not compile unless T has an
// implicit convertion to the integer types. For user-defined
// number types this will likely not be the case. In that case
// these functions should either be specialized for the UDT in
// question, or else overloads should be placed in the same
// namespace as the UDT: these will then be found via argument
// dependent lookup. See our concept archetypes for examples.
//
template <class T, class Policy>
inline int itrunc(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
T r = boost::math::trunc(v, pol);
if((r > (std::numeric_limits<int>::max)()) || (r < (std::numeric_limits<int>::min)()))
return static_cast<int>(policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", 0, v, 0, pol));
return static_cast<int>(r);
}
template <class T>
inline int itrunc(const T& v)
{
return itrunc(v, policies::policy<>());
}
template <class T, class Policy>
inline long ltrunc(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
T r = boost::math::trunc(v, pol);
if((r > (std::numeric_limits<long>::max)()) || (r < (std::numeric_limits<long>::min)()))
return static_cast<long>(policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", 0, v, 0L, pol));
return static_cast<long>(r);
}
template <class T>
inline long ltrunc(const T& v)
{
return ltrunc(v, policies::policy<>());
}
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
inline boost::long_long_type lltrunc(const T& v, const Policy& pol)
{
BOOST_MATH_STD_USING
T r = boost::math::trunc(v, pol);
if((r > (std::numeric_limits<boost::long_long_type>::max)()) || (r < (std::numeric_limits<boost::long_long_type>::min)()))
return static_cast<boost::long_long_type>(policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", 0, v, 0LL, pol));
return static_cast<boost::long_long_type>(r);
}
template <class T>
inline boost::long_long_type lltrunc(const T& v)
{
return lltrunc(v, policies::policy<>());
}
#endif
}} // namespaces
#endif // BOOST_MATH_TRUNC_HPP

View File

@@ -0,0 +1,903 @@
// Copyright John Maddock 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_ZETA_HPP
#define BOOST_MATH_ZETA_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/precision.hpp>
#include <boost/math/tools/series.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
struct zeta_series_cache_size
{
//
// Work how large to make our cache size when evaluating the series
// evaluation: normally this is just large enough for the series
// to have converged, but for arbitrary precision types we need a
// really large cache to achieve reasonable precision in a reasonable
// time. This is important when constructing rational approximations
// to zeta for example.
//
typedef typename boost::math::policies::precision<T,Policy>::type precision_type;
typedef typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<0> >,
mpl::int_<5000>,
typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<64> >,
mpl::int_<70>,
typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<113> >,
mpl::int_<100>,
mpl::int_<5000>
>::type
>::type
>::type type;
};
template <class T, class Policy>
T zeta_series_imp(T s, T sc, const Policy&)
{
//
// Series evaluation from:
// Havil, J. Gamma: Exploring Euler's Constant.
// Princeton, NJ: Princeton University Press, 2003.
//
// See also http://mathworld.wolfram.com/RiemannZetaFunction.html
//
BOOST_MATH_STD_USING
T sum = 0;
T mult = 0.5;
T change;
typedef typename zeta_series_cache_size<T,Policy>::type cache_size;
T powers[cache_size::value] = { 0, };
unsigned n = 0;
do{
T binom = -static_cast<T>(n);
T nested_sum = 1;
if(n < sizeof(powers) / sizeof(powers[0]))
powers[n] = pow(static_cast<T>(n + 1), -s);
for(unsigned k = 1; k <= n; ++k)
{
T p;
if(k < sizeof(powers) / sizeof(powers[0]))
{
p = powers[k];
//p = pow(k + 1, -s);
}
else
p = pow(static_cast<T>(k + 1), -s);
nested_sum += binom * p;
binom *= (k - static_cast<T>(n)) / (k + 1);
}
change = mult * nested_sum;
sum += change;
mult /= 2;
++n;
}while(fabs(change / sum) > tools::epsilon<T>());
return sum * 1 / -boost::math::powm1(T(2), sc);
}
//
// Classical p-series:
//
template <class T>
struct zeta_series2
{
typedef T result_type;
zeta_series2(T _s) : s(-_s), k(1){}
T operator()()
{
BOOST_MATH_STD_USING
return pow(static_cast<T>(k++), s);
}
private:
T s;
unsigned k;
};
template <class T, class Policy>
inline T zeta_series2_imp(T s, const Policy& pol)
{
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();;
zeta_series2<T> f(s);
T result = tools::sum_series(
f,
policies::get_epsilon<T, Policy>(),
max_iter);
policies::check_series_iterations<T>("boost::math::zeta_series2<%1%>(%1%)", max_iter, pol);
return result;
}
template <class T, class Policy>
T zeta_imp_prec(T s, T sc, const Policy& pol, const mpl::int_<0>&)
{
BOOST_MATH_STD_USING
T result;
//
// Only use power series if it will converge in 100
// iterations or less: the more iterations it consumes
// the slower convergence becomes so we have to be very
// careful in it's usage.
//
if (s > -log(tools::epsilon<T>()) / 4.5)
result = detail::zeta_series2_imp(s, pol);
else
result = detail::zeta_series_imp(s, sc, pol);
return result;
}
template <class T, class Policy>
inline T zeta_imp_prec(T s, T sc, const Policy&, const mpl::int_<53>&)
{
BOOST_MATH_STD_USING
T result;
if(s < 1)
{
// Rational Approximation
// Maximum Deviation Found: 2.020e-18
// Expected Error Term: -2.020e-18
// Max error found at double precision: 3.994987e-17
static const T P[6] = {
0.24339294433593750202L,
-0.49092470516353571651L,
0.0557616214776046784287L,
-0.00320912498879085894856L,
0.000451534528645796438704L,
-0.933241270357061460782e-5L,
};
static const T Q[6] = {
1L,
-0.279960334310344432495L,
0.0419676223309986037706L,
-0.00413421406552171059003L,
0.00024978985622317935355L,
-0.101855788418564031874e-4L,
};
result = tools::evaluate_polynomial(P, sc) / tools::evaluate_polynomial(Q, sc);
result -= 1.2433929443359375F;
result += (sc);
result /= (sc);
}
else if(s <= 2)
{
// Maximum Deviation Found: 9.007e-20
// Expected Error Term: 9.007e-20
static const T P[6] = {
0.577215664901532860516,
0.243210646940107164097,
0.0417364673988216497593,
0.00390252087072843288378,
0.000249606367151877175456,
0.110108440976732897969e-4,
};
static const T Q[6] = {
1,
0.295201277126631761737,
0.043460910607305495864,
0.00434930582085826330659,
0.000255784226140488490982,
0.10991819782396112081e-4,
};
result = tools::evaluate_polynomial(P, -sc) / tools::evaluate_polynomial(Q, -sc);
result += 1 / (-sc);
}
else if(s <= 4)
{
// Maximum Deviation Found: 5.946e-22
// Expected Error Term: -5.946e-22
static const float Y = 0.6986598968505859375;
static const T P[6] = {
-0.0537258300023595030676,
0.0445163473292365591906,
0.0128677673534519952905,
0.00097541770457391752726,
0.769875101573654070925e-4,
0.328032510000383084155e-5,
};
static const T Q[7] = {
1,
0.33383194553034051422,
0.0487798431291407621462,
0.00479039708573558490716,
0.000270776703956336357707,
0.106951867532057341359e-4,
0.236276623974978646399e-7,
};
result = tools::evaluate_polynomial(P, s - 2) / tools::evaluate_polynomial(Q, s - 2);
result += Y + 1 / (-sc);
}
else if(s <= 7)
{
// Maximum Deviation Found: 2.955e-17
// Expected Error Term: 2.955e-17
// Max error found at double precision: 2.009135e-16
static const T P[6] = {
-2.49710190602259410021,
-2.60013301809475665334,
-0.939260435377109939261,
-0.138448617995741530935,
-0.00701721240549802377623,
-0.229257310594893932383e-4,
};
static const T Q[9] = {
1,
0.706039025937745133628,
0.15739599649558626358,
0.0106117950976845084417,
-0.36910273311764618902e-4,
0.493409563927590008943e-5,
-0.234055487025287216506e-6,
0.718833729365459760664e-8,
-0.1129200113474947419e-9,
};
result = tools::evaluate_polynomial(P, s - 4) / tools::evaluate_polynomial(Q, s - 4);
result = 1 + exp(result);
}
else if(s < 15)
{
// Maximum Deviation Found: 7.117e-16
// Expected Error Term: 7.117e-16
// Max error found at double precision: 9.387771e-16
static const T P[7] = {
-4.78558028495135619286,
-1.89197364881972536382,
-0.211407134874412820099,
-0.000189204758260076688518,
0.00115140923889178742086,
0.639949204213164496988e-4,
0.139348932445324888343e-5,
};
static const T Q[9] = {
1,
0.244345337378188557777,
0.00873370754492288653669,
-0.00117592765334434471562,
-0.743743682899933180415e-4,
-0.21750464515767984778e-5,
0.471001264003076486547e-8,
-0.833378440625385520576e-10,
0.699841545204845636531e-12,
};
result = tools::evaluate_polynomial(P, s - 7) / tools::evaluate_polynomial(Q, s - 7);
result = 1 + exp(result);
}
else if(s < 36)
{
// Max error in interpolated form: 1.668e-17
// Max error found at long double precision: 1.669714e-17
static const T P[8] = {
-10.3948950573308896825,
-2.85827219671106697179,
-0.347728266539245787271,
-0.0251156064655346341766,
-0.00119459173416968685689,
-0.382529323507967522614e-4,
-0.785523633796723466968e-6,
-0.821465709095465524192e-8,
};
static const T Q[10] = {
1,
0.208196333572671890965,
0.0195687657317205033485,
0.00111079638102485921877,
0.408507746266039256231e-4,
0.955561123065693483991e-6,
0.118507153474022900583e-7,
0.222609483627352615142e-14,
};
result = tools::evaluate_polynomial(P, s - 15) / tools::evaluate_polynomial(Q, s - 15);
result = 1 + exp(result);
}
else if(s < 56)
{
result = 1 + pow(T(2), -s);
}
else
{
result = 1;
}
return result;
}
template <class T, class Policy>
T zeta_imp_prec(T s, T sc, const Policy&, const mpl::int_<64>&)
{
BOOST_MATH_STD_USING
T result;
if(s < 1)
{
// Rational Approximation
// Maximum Deviation Found: 3.099e-20
// Expected Error Term: 3.099e-20
// Max error found at long double precision: 5.890498e-20
static const T P[6] = {
0.243392944335937499969L,
-0.496837806864865688082L,
0.0680008039723709987107L,
-0.00511620413006619942112L,
0.000455369899250053003335L,
-0.279496685273033761927e-4L,
};
static const T Q[7] = {
1L,
-0.30425480068225790522L,
0.050052748580371598736L,
-0.00519355671064700627862L,
0.000360623385771198350257L,
-0.159600883054550987633e-4L,
0.339770279812410586032e-6L,
};
result = tools::evaluate_polynomial(P, sc) / tools::evaluate_polynomial(Q, sc);
result -= 1.2433929443359375F;
result += (sc);
result /= (sc);
}
else if(s <= 2)
{
// Maximum Deviation Found: 1.059e-21
// Expected Error Term: 1.059e-21
// Max error found at long double precision: 1.626303e-19
static const T P[6] = {
0.577215664901532860605L,
0.222537368917162139445L,
0.0356286324033215682729L,
0.00304465292366350081446L,
0.000178102511649069421904L,
0.700867470265983665042e-5L,
};
static const T Q[7] = {
1L,
0.259385759149531030085L,
0.0373974962106091316854L,
0.00332735159183332820617L,
0.000188690420706998606469L,
0.635994377921861930071e-5L,
0.226583954978371199405e-7L,
};
result = tools::evaluate_polynomial(P, -sc) / tools::evaluate_polynomial(Q, -sc);
result += 1 / (-sc);
}
else if(s <= 4)
{
// Maximum Deviation Found: 5.946e-22
// Expected Error Term: -5.946e-22
static const float Y = 0.6986598968505859375;
static const T P[7] = {
-0.053725830002359501027L,
0.0470551187571475844778L,
0.0101339410415759517471L,
0.00100240326666092854528L,
0.685027119098122814867e-4L,
0.390972820219765942117e-5L,
0.540319769113543934483e-7L,
};
static const T Q[8] = {
1,
0.286577739726542730421L,
0.0447355811517733225843L,
0.00430125107610252363302L,
0.000284956969089786662045L,
0.116188101609848411329e-4L,
0.278090318191657278204e-6L,
-0.19683620233222028478e-8L,
};
result = tools::evaluate_polynomial(P, s - 2) / tools::evaluate_polynomial(Q, s - 2);
result += Y + 1 / (-sc);
}
else if(s <= 7)
{
// Max error found at long double precision: 8.132216e-19
static const T P[8] = {
-2.49710190602259407065L,
-3.36664913245960625334L,
-1.77180020623777595452L,
-0.464717885249654313933L,
-0.0643694921293579472583L,
-0.00464265386202805715487L,
-0.000165556579779704340166L,
-0.252884970740994069582e-5L,
};
static const T Q[9] = {
1,
1.01300131390690459085L,
0.387898115758643503827L,
0.0695071490045701135188L,
0.00586908595251442839291L,
0.000217752974064612188616L,
0.397626583349419011731e-5L,
-0.927884739284359700764e-8L,
0.119810501805618894381e-9L,
};
result = tools::evaluate_polynomial(P, s - 4) / tools::evaluate_polynomial(Q, s - 4);
result = 1 + exp(result);
}
else if(s < 15)
{
// Max error in interpolated form: 1.133e-18
// Max error found at long double precision: 2.183198e-18
static const T P[9] = {
-4.78558028495135548083L,
-3.23873322238609358947L,
-0.892338582881021799922L,
-0.131326296217965913809L,
-0.0115651591773783712996L,
-0.000657728968362695775205L,
-0.252051328129449973047e-4L,
-0.626503445372641798925e-6L,
-0.815696314790853893484e-8L,
};
static const T Q[9] = {
1,
0.525765665400123515036L,
0.10852641753657122787L,
0.0115669945375362045249L,
0.000732896513858274091966L,
0.30683952282420248448e-4L,
0.819649214609633126119e-6L,
0.117957556472335968146e-7L,
-0.193432300973017671137e-12L,
};
result = tools::evaluate_polynomial(P, s - 7) / tools::evaluate_polynomial(Q, s - 7);
result = 1 + exp(result);
}
else if(s < 42)
{
// Max error in interpolated form: 1.668e-17
// Max error found at long double precision: 1.669714e-17
static const T P[9] = {
-10.3948950573308861781L,
-2.82646012777913950108L,
-0.342144362739570333665L,
-0.0249285145498722647472L,
-0.00122493108848097114118L,
-0.423055371192592850196e-4L,
-0.1025215577185967488e-5L,
-0.165096762663509467061e-7L,
-0.145392555873022044329e-9L,
};
static const T Q[10] = {
1,
0.205135978585281988052L,
0.0192359357875879453602L,
0.00111496452029715514119L,
0.434928449016693986857e-4L,
0.116911068726610725891e-5L,
0.206704342290235237475e-7L,
0.209772836100827647474e-9L,
-0.939798249922234703384e-16L,
0.264584017421245080294e-18L,
};
result = tools::evaluate_polynomial(P, s - 15) / tools::evaluate_polynomial(Q, s - 15);
result = 1 + exp(result);
}
else if(s < 63)
{
result = 1 + pow(T(2), -s);
}
else
{
result = 1;
}
return result;
}
template <class T, class Policy>
T zeta_imp_prec(T s, T sc, const Policy& pol, const mpl::int_<113>&)
{
BOOST_MATH_STD_USING
T result;
if(s < 1)
{
// Rational Approximation
// Maximum Deviation Found: 9.493e-37
// Expected Error Term: 9.492e-37
// Max error found at long double precision: 7.281332e-31
static const T P[10] = {
-1L,
-0.0353008629988648122808504280990313668L,
0.0107795651204927743049369868548706909L,
0.000523961870530500751114866884685172975L,
-0.661805838304910731947595897966487515e-4L,
-0.658932670403818558510656304189164638e-5L,
-0.103437265642266106533814021041010453e-6L,
0.116818787212666457105375746642927737e-7L,
0.660690993901506912123512551294239036e-9L,
0.113103113698388531428914333768142527e-10L,
};
static const T Q[11] = {
1L,
-0.387483472099602327112637481818565459L,
0.0802265315091063135271497708694776875L,
-0.0110727276164171919280036408995078164L,
0.00112552716946286252000434849173787243L,
-0.874554160748626916455655180296834352e-4L,
0.530097847491828379568636739662278322e-5L,
-0.248461553590496154705565904497247452e-6L,
0.881834921354014787309644951507523899e-8L,
-0.217062446168217797598596496310953025e-9L,
0.315823200002384492377987848307151168e-11L,
};
result = tools::evaluate_polynomial(P, sc) / tools::evaluate_polynomial(Q, sc);
result += (sc);
result /= (sc);
}
else if(s <= 2)
{
// Maximum Deviation Found: 1.616e-37
// Expected Error Term: -1.615e-37
static const T P[10] = {
0.577215664901532860606512090082402431L,
0.255597968739771510415479842335906308L,
0.0494056503552807274142218876983542205L,
0.00551372778611700965268920983472292325L,
0.00043667616723970574871427830895192731L,
0.268562259154821957743669387915239528e-4L,
0.109249633923016310141743084480436612e-5L,
0.273895554345300227466534378753023924e-7L,
0.583103205551702720149237384027795038e-9L,
-0.835774625259919268768735944711219256e-11L,
};
static const T Q[11] = {
1L,
0.316661751179735502065583176348292881L,
0.0540401806533507064453851182728635272L,
0.00598621274107420237785899476374043797L,
0.000474907812321704156213038740142079615L,
0.272125421722314389581695715835862418e-4L,
0.112649552156479800925522445229212933e-5L,
0.301838975502992622733000078063330461e-7L,
0.422960728687211282539769943184270106e-9L,
-0.377105263588822468076813329270698909e-11L,
-0.581926559304525152432462127383600681e-13L,
};
result = tools::evaluate_polynomial(P, -sc) / tools::evaluate_polynomial(Q, -sc);
result += 1 / (-sc);
}
else if(s <= 4)
{
// Maximum Deviation Found: 1.891e-36
// Expected Error Term: -1.891e-36
// Max error found: 2.171527e-35
static const float Y = 0.6986598968505859375;
static const T P[11] = {
-0.0537258300023595010275848333539748089L,
0.0429086930802630159457448174466342553L,
0.0136148228754303412510213395034056857L,
0.00190231601036042925183751238033763915L,
0.000186880390916311438818302549192456581L,
0.145347370745893262394287982691323657e-4L,
0.805843276446813106414036600485884885e-6L,
0.340818159286739137503297172091882574e-7L,
0.115762357488748996526167305116837246e-8L,
0.231904754577648077579913403645767214e-10L,
0.340169592866058506675897646629036044e-12L,
};
static const T Q[12] = {
1L,
0.363755247765087100018556983050520554L,
0.0696581979014242539385695131258321598L,
0.00882208914484611029571547753782014817L,
0.000815405623261946661762236085660996718L,
0.571366167062457197282642344940445452e-4L,
0.309278269271853502353954062051797838e-5L,
0.12822982083479010834070516053794262e-6L,
0.397876357325018976733953479182110033e-8L,
0.8484432107648683277598472295289279e-10L,
0.105677416606909614301995218444080615e-11L,
0.547223964564003701979951154093005354e-15L,
};
result = tools::evaluate_polynomial(P, s - 2) / tools::evaluate_polynomial(Q, s - 2);
result += Y + 1 / (-sc);
}
else if(s <= 6)
{
// Max error in interpolated form: 1.510e-37
// Max error found at long double precision: 2.769266e-34
static const T Y = 3.28348541259765625F;
static const T P[13] = {
0.786383506575062179339611614117697622L,
0.495766593395271370974685959652073976L,
-0.409116737851754766422360889037532228L,
-0.57340744006238263817895456842655987L,
-0.280479899797421910694892949057963111L,
-0.0753148409447590257157585696212649869L,
-0.0122934003684672788499099362823748632L,
-0.00126148398446193639247961370266962927L,
-0.828465038179772939844657040917364896e-4L,
-0.361008916706050977143208468690645684e-5L,
-0.109879825497910544424797771195928112e-6L,
-0.214539416789686920918063075528797059e-8L,
-0.15090220092460596872172844424267351e-10L,
};
static const T Q[14] = {
1L,
1.69490865837142338462982225731926485L,
1.22697696630994080733321401255942464L,
0.495409420862526540074366618006341533L,
0.122368084916843823462872905024259633L,
0.0191412993625268971656513890888208623L,
0.00191401538628980617753082598351559642L,
0.000123318142456272424148930280876444459L,
0.531945488232526067889835342277595709e-5L,
0.161843184071894368337068779669116236e-6L,
0.305796079600152506743828859577462778e-8L,
0.233582592298450202680170811044408894e-10L,
-0.275363878344548055574209713637734269e-13L,
0.221564186807357535475441900517843892e-15L,
};
result = tools::evaluate_polynomial(P, s - 4) / tools::evaluate_polynomial(Q, s - 4);
result -= Y;
result = 1 + exp(result);
}
else if(s < 10)
{
// Max error in interpolated form: 1.999e-34
// Max error found at long double precision: 2.156186e-33
static const T P[13] = {
-4.0545627381873738086704293881227365L,
-4.70088348734699134347906176097717782L,
-2.36921550900925512951976617607678789L,
-0.684322583796369508367726293719322866L,
-0.126026534540165129870721937592996324L,
-0.015636903921778316147260572008619549L,
-0.00135442294754728549644376325814460807L,
-0.842793965853572134365031384646117061e-4L,
-0.385602133791111663372015460784978351e-5L,
-0.130458500394692067189883214401478539e-6L,
-0.315861074947230418778143153383660035e-8L,
-0.500334720512030826996373077844707164e-10L,
-0.420204769185233365849253969097184005e-12L,
};
static const T Q[14] = {
1L,
0.97663511666410096104783358493318814L,
0.40878780231201806504987368939673249L,
0.0963890666609396058945084107597727252L,
0.0142207619090854604824116070866614505L,
0.00139010220902667918476773423995750877L,
0.940669540194694997889636696089994734e-4L,
0.458220848507517004399292480807026602e-5L,
0.16345521617741789012782420625435495e-6L,
0.414007452533083304371566316901024114e-8L,
0.68701473543366328016953742622661377e-10L,
0.603461891080716585087883971886075863e-12L,
0.294670713571839023181857795866134957e-16L,
-0.147003914536437243143096875069813451e-18L,
};
result = tools::evaluate_polynomial(P, s - 6) / tools::evaluate_polynomial(Q, s - 6);
result = 1 + exp(result);
}
else if(s < 17)
{
// Max error in interpolated form: 1.641e-32
// Max error found at long double precision: 1.696121e-32
static const T P[13] = {
-6.91319491921722925920883787894829678L,
-3.65491257639481960248690596951049048L,
-0.813557553449954526442644544105257881L,
-0.0994317301685870959473658713841138083L,
-0.00726896610245676520248617014211734906L,
-0.000317253318715075854811266230916762929L,
-0.66851422826636750855184211580127133e-5L,
0.879464154730985406003332577806849971e-7L,
0.113838903158254250631678791998294628e-7L,
0.379184410304927316385211327537817583e-9L,
0.612992858643904887150527613446403867e-11L,
0.347873737198164757035457841688594788e-13L,
-0.289187187441625868404494665572279364e-15L,
};
static const T Q[14] = {
1L,
0.427310044448071818775721584949868806L,
0.074602514873055756201435421385243062L,
0.00688651562174480772901425121653945942L,
0.000360174847635115036351323894321880445L,
0.973556847713307543918865405758248777e-5L,
-0.853455848314516117964634714780874197e-8L,
-0.118203513654855112421673192194622826e-7L,
-0.462521662511754117095006543363328159e-9L,
-0.834212591919475633107355719369463143e-11L,
-0.5354594751002702935740220218582929e-13L,
0.406451690742991192964889603000756203e-15L,
0.887948682401000153828241615760146728e-19L,
-0.34980761098820347103967203948619072e-21L,
};
result = tools::evaluate_polynomial(P, s - 10) / tools::evaluate_polynomial(Q, s - 10);
result = 1 + exp(result);
}
else if(s < 30)
{
// Max error in interpolated form: 1.563e-31
// Max error found at long double precision: 1.562725e-31
static const T P[13] = {
-11.7824798233959252791987402769438322L,
-4.36131215284987731928174218354118102L,
-0.732260980060982349410898496846972204L,
-0.0744985185694913074484248803015717388L,
-0.00517228281320594683022294996292250527L,
-0.000260897206152101522569969046299309939L,
-0.989553462123121764865178453128769948e-5L,
-0.286916799741891410827712096608826167e-6L,
-0.637262477796046963617949532211619729e-8L,
-0.106796831465628373325491288787760494e-9L,
-0.129343095511091870860498356205376823e-11L,
-0.102397936697965977221267881716672084e-13L,
-0.402663128248642002351627980255756363e-16L,
};
static const T Q[14] = {
1L,
0.311288325355705609096155335186466508L,
0.0438318468940415543546769437752132748L,
0.00374396349183199548610264222242269536L,
0.000218707451200585197339671707189281302L,
0.927578767487930747532953583797351219e-5L,
0.294145760625753561951137473484889639e-6L,
0.704618586690874460082739479535985395e-8L,
0.126333332872897336219649130062221257e-9L,
0.16317315713773503718315435769352765e-11L,
0.137846712823719515148344938160275695e-13L,
0.580975420554224366450994232723910583e-16L,
-0.291354445847552426900293580511392459e-22L,
0.73614324724785855925025452085443636e-25L,
};
result = tools::evaluate_polynomial(P, s - 17) / tools::evaluate_polynomial(Q, s - 17);
result = 1 + exp(result);
}
else if(s < 74)
{
// Max error in interpolated form: 2.311e-27
// Max error found at long double precision: 2.297544e-27
static const T P[14] = {
-20.7944102007844314586649688802236072L,
-4.95759941987499442499908748130192187L,
-0.563290752832461751889194629200298688L,
-0.0406197001137935911912457120706122877L,
-0.0020846534789473022216888863613422293L,
-0.808095978462109173749395599401375667e-4L,
-0.244706022206249301640890603610060959e-5L,
-0.589477682919645930544382616501666572e-7L,
-0.113699573675553496343617442433027672e-8L,
-0.174767860183598149649901223128011828e-10L,
-0.210051620306761367764549971980026474e-12L,
-0.189187969537370950337212675466400599e-14L,
-0.116313253429564048145641663778121898e-16L,
-0.376708747782400769427057630528578187e-19L,
};
static const T Q[16] = {
1L,
0.205076752981410805177554569784219717L,
0.0202526722696670378999575738524540269L,
0.001278305290005994980069466658219057L,
0.576404779858501791742255670403304787e-4L,
0.196477049872253010859712483984252067e-5L,
0.521863830500876189501054079974475762e-7L,
0.109524209196868135198775445228552059e-8L,
0.181698713448644481083966260949267825e-10L,
0.234793316975091282090312036524695562e-12L,
0.227490441461460571047545264251399048e-14L,
0.151500292036937400913870642638520668e-16L,
0.543475775154780935815530649335936121e-19L,
0.241647013434111434636554455083309352e-28L,
-0.557103423021951053707162364713587374e-31L,
0.618708773442584843384712258199645166e-34L,
};
result = tools::evaluate_polynomial(P, s - 30) / tools::evaluate_polynomial(Q, s - 30);
result = 1 + exp(result);
}
else if(s < 117)
{
result = 1 + pow(T(2), -s);
}
else
{
result = 1;
}
return result;
}
template <class T, class Policy, class Tag>
T zeta_imp(T s, T sc, const Policy& pol, const Tag& tag)
{
BOOST_MATH_STD_USING
if(s == 1)
return policies::raise_pole_error<T>(
"boost::math::zeta<%1%>",
"Evaluation of zeta function at pole %1%",
s, pol);
T result;
if(s == 0)
{
result = -0.5;
}
else if(s < 0)
{
std::swap(s, sc);
if(floor(sc/2) == sc/2)
result = 0;
else
{
result = boost::math::sin_pi(0.5f * sc, pol)
* 2 * pow(2 * constants::pi<T>(), -s)
* boost::math::tgamma(s, pol)
* zeta_imp(s, sc, pol, tag);
}
}
else
{
result = zeta_imp_prec(s, sc, pol, tag);
}
return result;
}
} // detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type zeta(T s, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::precision<result_type, Policy>::type precision_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
typedef typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<0> >,
mpl::int_<0>,
typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<53> >,
mpl::int_<53>, // double
typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<64> >,
mpl::int_<64>, // 80-bit long double
typename mpl::if_<
mpl::less_equal<precision_type, mpl::int_<113> >,
mpl::int_<113>, // 128-bit long double
mpl::int_<0> // too many bits, use generic version.
>::type
>::type
>::type
>::type tag_type;
//typedef mpl::int_<0> tag_type;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::zeta_imp(
static_cast<value_type>(s),
static_cast<value_type>(1 - static_cast<value_type>(s)),
forwarding_policy(),
tag_type()), "boost::math::zeta<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type zeta(T s)
{
return zeta(s, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ZETA_HPP