1
0

Initial commit

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

2
code_isotrope/README Executable file
View File

@@ -0,0 +1,2 @@
Pour l'affichage python nécessite la librairie "matplotlib", pour l'installer : "sudo apt install pip-python ; pip install matplotlib" (pip se chargera des dépendances)
Pour compiler et exécuter le programme taper la commande "make"

89
code_isotrope/affichage_iso.py Executable file
View File

@@ -0,0 +1,89 @@
#!/usr/bin/python
#-*- coding:utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
A=np.loadtxt("data_iso.res")
xdata_v = A[:,0]
xdata_l = 3e8/xdata_v
ydata_vi = A[:,1]
ydata_li = ydata_vi*3e8/(xdata_l**2)
ydata_vp = A[:,2]
ydata_lp = ydata_vp*3e8/(xdata_l**2)
fig,ax = plt.subplots(3,2,sharex='col',gridspec_kw={'height_ratios':[3,3,0.20]},figsize=(18,9))
plt.subplots_adjust(left=0.06,bottom=0.07,right=0.98,top=0.9,wspace=0.2,hspace=0.3)
ax[0,0].plot(xdata_l,ydata_li,label="for B = 10^-4 T,\n gamma = 10^4,\n pitch = 45deg.")
ax[0,0].set_xscale('log')
ax[0,0].set_xlabel(r"$\lambda$ ($m$)")
ax[0,0].set_yscale('log')
ax[0,0].set_xlim(3e-9,3e-1)
ax[0,0].set_ylabel(r"Emissivity ($W \cdot m^{-1}$)")
#ax[0,0].legend()
ax[0,0].set_title("Emissivity for one particle")
ax[0,1].plot(xdata_v,ydata_vi)
ax[0,1].set_xscale('log')
ax[0,1].set_yscale('log')
ax[0,1].set_xlim(1e9,1e17)
#ax[0,1].set_ylim(1e-8,1)
ax[0,1].set_xlabel(r"$\nu$ ($Hz$)")
ax[0,1].set_ylabel(r"Emissivity ($W \cdot Hz^{-1}$)")
#ax[0,1].legend()
ax[0,1].set_title("Emissivity for one particle")
ax[1,0].plot(xdata_l,ydata_lp)
ax[1,0].set_xlabel(r"$\lambda$ ($m$)")
ax[1,0].set_xscale('log')
ax[1,0].set_yscale('log')
ax[1,0].set_ylabel(r"Emissivity ($W \cdot m^{-1}$)")
#ax[1,0].legend()
ax[1,0].set_title("Emissivity for a population of particles")
ax[1,1].plot(xdata_v,ydata_vp)
ax[1,1].set_xscale('log')
ax[1,1].set_yscale('log')
#ax[1,1].set_ylim(1e9,1e17)
#ax[1,1].set_xlim(1e-2,1e2)
ax[1,1].set_xlabel(r"$\nu$ ($Hz$)")
ax[1,1].set_ylabel(r"Emissivity ($W \cdot Hz^{-1}$)")
#ax[1,1].legend()
ax[1,1].set_title("Emissivity for a population of particles")
def annotation_line(ax, xmin, xmax, y, text, ytext=0, linecolor='black', linewidth=1, fontsize=8):
ax.annotate('', xy=(xmin, y), xytext=(xmax, y), xycoords='data', textcoords='data',arrowprops={'arrowstyle': '|-|', 'color':linecolor, 'linewidth':linewidth})
xcenter = np.log10(xmin)+(np.log10(xmax)-np.log10(xmin))/2
if ytext==0:
ytext = y+(ax.get_ylim()[1]-ax.get_ylim()[0])/5
ax.annotate( text, xy=(pow(10,xcenter),ytext), ha='center', va='center', fontsize=fontsize )
ax[2][1].set_ylim(-1,2)
ax[2][1].tick_params(labelleft=False,left=False)
#annotation_line(ax[2][1],1e7,3e8,0,"Radio Waves")
annotation_line(ax[2][1],1e9,3e11,0,"Microwaves")
annotation_line(ax[2][1],3e11,4e14,0,"IR")
annotation_line(ax[2][1],4e14,7.5e14,0,"Visible")
annotation_line(ax[2][1],7.5e14,2e16,0,"UV")
annotation_line(ax[2][1],2e16,1e17,0,"X Rays")
#annotation_line(ax[2][1],2e19,1e23,0,"Gamma Rays")
ax[2,1].set_xlabel(r"$\nu$ ($Hz$)")
ax[2][0].set_ylim(-1,2)
ax[2][0].tick_params(labelleft=False,left=False)
#annotation_line(ax[2][0],1e0,1e3,0,"Radio Waves")
annotation_line(ax[2][0],1e-3,3e-1,0,"Microwaves")
annotation_line(ax[2][0],7.5e-7,1e-3,0,"IR")
annotation_line(ax[2][0],4e-7,7.5e-7,0,"Visible")
annotation_line(ax[2][0],8e-9,4e-7,0,"UV")
annotation_line(ax[2][0],3e-9,8e-9,0,"X Rays")
#annotation_line(ax[2][0],1e-12,1e-11,0,"Gamma Rays")
ax[2,0].set_xlabel(r"$\lambda$ ($m$)")
fig.suptitle(r"Plots for an isotropic synchrotron radiation for $B = 10^{-4}T$, $p=2.0$, $\gamma = 10^{4}$, $\alpha_{p} = 45^{\circ}$.")
plt.savefig("isotropic_sed.png",bbox_inches='tight')
#plt.show()

View File

@@ -0,0 +1,75 @@
// Copyright John Maddock 2006, 2007, 2012, 2014.
// Copyright Paul A. Bristow 2006, 2007, 2012
// 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 includes *all* the special functions.
// this may be useful if many are used
// - to avoid including each function individually.
#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_HPP
#define BOOST_MATH_SPECIAL_FUNCTIONS_HPP
#include <boost/math/special_functions/airy.hpp>
#include <boost/math/special_functions/acosh.hpp>
#include <boost/math/special_functions/asinh.hpp>
#include <boost/math/special_functions/atanh.hpp>
#include <boost/math/special_functions/bernoulli.hpp>
#include <boost/math/special_functions/bessel.hpp>
#include <boost/math/special_functions/bessel_prime.hpp>
#include <boost/math/special_functions/beta.hpp>
#include <boost/math/special_functions/binomial.hpp>
#include <boost/math/special_functions/cbrt.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
#include <boost/math/special_functions/chebyshev.hpp>
#include <boost/math/special_functions/digamma.hpp>
#include <boost/math/special_functions/ellint_1.hpp>
#include <boost/math/special_functions/ellint_2.hpp>
#include <boost/math/special_functions/ellint_3.hpp>
#include <boost/math/special_functions/ellint_d.hpp>
#include <boost/math/special_functions/jacobi_zeta.hpp>
#include <boost/math/special_functions/heuman_lambda.hpp>
#include <boost/math/special_functions/ellint_rc.hpp>
#include <boost/math/special_functions/ellint_rd.hpp>
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/special_functions/ellint_rg.hpp>
#include <boost/math/special_functions/erf.hpp>
#include <boost/math/special_functions/expint.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/hermite.hpp>
#include <boost/math/special_functions/hypot.hpp>
#include <boost/math/special_functions/jacobi_elliptic.hpp>
#include <boost/math/special_functions/laguerre.hpp>
#include <boost/math/special_functions/lanczos.hpp>
#include <boost/math/special_functions/legendre.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/next.hpp>
#include <boost/math/special_functions/owens_t.hpp>
#include <boost/math/special_functions/polygamma.hpp>
#include <boost/math/special_functions/powm1.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/special_functions/sinc.hpp>
#include <boost/math/special_functions/sinhc.hpp>
#include <boost/math/special_functions/spherical_harmonic.hpp>
#include <boost/math/special_functions/sqrt1pm1.hpp>
#include <boost/math/special_functions/zeta.hpp>
#include <boost/math/special_functions/modf.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/special_functions/pow.hpp>
#include <boost/math/special_functions/next.hpp>
#include <boost/math/special_functions/owens_t.hpp>
#include <boost/math/special_functions/hankel.hpp>
#include <boost/math/special_functions/ulp.hpp>
#include <boost/math/special_functions/relative_difference.hpp>
#include <boost/math/special_functions/lambert_w.hpp>
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_HPP

View File

@@ -0,0 +1,104 @@
// 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>
#include <boost/math/constants/constants.hpp>
// This is the inverse of the hyperbolic cosine function.
namespace boost
{
namespace math
{
namespace detail
{
template<typename T, typename Policy>
inline T acosh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if((x < 1) || (boost::math::isnan)(x))
{
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) + constants::ln_two<T>();
}
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,469 @@
// Copyright John Maddock 2012.
// 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_AIRY_HPP
#define BOOST_MATH_AIRY_HPP
#include <limits>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/bessel.hpp>
#include <boost/math/special_functions/cbrt.hpp>
#include <boost/math/special_functions/detail/airy_ai_bi_zero.hpp>
#include <boost/math/tools/roots.hpp>
namespace boost{ namespace math{
namespace detail{
template <class T, class Policy>
T airy_ai_imp(T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if(x < 0)
{
T p = (-x * sqrt(-x) * 2) / 3;
T v = T(1) / 3;
T j1 = boost::math::cyl_bessel_j(v, p, pol);
T j2 = boost::math::cyl_bessel_j(-v, p, pol);
T ai = sqrt(-x) * (j1 + j2) / 3;
//T bi = sqrt(-x / 3) * (j2 - j1);
return ai;
}
else if(fabs(x * x * x) / 6 < tools::epsilon<T>())
{
T tg = boost::math::tgamma(constants::twothirds<T>(), pol);
T ai = 1 / (pow(T(3), constants::twothirds<T>()) * tg);
//T bi = 1 / (sqrt(boost::math::cbrt(T(3))) * tg);
return ai;
}
else
{
T p = 2 * x * sqrt(x) / 3;
T v = T(1) / 3;
//T j1 = boost::math::cyl_bessel_i(-v, p, pol);
//T j2 = boost::math::cyl_bessel_i(v, p, pol);
//
// Note that although we can calculate ai from j1 and j2, the accuracy is horrible
// as we're subtracting two very large values, so use the Bessel K relation instead:
//
T ai = cyl_bessel_k(v, p, pol) * sqrt(x / 3) / boost::math::constants::pi<T>(); //sqrt(x) * (j1 - j2) / 3;
//T bi = sqrt(x / 3) * (j1 + j2);
return ai;
}
}
template <class T, class Policy>
T airy_bi_imp(T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if(x < 0)
{
T p = (-x * sqrt(-x) * 2) / 3;
T v = T(1) / 3;
T j1 = boost::math::cyl_bessel_j(v, p, pol);
T j2 = boost::math::cyl_bessel_j(-v, p, pol);
//T ai = sqrt(-x) * (j1 + j2) / 3;
T bi = sqrt(-x / 3) * (j2 - j1);
return bi;
}
else if(fabs(x * x * x) / 6 < tools::epsilon<T>())
{
T tg = boost::math::tgamma(constants::twothirds<T>(), pol);
//T ai = 1 / (pow(T(3), constants::twothirds<T>()) * tg);
T bi = 1 / (sqrt(boost::math::cbrt(T(3))) * tg);
return bi;
}
else
{
T p = 2 * x * sqrt(x) / 3;
T v = T(1) / 3;
T j1 = boost::math::cyl_bessel_i(-v, p, pol);
T j2 = boost::math::cyl_bessel_i(v, p, pol);
T bi = sqrt(x / 3) * (j1 + j2);
return bi;
}
}
template <class T, class Policy>
T airy_ai_prime_imp(T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if(x < 0)
{
T p = (-x * sqrt(-x) * 2) / 3;
T v = T(2) / 3;
T j1 = boost::math::cyl_bessel_j(v, p, pol);
T j2 = boost::math::cyl_bessel_j(-v, p, pol);
T aip = -x * (j1 - j2) / 3;
return aip;
}
else if(fabs(x * x) / 2 < tools::epsilon<T>())
{
T tg = boost::math::tgamma(constants::third<T>(), pol);
T aip = 1 / (boost::math::cbrt(T(3)) * tg);
return -aip;
}
else
{
T p = 2 * x * sqrt(x) / 3;
T v = T(2) / 3;
//T j1 = boost::math::cyl_bessel_i(-v, p, pol);
//T j2 = boost::math::cyl_bessel_i(v, p, pol);
//
// Note that although we can calculate ai from j1 and j2, the accuracy is horrible
// as we're subtracting two very large values, so use the Bessel K relation instead:
//
T aip = -cyl_bessel_k(v, p, pol) * x / (boost::math::constants::root_three<T>() * boost::math::constants::pi<T>());
return aip;
}
}
template <class T, class Policy>
T airy_bi_prime_imp(T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if(x < 0)
{
T p = (-x * sqrt(-x) * 2) / 3;
T v = T(2) / 3;
T j1 = boost::math::cyl_bessel_j(v, p, pol);
T j2 = boost::math::cyl_bessel_j(-v, p, pol);
T aip = -x * (j1 + j2) / constants::root_three<T>();
return aip;
}
else if(fabs(x * x) / 2 < tools::epsilon<T>())
{
T tg = boost::math::tgamma(constants::third<T>(), pol);
T bip = sqrt(boost::math::cbrt(T(3))) / tg;
return bip;
}
else
{
T p = 2 * x * sqrt(x) / 3;
T v = T(2) / 3;
T j1 = boost::math::cyl_bessel_i(-v, p, pol);
T j2 = boost::math::cyl_bessel_i(v, p, pol);
T aip = x * (j1 + j2) / boost::math::constants::root_three<T>();
return aip;
}
}
template <class T, class Policy>
T airy_ai_zero_imp(int m, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names, needed for log, sqrt.
// Handle cases when a negative zero (negative rank) is requested.
if(m < 0)
{
return policies::raise_domain_error<T>("boost::math::airy_ai_zero<%1%>(%1%, int)",
"Requested the %1%'th zero, but the rank must be 1 or more !", static_cast<T>(m), pol);
}
// Handle case when the zero'th zero is requested.
if(m == 0U)
{
return policies::raise_domain_error<T>("boost::math::airy_ai_zero<%1%>(%1%,%1%)",
"The requested rank of the zero is %1%, but must be 1 or more !", static_cast<T>(m), pol);
}
// Set up the initial guess for the upcoming root-finding.
const T guess_root = boost::math::detail::airy_zero::airy_ai_zero_detail::initial_guess<T>(m);
// Select the maximum allowed iterations based on the number
// of decimal digits in the numeric type T, being at least 12.
const int my_digits10 = static_cast<int>(static_cast<float>(policies::digits<T, Policy>() * 0.301F));
const boost::uintmax_t iterations_allowed = static_cast<boost::uintmax_t>((std::max)(12, my_digits10 * 2));
boost::uintmax_t iterations_used = iterations_allowed;
// Use a dynamic tolerance because the roots get closer the higher m gets.
T tolerance;
if (m <= 10) { tolerance = T(0.3F); }
else if(m <= 100) { tolerance = T(0.1F); }
else if(m <= 1000) { tolerance = T(0.05F); }
else { tolerance = T(1) / sqrt(T(m)); }
// Perform the root-finding using Newton-Raphson iteration from Boost.Math.
const T am =
boost::math::tools::newton_raphson_iterate(
boost::math::detail::airy_zero::airy_ai_zero_detail::function_object_ai_and_ai_prime<T, Policy>(pol),
guess_root,
T(guess_root - tolerance),
T(guess_root + tolerance),
policies::digits<T, Policy>(),
iterations_used);
static_cast<void>(iterations_used);
return am;
}
template <class T, class Policy>
T airy_bi_zero_imp(int m, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names, needed for log, sqrt.
// Handle cases when a negative zero (negative rank) is requested.
if(m < 0)
{
return policies::raise_domain_error<T>("boost::math::airy_bi_zero<%1%>(%1%, int)",
"Requested the %1%'th zero, but the rank must 1 or more !", static_cast<T>(m), pol);
}
// Handle case when the zero'th zero is requested.
if(m == 0U)
{
return policies::raise_domain_error<T>("boost::math::airy_bi_zero<%1%>(%1%,%1%)",
"The requested rank of the zero is %1%, but must be 1 or more !", static_cast<T>(m), pol);
}
// Set up the initial guess for the upcoming root-finding.
const T guess_root = boost::math::detail::airy_zero::airy_bi_zero_detail::initial_guess<T>(m);
// Select the maximum allowed iterations based on the number
// of decimal digits in the numeric type T, being at least 12.
const int my_digits10 = static_cast<int>(static_cast<float>(policies::digits<T, Policy>() * 0.301F));
const boost::uintmax_t iterations_allowed = static_cast<boost::uintmax_t>((std::max)(12, my_digits10 * 2));
boost::uintmax_t iterations_used = iterations_allowed;
// Use a dynamic tolerance because the roots get closer the higher m gets.
T tolerance;
if (m <= 10) { tolerance = T(0.3F); }
else if(m <= 100) { tolerance = T(0.1F); }
else if(m <= 1000) { tolerance = T(0.05F); }
else { tolerance = T(1) / sqrt(T(m)); }
// Perform the root-finding using Newton-Raphson iteration from Boost.Math.
const T bm =
boost::math::tools::newton_raphson_iterate(
boost::math::detail::airy_zero::airy_bi_zero_detail::function_object_bi_and_bi_prime<T, Policy>(pol),
guess_root,
T(guess_root - tolerance),
T(guess_root + tolerance),
policies::digits<T, Policy>(),
iterations_used);
static_cast<void>(iterations_used);
return bm;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type airy_ai(T x, const Policy&)
{
BOOST_FPU_EXCEPTION_GUARD
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, Policy>(detail::airy_ai_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type airy_ai(T x)
{
return airy_ai(x, policies::policy<>());
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type airy_bi(T x, const Policy&)
{
BOOST_FPU_EXCEPTION_GUARD
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, Policy>(detail::airy_bi_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type airy_bi(T x)
{
return airy_bi(x, policies::policy<>());
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type airy_ai_prime(T x, const Policy&)
{
BOOST_FPU_EXCEPTION_GUARD
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, Policy>(detail::airy_ai_prime_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type airy_ai_prime(T x)
{
return airy_ai_prime(x, policies::policy<>());
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type airy_bi_prime(T x, const Policy&)
{
BOOST_FPU_EXCEPTION_GUARD
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, Policy>(detail::airy_bi_prime_imp<value_type>(static_cast<value_type>(x), forwarding_policy()), "boost::math::airy<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type airy_bi_prime(T x)
{
return airy_bi_prime(x, policies::policy<>());
}
template <class T, class Policy>
inline T airy_ai_zero(int m, const Policy& /*pol*/)
{
BOOST_FPU_EXCEPTION_GUARD
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;
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Airy value type must be a floating-point type.");
return policies::checked_narrowing_cast<T, Policy>(detail::airy_ai_zero_imp<value_type>(m, forwarding_policy()), "boost::math::airy_ai_zero<%1%>(unsigned)");
}
template <class T>
inline T airy_ai_zero(int m)
{
return airy_ai_zero<T>(m, policies::policy<>());
}
template <class T, class OutputIterator, class Policy>
inline OutputIterator airy_ai_zero(
int start_index,
unsigned number_of_zeros,
OutputIterator out_it,
const Policy& pol)
{
typedef T result_type;
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Airy value type must be a floating-point type.");
for(unsigned i = 0; i < number_of_zeros; ++i)
{
*out_it = boost::math::airy_ai_zero<result_type>(start_index + i, pol);
++out_it;
}
return out_it;
}
template <class T, class OutputIterator>
inline OutputIterator airy_ai_zero(
int start_index,
unsigned number_of_zeros,
OutputIterator out_it)
{
return airy_ai_zero<T>(start_index, number_of_zeros, out_it, policies::policy<>());
}
template <class T, class Policy>
inline T airy_bi_zero(int m, const Policy& /*pol*/)
{
BOOST_FPU_EXCEPTION_GUARD
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;
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Airy value type must be a floating-point type.");
return policies::checked_narrowing_cast<T, Policy>(detail::airy_bi_zero_imp<value_type>(m, forwarding_policy()), "boost::math::airy_bi_zero<%1%>(unsigned)");
}
template <typename T>
inline T airy_bi_zero(int m)
{
return airy_bi_zero<T>(m, policies::policy<>());
}
template <class T, class OutputIterator, class Policy>
inline OutputIterator airy_bi_zero(
int start_index,
unsigned number_of_zeros,
OutputIterator out_it,
const Policy& pol)
{
typedef T result_type;
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Airy value type must be a floating-point type.");
for(unsigned i = 0; i < number_of_zeros; ++i)
{
*out_it = boost::math::airy_bi_zero<result_type>(start_index + i, pol);
++out_it;
}
return out_it;
}
template <class T, class OutputIterator>
inline OutputIterator airy_bi_zero(
int start_index,
unsigned number_of_zeros,
OutputIterator out_it)
{
return airy_bi_zero<T>(start_index, number_of_zeros, out_it, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_AIRY_HPP

View File

@@ -0,0 +1,112 @@
// 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>
#include <boost/math/constants/constants.hpp>
// This is the inverse of the hyperbolic sine function.
namespace boost
{
namespace math
{
namespace detail{
template<typename T, class Policy>
inline T asinh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if((boost::math::isnan)(x))
{
return policies::raise_domain_error<T>(
"boost::math::asinh<%1%>(%1%)",
"asinh requires a finite argument, but got x = %1%.", x, pol);
}
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 constants::ln_two<T>() + log(x) + 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, pol));
}
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,123 @@
// 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
{
// 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)
{
return policies::raise_domain_error<T>(
function,
"atanh requires x <= 1, but got x = %1%.", x, pol);
}
else if((boost::math::isnan)(x))
{
return policies::raise_domain_error<T>(
function,
"atanh requires -1 <= 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(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,143 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2013 Nikhar Agrawal
// Copyright 2013 Christopher Kormanyos
// Copyright 2013 John Maddock
// Copyright 2013 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef _BOOST_BERNOULLI_B2N_2013_05_30_HPP_
#define _BOOST_BERNOULLI_B2N_2013_05_30_HPP_
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/detail/unchecked_bernoulli.hpp>
#include <boost/math/special_functions/detail/bernoulli_details.hpp>
namespace boost { namespace math {
namespace detail {
template <class T, class OutputIterator, class Policy, int N>
OutputIterator bernoulli_number_imp(OutputIterator out, std::size_t start, std::size_t n, const Policy& pol, const mpl::int_<N>& tag)
{
for(std::size_t i = start; (i <= max_bernoulli_b2n<T>::value) && (i < start + n); ++i)
{
*out = unchecked_bernoulli_imp<T>(i, tag);
++out;
}
for(std::size_t i = (std::max)(static_cast<std::size_t>(max_bernoulli_b2n<T>::value + 1), start); i < start + n; ++i)
{
// We must overflow:
*out = (i & 1 ? 1 : -1) * policies::raise_overflow_error<T>("boost::math::bernoulli_b2n<%1%>(n)", 0, T(i), pol);
++out;
}
return out;
}
template <class T, class OutputIterator, class Policy>
OutputIterator bernoulli_number_imp(OutputIterator out, std::size_t start, std::size_t n, const Policy& pol, const mpl::int_<0>& tag)
{
for(std::size_t i = start; (i <= max_bernoulli_b2n<T>::value) && (i < start + n); ++i)
{
*out = unchecked_bernoulli_imp<T>(i, tag);
++out;
}
//
// Short circuit return so we don't grab the mutex below unless we have to:
//
if(start + n <= max_bernoulli_b2n<T>::value)
return out;
return get_bernoulli_numbers_cache<T, Policy>().copy_bernoulli_numbers(out, start, n, pol);
}
} // namespace detail
template <class T, class Policy>
inline T bernoulli_b2n(const int i, const Policy &pol)
{
typedef mpl::int_<detail::bernoulli_imp_variant<T>::value> tag_type;
if(i < 0)
return policies::raise_domain_error<T>("boost::math::bernoulli_b2n<%1%>", "Index should be >= 0 but got %1%", T(i), pol);
T result = static_cast<T>(0); // The = 0 is just to silence compiler warnings :-(
boost::math::detail::bernoulli_number_imp<T>(&result, static_cast<std::size_t>(i), 1u, pol, tag_type());
return result;
}
template <class T>
inline T bernoulli_b2n(const int i)
{
return boost::math::bernoulli_b2n<T>(i, policies::policy<>());
}
template <class T, class OutputIterator, class Policy>
inline OutputIterator bernoulli_b2n(const int start_index,
const unsigned number_of_bernoullis_b2n,
OutputIterator out_it,
const Policy& pol)
{
typedef mpl::int_<detail::bernoulli_imp_variant<T>::value> tag_type;
if(start_index < 0)
{
*out_it = policies::raise_domain_error<T>("boost::math::bernoulli_b2n<%1%>", "Index should be >= 0 but got %1%", T(start_index), pol);
return ++out_it;
}
return boost::math::detail::bernoulli_number_imp<T>(out_it, start_index, number_of_bernoullis_b2n, pol, tag_type());
}
template <class T, class OutputIterator>
inline OutputIterator bernoulli_b2n(const int start_index,
const unsigned number_of_bernoullis_b2n,
OutputIterator out_it)
{
return boost::math::bernoulli_b2n<T, OutputIterator>(start_index, number_of_bernoullis_b2n, out_it, policies::policy<>());
}
template <class T, class Policy>
inline T tangent_t2n(const int i, const Policy &pol)
{
if(i < 0)
return policies::raise_domain_error<T>("boost::math::tangent_t2n<%1%>", "Index should be >= 0 but got %1%", T(i), pol);
T result;
boost::math::detail::get_bernoulli_numbers_cache<T, Policy>().copy_tangent_numbers(&result, i, 1, pol);
return result;
}
template <class T>
inline T tangent_t2n(const int i)
{
return boost::math::tangent_t2n<T>(i, policies::policy<>());
}
template <class T, class OutputIterator, class Policy>
inline OutputIterator tangent_t2n(const int start_index,
const unsigned number_of_tangent_t2n,
OutputIterator out_it,
const Policy& pol)
{
if(start_index < 0)
{
*out_it = policies::raise_domain_error<T>("boost::math::tangent_t2n<%1%>", "Index should be >= 0 but got %1%", T(start_index), pol);
return ++out_it;
}
return boost::math::detail::get_bernoulli_numbers_cache<T, Policy>().copy_tangent_numbers(out_it, start_index, number_of_tangent_t2n, pol);
}
template <class T, class OutputIterator>
inline OutputIterator tangent_t2n(const int start_index,
const unsigned number_of_tangent_t2n,
OutputIterator out_it)
{
return boost::math::tangent_t2n<T, OutputIterator>(start_index, number_of_tangent_t2n, out_it, policies::policy<>());
}
} } // namespace boost::math
#endif // _BOOST_BERNOULLI_B2N_2013_05_30_HPP_

View File

@@ -0,0 +1,762 @@
// Copyright (c) 2007, 2013 John Maddock
// Copyright Christopher Kormanyos 2013.
// 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 <limits>
#include <boost/math/special_functions/math_fwd.hpp>
#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_jy_zero.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>
#include <boost/math/tools/roots.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;
if(v + 3 > max_factorial<T>::value)
{
term = v * log(mult) - boost::math::lgamma(v+1+T(0.5f), Policy());
term = exp(term);
}
else
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);
}
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 v is an integer, use the integer recursion
// method, both that and Steeds method are O(v):
if((0 == v - ival))
{
return bessel_jn(ival, 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);
//
// Special case for x == 0:
//
if(x == 0)
return 0;
//
// 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) ? static_cast<T>(1) : static_cast<T>(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>() <= 113)
{
if(v == 0)
{
return bessel_i0(x);
}
if(v == 1)
{
return bessel_i1(x);
}
}
if((v > 0) && (x / v < 0.25))
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
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
if(floor(v) == v)
{
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)
{
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;
}
template <class T, class Policy>
inline T cyl_bessel_j_zero_imp(T v, int m, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names, needed for floor.
static const char* function = "boost::math::cyl_bessel_j_zero<%1%>(%1%, int)";
const T half_epsilon(boost::math::tools::epsilon<T>() / 2U);
// Handle non-finite order.
if (!(boost::math::isfinite)(v) )
{
return policies::raise_domain_error<T>(function, "Order argument is %1%, but must be finite >= 0 !", v, pol);
}
// Handle negative rank.
if(m < 0)
{
// Zeros of Jv(x) with negative rank are not defined and requesting one raises a domain error.
return policies::raise_domain_error<T>(function, "Requested the %1%'th zero, but the rank must be positive !", static_cast<T>(m), pol);
}
// Get the absolute value of the order.
const bool order_is_negative = (v < 0);
const T vv((!order_is_negative) ? v : T(-v));
// Check if the order is very close to zero or very close to an integer.
const bool order_is_zero = (vv < half_epsilon);
const bool order_is_integer = ((vv - floor(vv)) < half_epsilon);
if(m == 0)
{
if(order_is_zero)
{
// The zero'th zero of J0(x) is not defined and requesting it raises a domain error.
return policies::raise_domain_error<T>(function, "Requested the %1%'th zero of J0, but the rank must be > 0 !", static_cast<T>(m), pol);
}
// The zero'th zero of Jv(x) for v < 0 is not defined
// unless the order is a negative integer.
if(order_is_negative && (!order_is_integer))
{
// For non-integer, negative order, requesting the zero'th zero raises a domain error.
return policies::raise_domain_error<T>(function, "Requested the %1%'th zero of Jv for negative, non-integer order, but the rank must be > 0 !", static_cast<T>(m), pol);
}
// The zero'th zero does exist and its value is zero.
return T(0);
}
// Set up the initial guess for the upcoming root-finding.
// If the order is a negative integer, then use the corresponding
// positive integer for the order.
const T guess_root = boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::initial_guess<T, Policy>((order_is_integer ? vv : v), m, pol);
// Select the maximum allowed iterations from the policy.
boost::uintmax_t number_of_iterations = policies::get_max_root_iterations<Policy>();
const T delta_lo = ((guess_root > 0.2F) ? T(0.2) : T(guess_root / 2U));
// Perform the root-finding using Newton-Raphson iteration from Boost.Math.
const T jvm =
boost::math::tools::newton_raphson_iterate(
boost::math::detail::bessel_zero::cyl_bessel_j_zero_detail::function_object_jv_and_jv_prime<T, Policy>((order_is_integer ? vv : v), order_is_zero, pol),
guess_root,
T(guess_root - delta_lo),
T(guess_root + 0.2F),
policies::digits<T, Policy>(),
number_of_iterations);
if(number_of_iterations >= policies::get_max_root_iterations<Policy>())
{
return policies::raise_evaluation_error<T>(function, "Unable to locate root in a reasonable time:"
" Current best guess is %1%", jvm, Policy());
}
return jvm;
}
template <class T, class Policy>
inline T cyl_neumann_zero_imp(T v, int m, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names, needed for floor.
static const char* function = "boost::math::cyl_neumann_zero<%1%>(%1%, int)";
// Handle non-finite order.
if (!(boost::math::isfinite)(v) )
{
return policies::raise_domain_error<T>(function, "Order argument is %1%, but must be finite >= 0 !", v, pol);
}
// Handle negative rank.
if(m < 0)
{
return policies::raise_domain_error<T>(function, "Requested the %1%'th zero, but the rank must be positive !", static_cast<T>(m), pol);
}
const T half_epsilon(boost::math::tools::epsilon<T>() / 2U);
// Get the absolute value of the order.
const bool order_is_negative = (v < 0);
const T vv((!order_is_negative) ? v : T(-v));
const bool order_is_integer = ((vv - floor(vv)) < half_epsilon);
// For negative integers, use reflection to positive integer order.
if(order_is_negative && order_is_integer)
return boost::math::detail::cyl_neumann_zero_imp(vv, m, pol);
// Check if the order is very close to a negative half-integer.
const T delta_half_integer(vv - (floor(vv) + 0.5F));
const bool order_is_negative_half_integer =
(order_is_negative && ((delta_half_integer > -half_epsilon) && (delta_half_integer < +half_epsilon)));
// The zero'th zero of Yv(x) for v < 0 is not defined
// unless the order is a negative integer.
if((m == 0) && (!order_is_negative_half_integer))
{
// For non-integer, negative order, requesting the zero'th zero raises a domain error.
return policies::raise_domain_error<T>(function, "Requested the %1%'th zero of Yv for negative, non-half-integer order, but the rank must be > 0 !", static_cast<T>(m), pol);
}
// For negative half-integers, use the corresponding
// spherical Bessel function of positive half-integer order.
if(order_is_negative_half_integer)
return boost::math::detail::cyl_bessel_j_zero_imp(vv, m, pol);
// Set up the initial guess for the upcoming root-finding.
// If the order is a negative integer, then use the corresponding
// positive integer for the order.
const T guess_root = boost::math::detail::bessel_zero::cyl_neumann_zero_detail::initial_guess<T, Policy>(v, m, pol);
// Select the maximum allowed iterations from the policy.
boost::uintmax_t number_of_iterations = policies::get_max_root_iterations<Policy>();
const T delta_lo = ((guess_root > 0.2F) ? T(0.2) : T(guess_root / 2U));
// Perform the root-finding using Newton-Raphson iteration from Boost.Math.
const T yvm =
boost::math::tools::newton_raphson_iterate(
boost::math::detail::bessel_zero::cyl_neumann_zero_detail::function_object_yv_and_yv_prime<T, Policy>(v, pol),
guess_root,
T(guess_root - delta_lo),
T(guess_root + 0.2F),
policies::digits<T, Policy>(),
number_of_iterations);
if(number_of_iterations >= policies::get_max_root_iterations<Policy>())
{
return policies::raise_evaluation_error<T>(function, "Unable to locate root in a reasonable time:"
" Current best guess is %1%", yvm, Policy());
}
return yvm;
}
} // 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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_j_imp<value_type>(v, static_cast<value_type>(x), tag_type(), forwarding_policy()), "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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_bessel_j_imp<value_type>(v, static_cast<value_type>(x), forwarding_policy()), "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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_i_imp<value_type>(static_cast<value_type>(v), static_cast<value_type>(x), forwarding_policy()), "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_tag128 tag_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_k_imp<value_type>(v, static_cast<value_type>(x), tag_type(), forwarding_policy()), "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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_neumann_imp<value_type>(v, static_cast<value_type>(x), tag_type(), forwarding_policy()), "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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_neumann_imp<value_type>(v, static_cast<value_type>(x), forwarding_policy()), "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<>());
}
template <class T, class Policy>
inline typename detail::bessel_traits<T, T, Policy>::result_type cyl_bessel_j_zero(T v, int m, 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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Order must be a floating-point type.");
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_j_zero_imp<value_type>(v, m, forwarding_policy()), "boost::math::cyl_bessel_j_zero<%1%>(%1%,%1%)");
}
template <class T>
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type cyl_bessel_j_zero(T v, int m)
{
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Order must be a floating-point type.");
return cyl_bessel_j_zero<T, policies::policy<> >(v, m, policies::policy<>());
}
template <class T, class OutputIterator, class Policy>
inline OutputIterator cyl_bessel_j_zero(T v,
int start_index,
unsigned number_of_zeros,
OutputIterator out_it,
const Policy& pol)
{
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Order must be a floating-point type.");
for(int i = 0; i < static_cast<int>(number_of_zeros); ++i)
{
*out_it = boost::math::cyl_bessel_j_zero(v, start_index + i, pol);
++out_it;
}
return out_it;
}
template <class T, class OutputIterator>
inline OutputIterator cyl_bessel_j_zero(T v,
int start_index,
unsigned number_of_zeros,
OutputIterator out_it)
{
return cyl_bessel_j_zero(v, start_index, number_of_zeros, out_it, policies::policy<>());
}
template <class T, class Policy>
inline typename detail::bessel_traits<T, T, Policy>::result_type cyl_neumann_zero(T v, int m, 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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Order must be a floating-point type.");
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_neumann_zero_imp<value_type>(v, m, forwarding_policy()), "boost::math::cyl_neumann_zero<%1%>(%1%,%1%)");
}
template <class T>
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type cyl_neumann_zero(T v, int m)
{
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Order must be a floating-point type.");
return cyl_neumann_zero<T, policies::policy<> >(v, m, policies::policy<>());
}
template <class T, class OutputIterator, class Policy>
inline OutputIterator cyl_neumann_zero(T v,
int start_index,
unsigned number_of_zeros,
OutputIterator out_it,
const Policy& pol)
{
BOOST_STATIC_ASSERT_MSG( false == std::numeric_limits<T>::is_specialized
|| ( true == std::numeric_limits<T>::is_specialized
&& false == std::numeric_limits<T>::is_integer),
"Order must be a floating-point type.");
for(int i = 0; i < static_cast<int>(number_of_zeros); ++i)
{
*out_it = boost::math::cyl_neumann_zero(v, start_index + i, pol);
++out_it;
}
return out_it;
}
template <class T, class OutputIterator>
inline OutputIterator cyl_neumann_zero(T v,
int start_index,
unsigned number_of_zeros,
OutputIterator out_it)
{
return cyl_neumann_zero(v, start_index, number_of_zeros, out_it, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_BESSEL_HPP

View File

@@ -0,0 +1,359 @@
// Copyright (c) 2013 Anton Bikineev
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_MATH_BESSEL_DERIVATIVES_HPP
#define BOOST_MATH_BESSEL_DERIVATIVES_HPP
#ifdef _MSC_VER
# pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/bessel.hpp>
#include <boost/math/special_functions/detail/bessel_jy_derivatives_asym.hpp>
#include <boost/math/special_functions/detail/bessel_jy_derivatives_series.hpp>
#include <boost/math/special_functions/detail/bessel_derivatives_linear.hpp>
namespace boost{ namespace math{
namespace detail{
template <class Tag, class T, class Policy>
inline T cyl_bessel_j_prime_imp(T v, T x, const Policy& pol)
{
static const char* const function = "boost::math::cyl_bessel_j_prime<%1%>(%1%,%1%)";
BOOST_MATH_STD_USING
//
// Prevent complex result:
//
if (x < 0 && floor(v) != v)
return boost::math::policies::raise_domain_error<T>(
function,
"Got x = %1%, but function requires x >= 0", x, pol);
//
// Special cases for x == 0:
//
if (x == 0)
{
if (v == 1)
return 0.5;
else if (v == -1)
return -0.5;
else if (floor(v) == v || v > 1)
return 0;
else return boost::math::policies::raise_domain_error<T>(
function,
"Got x = %1%, but function is indeterminate for this order", x, pol);
}
//
// Special case for large x: use asymptotic expansion:
//
if (boost::math::detail::asymptotic_bessel_derivative_large_x_limit(v, x))
return boost::math::detail::asymptotic_bessel_j_derivative_large_x_2(v, x);
//
// Special case for small x: use Taylor series:
//
if ((abs(x) < 5) || (abs(v) > x * x / 4))
{
bool inversed = false;
if (floor(v) == v && v < 0)
{
v = -v;
if (itrunc(v, pol) & 1)
inversed = true;
}
T r = boost::math::detail::bessel_j_derivative_small_z_series(v, x, pol);
return inversed ? T(-r) : r;
}
//
// Special case for v == 0:
//
if (v == 0)
return -boost::math::detail::cyl_bessel_j_imp<T>(1, x, Tag(), pol);
//
// Default case:
//
return boost::math::detail::bessel_j_derivative_linear(v, x, Tag(), pol);
}
template <class T, class Policy>
inline T sph_bessel_j_prime_imp(unsigned v, T x, const Policy& pol)
{
static const char* const function = "boost::math::sph_bessel_prime<%1%>(%1%,%1%)";
//
// Prevent complex result:
//
if (x < 0)
return boost::math::policies::raise_domain_error<T>(
function,
"Got x = %1%, but function requires x >= 0.", x, pol);
//
// Special case for v == 0:
//
if (v == 0)
return (x == 0) ? boost::math::policies::raise_overflow_error<T>(function, 0, pol)
: static_cast<T>(-boost::math::detail::sph_bessel_j_imp<T>(1, x, pol));
//
// Special case for x == 0 and v > 0:
//
if (x == 0)
return boost::math::policies::raise_domain_error<T>(
function,
"Got x = %1%, but function is indeterminate for this order", x, pol);
//
// Default case:
//
return boost::math::detail::sph_bessel_j_derivative_linear(v, x, pol);
}
template <class T, class Policy>
inline T cyl_bessel_i_prime_imp(T v, T x, const Policy& pol)
{
static const char* const function = "boost::math::cyl_bessel_i_prime<%1%>(%1%,%1%)";
BOOST_MATH_STD_USING
//
// Prevent complex result:
//
if (x < 0 && floor(v) != v)
return boost::math::policies::raise_domain_error<T>(
function,
"Got x = %1%, but function requires x >= 0", x, pol);
//
// Special cases for x == 0:
//
if (x == 0)
{
if (v == 1 || v == -1)
return 0.5;
else if (floor(v) == v || v > 1)
return 0;
else return boost::math::policies::raise_domain_error<T>(
function,
"Got x = %1%, but function is indeterminate for this order", x, pol);
}
//
// Special case for v == 0:
//
if (v == 0)
return boost::math::detail::cyl_bessel_i_imp<T>(1, x, pol);
//
// Default case:
//
return boost::math::detail::bessel_i_derivative_linear(v, x, pol);
}
template <class Tag, class T, class Policy>
inline T cyl_bessel_k_prime_imp(T v, T x, const Policy& pol)
{
//
// Prevent complex and indeterminate results:
//
if (x <= 0)
return boost::math::policies::raise_domain_error<T>(
"boost::math::cyl_bessel_k_prime<%1%>(%1%,%1%)",
"Got x = %1%, but function requires x > 0", x, pol);
//
// Special case for v == 0:
//
if (v == 0)
return -boost::math::detail::cyl_bessel_k_imp<T>(1, x, Tag(), pol);
//
// Default case:
//
return boost::math::detail::bessel_k_derivative_linear(v, x, Tag(), pol);
}
template <class Tag, class T, class Policy>
inline T cyl_neumann_prime_imp(T v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING
//
// Prevent complex and indeterminate results:
//
if (x <= 0)
return boost::math::policies::raise_domain_error<T>(
"boost::math::cyl_neumann_prime<%1%>(%1%,%1%)",
"Got x = %1%, but function requires x > 0", x, pol);
//
// Special case for large x: use asymptotic expansion:
//
if (boost::math::detail::asymptotic_bessel_derivative_large_x_limit(v, x))
return boost::math::detail::asymptotic_bessel_y_derivative_large_x_2(v, x);
//
// Special case for small x: use Taylor series:
//
if (v > 0 && floor(v) != v)
{
const T eps = boost::math::policies::get_epsilon<T, Policy>();
if (log(eps / 2) > v * log((x * x) / (v * 4)))
return boost::math::detail::bessel_y_derivative_small_z_series(v, x, pol);
}
//
// Special case for v == 0:
//
if (v == 0)
return -boost::math::detail::cyl_neumann_imp<T>(1, x, Tag(), pol);
//
// Default case:
//
return boost::math::detail::bessel_y_derivative_linear(v, x, Tag(), pol);
}
template <class T, class Policy>
inline T sph_neumann_prime_imp(unsigned v, T x, const Policy& pol)
{
//
// Prevent complex and indeterminate result:
//
if (x <= 0)
return boost::math::policies::raise_domain_error<T>(
"boost::math::sph_neumann_prime<%1%>(%1%,%1%)",
"Got x = %1%, but function requires x > 0.", x, pol);
//
// Special case for v == 0:
//
if (v == 0)
return -boost::math::detail::sph_neumann_imp<T>(1, x, pol);
//
// Default case:
//
return boost::math::detail::sph_neumann_derivative_linear(v, x, pol);
}
} // namespace detail
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_j_prime(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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_j_prime_imp<tag_type, value_type>(static_cast<value_type>(v), static_cast<value_type>(x), forwarding_policy()), "boost::math::cyl_bessel_j_prime<%1%,%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_j_prime(T1 v, T2 x)
{
return cyl_bessel_j_prime(v, x, policies::policy<>());
}
template <class T, class Policy>
inline typename detail::bessel_traits<T, T, Policy>::result_type sph_bessel_prime(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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_bessel_j_prime_imp<value_type>(v, static_cast<value_type>(x), forwarding_policy()), "boost::math::sph_bessel_j_prime<%1%>(%1%,%1%)");
}
template <class T>
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_bessel_prime(unsigned v, T x)
{
return sph_bessel_prime(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_i_prime(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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_i_prime_imp<value_type>(static_cast<value_type>(v), static_cast<value_type>(x), forwarding_policy()), "boost::math::cyl_bessel_i_prime<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_i_prime(T1 v, T2 x)
{
return cyl_bessel_i_prime(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_k_prime(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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_k_prime_imp<tag_type, value_type>(static_cast<value_type>(v), static_cast<value_type>(x), forwarding_policy()), "boost::math::cyl_bessel_k_prime<%1%,%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_k_prime(T1 v, T2 x)
{
return cyl_bessel_k_prime(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_neumann_prime(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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_neumann_prime_imp<tag_type, value_type>(static_cast<value_type>(v), static_cast<value_type>(x), forwarding_policy()), "boost::math::cyl_neumann_prime<%1%,%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_neumann_prime(T1 v, T2 x)
{
return cyl_neumann_prime(v, x, policies::policy<>());
}
template <class T, class Policy>
inline typename detail::bessel_traits<T, T, Policy>::result_type sph_neumann_prime(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;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_neumann_prime_imp<value_type>(v, static_cast<value_type>(x), forwarding_policy()), "boost::math::sph_neumann_prime<%1%>(%1%,%1%)");
}
template <class T>
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_neumann_prime(unsigned v, T x)
{
return sph_neumann_prime(v, x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_BESSEL_DERIVATIVES_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,82 @@
// 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/math_fwd.hpp>
#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%.",
static_cast<T>(k), pol);
T result;
if((k == 0) || (k == n))
return static_cast<T>(1);
if((k == 1) || (k == n-1))
return static_cast<T>(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,179 @@
// (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::isinf)(z) || (z == 0))
return z;
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;
}
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,169 @@
// (C) Copyright Nick Thompson 2017.
// 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_CHEBYSHEV_HPP
#define BOOST_MATH_SPECIAL_CHEBYSHEV_HPP
#include <cmath>
#include <boost/math/constants/constants.hpp>
#if (__cplusplus > 201103) || (defined(_CPPLIB_VER) && (_CPPLIB_VER >= 610))
# define BOOST_MATH_CHEB_USE_STD_ACOSH
#endif
#ifndef BOOST_MATH_CHEB_USE_STD_ACOSH
# include <boost/math/special_functions/acosh.hpp>
#endif
namespace boost { namespace math {
template<class T1, class T2, class T3>
inline typename tools::promote_args<T1, T2, T3>::type chebyshev_next(T1 const & x, T2 const & Tn, T3 const & Tn_1)
{
return 2*x*Tn - Tn_1;
}
namespace detail {
template<class Real, bool second>
inline Real chebyshev_imp(unsigned n, Real const & x)
{
#ifdef BOOST_MATH_CHEB_USE_STD_ACOSH
using std::acosh;
#else
using boost::math::acosh;
#endif
using std::cosh;
using std::pow;
using std::sqrt;
Real T0 = 1;
Real T1;
if (second)
{
if (x > 1 || x < -1)
{
Real t = sqrt(x*x -1);
return static_cast<Real>((pow(x+t, (int)(n+1)) - pow(x-t, (int)(n+1)))/(2*t));
}
T1 = 2*x;
}
else
{
if (x > 1)
{
return cosh(n*acosh(x));
}
if (x < -1)
{
if (n & 1)
{
return -cosh(n*acosh(-x));
}
else
{
return cosh(n*acosh(-x));
}
}
T1 = x;
}
if (n == 0)
{
return T0;
}
unsigned l = 1;
while(l < n)
{
std::swap(T0, T1);
T1 = boost::math::chebyshev_next(x, T0, T1);
++l;
}
return T1;
}
} // namespace detail
template <class Real, class Policy>
inline typename tools::promote_args<Real>::type
chebyshev_t(unsigned n, Real const & x, const Policy&)
{
typedef typename tools::promote_args<Real>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::chebyshev_imp<value_type, false>(n, static_cast<value_type>(x)), "boost::math::chebyshev_t<%1%>(unsigned, %1%)");
}
template<class Real>
inline typename tools::promote_args<Real>::type chebyshev_t(unsigned n, Real const & x)
{
return chebyshev_t(n, x, policies::policy<>());
}
template <class Real, class Policy>
inline typename tools::promote_args<Real>::type
chebyshev_u(unsigned n, Real const & x, const Policy&)
{
typedef typename tools::promote_args<Real>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
return policies::checked_narrowing_cast<result_type, Policy>(detail::chebyshev_imp<value_type, true>(n, static_cast<value_type>(x)), "boost::math::chebyshev_u<%1%>(unsigned, %1%)");
}
template<class Real>
inline typename tools::promote_args<Real>::type chebyshev_u(unsigned n, Real const & x)
{
return chebyshev_u(n, x, policies::policy<>());
}
template <class Real, class Policy>
inline typename tools::promote_args<Real>::type
chebyshev_t_prime(unsigned n, Real const & x, const Policy&)
{
typedef typename tools::promote_args<Real>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
if (n == 0)
{
return result_type(0);
}
return policies::checked_narrowing_cast<result_type, Policy>(n * detail::chebyshev_imp<value_type, true>(n - 1, static_cast<value_type>(x)), "boost::math::chebyshev_t_prime<%1%>(unsigned, %1%)");
}
template<class Real>
inline typename tools::promote_args<Real>::type chebyshev_t_prime(unsigned n, Real const & x)
{
return chebyshev_t_prime(n, x, policies::policy<>());
}
/*
* This is Algorithm 3.1 of
* Gil, Amparo, Javier Segura, and Nico M. Temme.
* Numerical methods for special functions.
* Society for Industrial and Applied Mathematics, 2007.
* https://www.siam.org/books/ot99/OT99SampleChapter.pdf
* However, our definition of c0 differs by a factor of 1/2, as stated in the docs. . .
*/
template<class Real, class T2>
inline Real chebyshev_clenshaw_recurrence(const Real* const c, size_t length, const T2& x)
{
using boost::math::constants::half;
if (length < 2)
{
if (length == 0)
{
return 0;
}
return c[0]/2;
}
Real b2 = 0;
Real b1 = c[length -1];
for(size_t j = length - 2; j >= 1; --j)
{
Real tmp = 2*x*b1 - b2 + c[j];
b2 = b1;
b1 = tmp;
}
return x*b1 - b2 + half<Real>()*c[0];
}
}}
#endif

View File

@@ -0,0 +1,237 @@
// (C) Copyright Nick Thompson 2017.
// 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_CHEBYSHEV_TRANSFORM_HPP
#define BOOST_MATH_SPECIAL_CHEBYSHEV_TRANSFORM_HPP
#include <cmath>
#include <type_traits>
#include <fftw3.h>
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/chebyshev.hpp>
#ifdef BOOST_HAS_FLOAT128
#include <quadmath.h>
#endif
namespace boost { namespace math {
namespace detail{
template <class T>
struct fftw_cos_transform;
template<>
struct fftw_cos_transform<double>
{
fftw_cos_transform(int n, double* data1, double* data2)
{
plan = fftw_plan_r2r_1d(n, data1, data2, FFTW_REDFT10, FFTW_ESTIMATE);
}
~fftw_cos_transform()
{
fftw_destroy_plan(plan);
}
void execute(double* data1, double* data2)
{
fftw_execute_r2r(plan, data1, data2);
}
static double cos(double x) { return std::cos(x); }
static double fabs(double x) { return std::fabs(x); }
private:
fftw_plan plan;
};
template<>
struct fftw_cos_transform<float>
{
fftw_cos_transform(int n, float* data1, float* data2)
{
plan = fftwf_plan_r2r_1d(n, data1, data2, FFTW_REDFT10, FFTW_ESTIMATE);
}
~fftw_cos_transform()
{
fftwf_destroy_plan(plan);
}
void execute(float* data1, float* data2)
{
fftwf_execute_r2r(plan, data1, data2);
}
static float cos(float x) { return std::cos(x); }
static float fabs(float x) { return std::fabs(x); }
private:
fftwf_plan plan;
};
template<>
struct fftw_cos_transform<long double>
{
fftw_cos_transform(int n, long double* data1, long double* data2)
{
plan = fftwl_plan_r2r_1d(n, data1, data2, FFTW_REDFT10, FFTW_ESTIMATE);
}
~fftw_cos_transform()
{
fftwl_destroy_plan(plan);
}
void execute(long double* data1, long double* data2)
{
fftwl_execute_r2r(plan, data1, data2);
}
static long double cos(long double x) { return std::cos(x); }
static long double fabs(long double x) { return std::fabs(x); }
private:
fftwl_plan plan;
};
#ifdef BOOST_HAS_FLOAT128
template<>
struct fftw_cos_transform<__float128>
{
fftw_cos_transform(int n, __float128* data1, __float128* data2)
{
plan = fftwq_plan_r2r_1d(n, data1, data2, FFTW_REDFT10, FFTW_ESTIMATE);
}
~fftw_cos_transform()
{
fftwq_destroy_plan(plan);
}
void execute(__float128* data1, __float128* data2)
{
fftwq_execute_r2r(plan, data1, data2);
}
static __float128 cos(__float128 x) { return cosq(x); }
static __float128 fabs(__float128 x) { return fabsq(x); }
private:
fftwq_plan plan;
};
#endif
}
template<class Real>
class chebyshev_transform
{
public:
template<class F>
chebyshev_transform(const F& f, Real a, Real b,
Real tol = 500 * std::numeric_limits<Real>::epsilon(),
size_t max_refinements = 15) : m_a(a), m_b(b)
{
if (a >= b)
{
throw std::domain_error("a < b is required.\n");
}
using boost::math::constants::half;
using boost::math::constants::pi;
using std::cos;
using std::abs;
Real bma = (b-a)*half<Real>();
Real bpa = (b+a)*half<Real>();
size_t n = 256;
std::vector<Real> vf;
size_t refinements = 0;
while(refinements < max_refinements)
{
vf.resize(n);
m_coeffs.resize(n);
detail::fftw_cos_transform<Real> plan(static_cast<int>(n), vf.data(), m_coeffs.data());
Real inv_n = 1/static_cast<Real>(n);
for(size_t j = 0; j < n/2; ++j)
{
// Use symmetry cos((j+1/2)pi/n) = - cos((n-1-j+1/2)pi/n)
Real y = detail::fftw_cos_transform<Real>::cos(pi<Real>()*(j+half<Real>())*inv_n);
vf[j] = f(y*bma + bpa)*inv_n;
vf[n-1-j]= f(bpa-y*bma)*inv_n;
}
plan.execute(vf.data(), m_coeffs.data());
Real max_coeff = 0;
for (auto const & coeff : m_coeffs)
{
if (detail::fftw_cos_transform<Real>::fabs(coeff) > max_coeff)
{
max_coeff = detail::fftw_cos_transform<Real>::fabs(coeff);
}
}
size_t j = m_coeffs.size() - 1;
while (abs(m_coeffs[j])/max_coeff < tol)
{
--j;
}
// If ten coefficients are eliminated, the we say we've done all
// we need to do:
if (n - j > 10)
{
m_coeffs.resize(j+1);
return;
}
n *= 2;
++refinements;
}
}
Real operator()(Real x) const
{
using boost::math::constants::half;
if (x > m_b || x < m_a)
{
throw std::domain_error("x not in [a, b]\n");
}
Real z = (2*x - m_a - m_b)/(m_b - m_a);
return chebyshev_clenshaw_recurrence(m_coeffs.data(), m_coeffs.size(), z);
}
// Integral over entire domain [a, b]
Real integrate() const
{
Real Q = m_coeffs[0]/2;
for(size_t j = 2; j < m_coeffs.size(); j += 2)
{
Q += -m_coeffs[j]/((j+1)*(j-1));
}
return (m_b - m_a)*Q;
}
const std::vector<Real>& coefficients() const
{
return m_coeffs;
}
Real prime(Real x) const
{
Real z = (2*x - m_a - m_b)/(m_b - m_a);
Real dzdx = 2/(m_b - m_a);
if (m_coeffs.size() < 2)
{
return 0;
}
Real b2 = 0;
Real d2 = 0;
Real b1 = m_coeffs[m_coeffs.size() -1];
Real d1 = 0;
for(size_t j = m_coeffs.size() - 2; j >= 1; --j)
{
Real tmp1 = 2*z*b1 - b2 + m_coeffs[j];
Real tmp2 = 2*z*d1 - d2 + 2*b1;
b2 = b1;
b1 = tmp1;
d2 = d1;
d1 = tmp2;
}
return dzdx*(z*d1 - d2 + b1);
}
private:
std::vector<Real> m_coeffs;
Real m_a;
Real m_b;
};
}}
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2009 John Maddock
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_ICONV_HPP
#define BOOST_MATH_ICONV_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/round.hpp>
#include <boost/type_traits/is_convertible.hpp>
namespace boost { namespace math { namespace detail{
template <class T, class Policy>
inline int iconv_imp(T v, Policy const&, mpl::true_ const&)
{
return static_cast<int>(v);
}
template <class T, class Policy>
inline int iconv_imp(T v, Policy const& pol, mpl::false_ const&)
{
BOOST_MATH_STD_USING
return iround(v, pol);
}
template <class T, class Policy>
inline int iconv(T v, Policy const& pol)
{
typedef typename boost::is_convertible<T, int>::type tag_type;
return iconv_imp(v, pol, tag_type());
}
}}} // namespaces
#endif // BOOST_MATH_ICONV_HPP

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,93 @@
// Copyright John Maddock 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SPECIAL_ROUND_FWD_HPP
#define BOOST_MATH_SPECIAL_ROUND_FWD_HPP
#include <boost/config.hpp>
#include <boost/math/tools/promotion.hpp>
#ifdef _MSC_VER
#pragma once
#endif
namespace boost
{
namespace math
{
template <class T, class Policy>
typename tools::promote_args<T>::type trunc(const T& v, const Policy& pol);
template <class T>
typename tools::promote_args<T>::type trunc(const T& v);
template <class T, class Policy>
int itrunc(const T& v, const Policy& pol);
template <class T>
int itrunc(const T& v);
template <class T, class Policy>
long ltrunc(const T& v, const Policy& pol);
template <class T>
long ltrunc(const T& v);
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
boost::long_long_type lltrunc(const T& v, const Policy& pol);
template <class T>
boost::long_long_type lltrunc(const T& v);
#endif
template <class T, class Policy>
typename tools::promote_args<T>::type round(const T& v, const Policy& pol);
template <class T>
typename tools::promote_args<T>::type round(const T& v);
template <class T, class Policy>
int iround(const T& v, const Policy& pol);
template <class T>
int iround(const T& v);
template <class T, class Policy>
long lround(const T& v, const Policy& pol);
template <class T>
long lround(const T& v);
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
boost::long_long_type llround(const T& v, const Policy& pol);
template <class T>
boost::long_long_type llround(const T& v);
#endif
template <class T, class Policy>
T modf(const T& v, T* ipart, const Policy& pol);
template <class T>
T modf(const T& v, T* ipart);
template <class T, class Policy>
T modf(const T& v, int* ipart, const Policy& pol);
template <class T>
T modf(const T& v, int* ipart);
template <class T, class Policy>
T modf(const T& v, long* ipart, const Policy& pol);
template <class T>
T modf(const T& v, long* ipart);
#ifdef BOOST_HAS_LONG_LONG
template <class T, class Policy>
T modf(const T& v, boost::long_long_type* ipart, const Policy& pol);
template <class T>
T modf(const T& v, boost::long_long_type* ipart);
#endif
}
}
#undef BOOST_MATH_STD_USING
#define BOOST_MATH_STD_USING BOOST_MATH_STD_USING_CORE\
using boost::math::round;\
using boost::math::iround;\
using boost::math::lround;\
using boost::math::trunc;\
using boost::math::itrunc;\
using boost::math::ltrunc;\
using boost::math::modf;
#endif // BOOST_MATH_SPECIAL_ROUND_FWD_HPP

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -0,0 +1,635 @@
// (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
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/series.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>
#include <boost/math/tools/big_constant.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 mpl::int_<113>*)
{ 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_<113>*)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.003968253968253968253968253968253968253968253968254),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0041666666666666666666666666666666666666666666666667),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0075757575757575757575757575757575757575757575757576),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.021092796092796092796092796092796092796092796092796),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.44325980392156862745098039215686274509803921568627),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.0539543302701197438039543302701197438039543302701),
BOOST_MATH_BIG_CONSTANT(T, 113, -26.456212121212121212121212121212121212121212121212),
BOOST_MATH_BIG_CONSTANT(T, 113, 281.4601449275362318840579710144927536231884057971),
BOOST_MATH_BIG_CONSTANT(T, 113, -3607.510546398046398046398046398046398046398046398),
BOOST_MATH_BIG_CONSTANT(T, 113, 54827.583333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 113, -974936.82385057471264367816091954022988505747126437),
BOOST_MATH_BIG_CONSTANT(T, 113, 20052695.796688078946143462272494530559046688078946),
BOOST_MATH_BIG_CONSTANT(T, 113, -472384867.72162990196078431372549019607843137254902),
BOOST_MATH_BIG_CONSTANT(T, 113, 12635724795.916666666666666666666666666666666666667)
};
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[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.003968253968253968253968253968253968253968253968254),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0041666666666666666666666666666666666666666666666667),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0075757575757575757575757575757575757575757575757576),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.021092796092796092796092796092796092796092796092796),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.44325980392156862745098039215686274509803921568627),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.0539543302701197438039543302701197438039543302701),
BOOST_MATH_BIG_CONSTANT(T, 64, -26.456212121212121212121212121212121212121212121212),
BOOST_MATH_BIG_CONSTANT(T, 64, 281.4601449275362318840579710144927536231884057971),
};
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[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, 0.083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.0083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.003968253968253968253968253968253968253968253968254),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.0041666666666666666666666666666666666666666666666667),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.0075757575757575757575757575757575757575757575757576),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.021092796092796092796092796092796092796092796092796),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.44325980392156862745098039215686274509803921568627)
};
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[] = {
BOOST_MATH_BIG_CONSTANT(T, 24, 0.083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 24, -0.0083333333333333333333333333333333333333333333333333),
BOOST_MATH_BIG_CONSTANT(T, 24, 0.003968253968253968253968253968253968253968253968254)
};
x -= 1;
T result = log(x);
result += 1 / (2 * x);
T z = 1 / (x*x);
result -= z * tools::evaluate_polynomial(P, z);
return result;
}
//
// Fully generic asymptotic expansion in terms of Bernoulli numbers, see:
// http://functions.wolfram.com/06.14.06.0012.01
//
template <class T>
struct digamma_series_func
{
private:
int k;
T xx;
T term;
public:
digamma_series_func(T x) : k(1), xx(x * x), term(1 / (x * x)) {}
T operator()()
{
T result = term * boost::math::bernoulli_b2n<T>(k) / (2 * k);
term /= xx;
++k;
return result;
}
typedef T result_type;
};
template <class T, class Policy>
inline T digamma_imp_large(T x, const Policy& pol, const mpl::int_<0>*)
{
BOOST_MATH_STD_USING
digamma_series_func<T> s(x);
T result = log(x) - 1 / (2 * x);
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, -result);
result = -result;
policies::check_series_iterations<T>("boost::math::digamma<%1%>(%1%)", max_iter, pol);
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_<113>*)
{
//
// 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 = T(1569415565) / 1073741824uL;
static const T root2 = (T(381566830) / 1073741824uL) / 1073741824uL;
static const T root3 = ((T(111616537) / 1073741824uL) / 1073741824uL) / 1073741824uL;
static const T root4 = (((T(503992070) / 1073741824uL) / 1073741824uL) / 1073741824uL) / 1073741824uL;
static const T root5 = BOOST_MATH_BIG_CONSTANT(T, 113, 0.52112228569249997894452490385577338504019838794544e-36);
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.25479851061131551526977464225335883769),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.18684290534374944114622235683619897417),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.80360876047931768958995775910991929922),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.67227342794829064330498117008564270136),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.26569010991230617151285010695543858005),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.05775672694575986971640757748003553385),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0071432147823164975485922555833274240665),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.00048740753910766168912364555706064993274),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.16454996865214115723416538844975174761e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.20327832297631728077731148515093164955e-6)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.6210924610812025425088411043163287646),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.6850757078559596612621337395886392594),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.4320913706209965531250495490639289418),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.4410872083455009362557012239501953402),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.081385727399251729505165509278152487225),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0089478633066857163432104815183858149496),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00055861622855066424871506755481997374154),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.1760168552357342401304462967950178554e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.20585454493572473724556649516040874384e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.90745971844439990284514121823069162795e-11),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.48857673606545846774761343500033283272e-13),
};
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 = T(1569415565) / 1073741824uL;
static const T root2 = (T(381566830) / 1073741824uL) / 1073741824uL;
static const T root3 = BOOST_MATH_BIG_CONSTANT(T, 64, 0.9016312093258695918615325266959189453125e-19);
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 0.254798510611315515235),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.314628554532916496608),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.665836341559876230295),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.314767657147375752913),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.0541156266153505273939),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.00289268368333918761452)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.1195759927055347547),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.54350554664961128724),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.486986018231042975162),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0660481487173569812846),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00298999662592323990972),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.165079794012604905639e-5),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.317940243105952177571e-7)
};
T g = x - root1;
g -= root2;
g -= root3;
T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(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 = T(1569415565) / 1073741824uL;
static const T root2 = (T(381566830) / 1073741824uL) / 1073741824uL;
static const T root3 = BOOST_MATH_BIG_CONSTANT(T, 53, 0.9016312093258695918615325266959189453125e-19);
static const T P[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, 0.25479851061131551),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.32555031186804491),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.65031853770896507),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.28919126444774784),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.045251321448739056),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.0020713321167745952)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.0767117023730469),
BOOST_MATH_BIG_CONSTANT(T, 53, 1.4606242909763515),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.43593529692665969),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.054151797245674225),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.0021284987017821144),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.55789841321675513e-6)
};
T g = x - root1;
g -= root2;
g -= root3;
T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(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.25479851023250261e0f,
-0.44981331915268368e0f,
-0.43916936919946835e0f,
-0.61041765350579073e-1f
};
static const T Q[] = {
0.1e1,
0.15890202430554952e1f,
0.65341249856146947e0f,
0.63851690523355715e-1f
};
T g = x - root;
g -= root_minor;
T r = tools::evaluate_polynomial(P, T(x-1)) / tools::evaluate_polynomial(Q, T(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 <= -1)
{
// 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(x == 0)
return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", 0, x, pol);
//
// 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:
//
while(x < 1)
{
result -= 1/x;
x += 1;
}
result += digamma_imp_1_2(x, t);
}
return result;
}
template <class T, class Policy>
T digamma_imp(T x, const mpl::int_<0>* 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 <= -1)
{
// 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(x == 0)
return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", 0, x, pol);
//
// If we're above the lower-limit for the
// asymptotic expansion then use it, the
// limit is a linear interpolation with
// limit = 10 at 50 bit precision and
// limit = 250 at 1000 bit precision.
//
int lim = 10 + ((tools::digits<T>() - 50) * 240L) / 950;
T two_x = ldexp(x, 1);
if(x >= lim)
{
result += digamma_imp_large(x, pol, t);
}
else if(floor(x) == x)
{
//
// Special case for integer arguments, see
// http://functions.wolfram.com/06.14.03.0001.01
//
result = -constants::euler<T, Policy>();
T val = 1;
while(val < x)
{
result += 1 / val;
val += 1;
}
}
else if(floor(two_x) == two_x)
{
//
// Special case for half integer arguments, see:
// http://functions.wolfram.com/06.14.03.0007.01
//
result = -2 * constants::ln_two<T, Policy>() - constants::euler<T, Policy>();
int n = itrunc(x);
if(n)
{
for(int k = 1; k < n; ++k)
result += 1 / T(k);
for(int k = n; k <= 2 * n - 1; ++k)
result += 2 / T(k);
}
}
else
{
//
// Rescale so we can use the asymptotic expansion:
//
while(x < lim)
{
result -= 1 / x;
x += 1;
}
result += digamma_imp_large(x, pol, t);
}
return result;
}
//
// Initializer: ensure all our constants are initialized prior to the first call of main:
//
template <class T, class Policy>
struct digamma_initializer
{
struct init
{
init()
{
typedef typename policies::precision<T, Policy>::type precision_type;
do_init(mpl::bool_<precision_type::value && (precision_type::value <= 113)>());
}
void do_init(const mpl::true_&)
{
boost::math::digamma(T(1.5), Policy());
boost::math::digamma(T(500), Policy());
}
void do_init(const mpl::false_&){}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename digamma_initializer<T, Policy>::init digamma_initializer<T, Policy>::initializer;
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type
digamma(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<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_<114> >
>,
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>,
typename mpl::if_<
mpl::less<precision_type, mpl::int_<65> >,
mpl::int_<64>,
mpl::int_<113>
>::type
>::type
>::type
>::type tag_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
// Force initialization of constants:
detail::digamma_initializer<value_type, forwarding_policy>::force_instantiate();
return policies::checked_narrowing_cast<result_type, Policy>(detail::digamma_imp(
static_cast<value_type>(x),
static_cast<const tag_type*>(0), forwarding_policy()), "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
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif

View File

@@ -0,0 +1,201 @@
// 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/math_fwd.hpp>
#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>
#include <boost/math/special_functions/round.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::half_pi<T>()));
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
T m = boost::math::round((phi - rphi) / constants::half_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::half_pi<T>() - rphi;
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
}
T sinp = sin(rphi);
sinp *= sinp;
T cosp = cos(rphi);
cosp *= cosp;
BOOST_MATH_INSTRUMENT_VARIABLE(sinp);
BOOST_MATH_INSTRUMENT_VARIABLE(cosp);
if(sinp > tools::min_value<T>())
{
//
// Use http://dlmf.nist.gov/19.25#E5, note that
// c-1 simplifies to cot^2(rphi) which avoid cancellation:
//
T c = 1 / sinp;
result = rphi == 0 ? static_cast<T>(0) : static_cast<T>(s * ellint_rf_imp(T(cosp / sinp), T(c - k * k), c, pol));
}
else
result = s * sin(rphi);
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,191 @@
// 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/math_fwd.hpp>
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/ellint_rd.hpp>
#include <boost/math/special_functions/ellint_rg.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
#include <boost/math/special_functions/round.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 if(k == 0)
{
return invert ? T(-phi) : phi;
}
else if(fabs(k) == 1)
{
return invert ? T(-sin(phi)) : T(sin(phi));
}
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::half_pi<T>()));
T m = boost::math::round((phi - rphi) / constants::half_pi<T>());
int s = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
s = -1;
rphi = constants::half_pi<T>() - rphi;
}
T k2 = k * k;
if(k2 > 1)
{
return policies::raise_domain_error<T>("boost::math::ellint_2<%1%>(%1%, %1%)", "The parameter k is out of range, got k = %1%", k, pol);
}
else if(rphi < tools::root_epsilon<T>())
{
// See http://functions.wolfram.com/EllipticIntegrals/EllipticE2/06/01/03/0001/
result = s * rphi;
}
else
{
// http://dlmf.nist.gov/19.25#E10
T sinp = sin(rphi);
T cosp = cos(rphi);
T c = 1 / (sinp * sinp);
T cm1 = cosp * cosp / (sinp * sinp); // c - 1
result = s * ((1 - k2) * ellint_rf_imp(cm1, T(c - k2), c, pol) + k2 * (1 - k2) * ellint_rd(cm1, c, T(c - k2), pol) / 3 + k2 * sqrt(cm1 / (c * (c - k2))));
}
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 = 2 * ellint_rg_imp(x, y, z, pol);
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,376 @@
// 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/math_fwd.hpp>
#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/special_functions/atanh.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
#include <boost/math/special_functions/round.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.
BOOST_MATH_STD_USING
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));
T result = 0;
// Special cases first:
if(v == 0)
{
// A&S 17.7.18 & 19
return (k == 0) ? phi : ellint_f_imp(phi, k, pol);
}
if((v > 0) && (1 / v < (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);
}
if(v == 1)
{
// http://functions.wolfram.com/08.06.03.0008.01
T m = k * k;
result = sqrt(1 - m * sphi * sphi) * tan(phi) - ellint_e_imp(phi, k, pol);
result /= 1 - m;
result += ellint_f_imp(phi, k, pol);
return result;
}
if(phi == constants::half_pi<T>())
{
// 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((phi > constants::half_pi<T>()) || (phi < 0))
{
// 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:
//
// See http://functions.wolfram.com/08.06.16.0002.01
//
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:
//
result = 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::half_pi<T>()));
T m = boost::math::round((fabs(phi) - rphi) / constants::half_pi<T>());
int sign = 1;
if((m != 0) && (k >= 1))
{
return policies::raise_domain_error<T>(function, "Got k=1 and phi=%1% but the result is complex in that domain", phi, pol);
}
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
sign = -1;
rphi = constants::half_pi<T>() - rphi;
}
result = sign * ellint_pi_imp(v, rphi, k, vc, pol);
if((m > 0) && (vc > 0))
result += m * ellint_pi_imp(v, k, vc, pol);
}
return phi < 0 ? T(-result) : result;
}
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.
//
// Mathematica simplifies the expressions
// given in A&S as follows (with thanks to
// Rocco Romeo for figuring these out!):
//
// V = (k2 - n)/(1 - n)
// Assuming[(k2 >= 0 && k2 <= 1) && n < 0, FullSimplify[Sqrt[(1 - V)*(1 - k2 / V)] / Sqrt[((1 - n)*(1 - k2 / n))]]]
// Result: ((-1 + k2) n) / ((-1 + n) (-k2 + n))
//
// Assuming[(k2 >= 0 && k2 <= 1) && n < 0, FullSimplify[k2 / (Sqrt[-n*(k2 - n) / (1 - n)] * Sqrt[(1 - n)*(1 - k2 / n)])]]
// Result : k2 / (k2 - n)
//
// Assuming[(k2 >= 0 && k2 <= 1) && n < 0, FullSimplify[Sqrt[1 / ((1 - n)*(1 - k2 / n))]]]
// Result : Sqrt[n / ((k2 - n) (-1 + n))]
//
T k2 = k * k;
T N = (k2 - v) / (1 - v);
T Nm1 = (1 - k2) / (1 - v);
T p2 = -v * N;
T t;
if(p2 <= tools::min_value<T>())
p2 = sqrt(-v) * sqrt(N);
else
p2 = sqrt(p2);
T delta = sqrt(1 - k2 * sphi * sphi);
if(N > k2)
{
result = ellint_pi_imp(N, phi, k, Nm1, pol);
result *= v / (v - 1);
result *= (k2 - 1) / (v - k2);
}
if(k != 0)
{
t = ellint_f_imp(phi, k, pol);
t *= k2 / (k2 - v);
result += t;
}
t = v / ((k2 - v) * (v - 1));
if(t > tools::min_value<T>())
{
result += atan((p2 / 2) * sin(2 * phi) / delta) * sqrt(t);
}
else
{
result += atan((p2 / 2) * sin(2 * phi) / delta) * sqrt(fabs(1 / (k2 - v))) * sqrt(fabs(v / (v - 1)));
}
return result;
}
if(k == 1)
{
// See http://functions.wolfram.com/08.06.03.0013.01
result = sqrt(v) * atanh(sqrt(v) * sin(phi)) - log(1 / cos(phi) + tan(phi));
result /= v - 1;
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. In contrast to previous
// revisions of this header, this identity does now work
// but appears not to produce better error rates in
// practice. Archived here for future reference...
//
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:
//
result = -ellint_pi_imp(N, phi, k, Nm1, pol);
result += ellint_f_imp(phi, k, pol);
//
// 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,
// by the time we get here phi should already have been
// normalised above.
//
BOOST_ASSERT(fabs(phi) < constants::half_pi<T>());
BOOST_ASSERT(phi >= 0);
T x, y, z, p, t;
T cosp = cos(phi);
x = cosp * cosp;
t = sphi * sphi;
y = 1 - k * k * t;
z = 1;
if(v * t < 0.5)
p = 1 - v * t;
else
p = x + vc * t;
result = sphi * (ellint_rf_imp(x, y, z, pol) + v * t * ellint_rj_imp(x, y, z, p, pol) / 3);
return result;
}
// 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)
{
// Apply A&S 17.7.17:
T k2 = k * k;
T N = (k2 - v) / (1 - v);
T Nm1 = (1 - k2) / (1 - v);
T result = 0;
result = boost::math::detail::ellint_pi_imp(N, k, Nm1, pol);
// This next part is split in two to avoid spurious over/underflow:
result *= -v / (1 - v);
result *= (1 - k2) / (k2 - v);
result += ellint_k_imp(k, pol) * k2 / (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,181 @@
// 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_D_HPP
#define BOOST_MATH_ELLINT_D_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/ellint_rd.hpp>
#include <boost/math/special_functions/ellint_rg.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
#include <boost/math/special_functions/round.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_d(T1 k, T2 phi, const Policy& pol);
namespace detail{
template <typename T, typename Policy>
T ellint_d_imp(T k, const Policy& pol);
// Elliptic integral (Legendre form) of the second kind
template <typename T, typename Policy>
T ellint_d_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_d<%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_d_imp(k, pol) / constants::pi<T>();
}
else
{
// Carlson's algorithm works only for |phi| <= pi/2,
// use the integrand's periodicity to normalize phi
//
T rphi = boost::math::tools::fmod_workaround(phi, T(constants::half_pi<T>()));
T m = boost::math::round((phi - rphi) / constants::half_pi<T>());
int s = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
s = -1;
rphi = constants::half_pi<T>() - rphi;
}
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
BOOST_MATH_INSTRUMENT_VARIABLE(m);
T sinp = sin(rphi);
T cosp = cos(rphi);
BOOST_MATH_INSTRUMENT_VARIABLE(sinp);
BOOST_MATH_INSTRUMENT_VARIABLE(cosp);
T c = 1 / (sinp * sinp);
T cm1 = cosp * cosp / (sinp * sinp); // c - 1
T k2 = k * k;
if(k2 > 1)
{
return policies::raise_domain_error<T>("boost::math::ellint_d<%1%>(%1%, %1%)", "The parameter k is out of range, got k = %1%", k, pol);
}
else if(rphi == 0)
{
result = 0;
}
else
{
// http://dlmf.nist.gov/19.25#E10
result = s * ellint_rd_imp(cm1, T(c - k2), c, pol) / 3;
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
if(m != 0)
result += m * ellint_d_imp(k, pol);
}
return invert ? T(-result) : result;
}
// Complete elliptic integral (Legendre form) of the second kind
template <typename T, typename Policy>
T ellint_d_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_d<%1%>(%1%)",
"Got k = %1%, function requires |k| <= 1", k, pol);
}
if(fabs(k) <= tools::root_epsilon<T>())
return constants::pi<T>() / 4;
T x = 0;
T t = k * k;
T y = 1 - t;
T z = 1;
T value = ellint_rd_imp(x, y, z, pol) / 3;
return value;
}
template <typename T, typename Policy>
inline typename tools::promote_args<T>::type ellint_d(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_d_imp(static_cast<value_type>(k), pol), "boost::math::ellint_d<%1%>(%1%)");
}
// Elliptic integral (Legendre form) of the second kind
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type ellint_d(T1 k, T2 phi, const mpl::false_&)
{
return boost::math::ellint_d(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_d(T k)
{
return ellint_d(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_d(T1 k, T2 phi)
{
typedef typename policies::is_policy<T2>::type tag_type;
return detail::ellint_d(k, phi, tag_type());
}
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type ellint_d(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_d_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%,%1%)");
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_D_HPP

View File

@@ -0,0 +1,114 @@
// Copyright (c) 2006 Xiaogang Zhang, 2015 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 y < 0 case.
// Updated 2015 to use Carlson's latest methods.
//
#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>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/constants/constants.hpp>
#include <iostream>
// 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)
{
BOOST_MATH_STD_USING
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);
}
// for y < 0, the integral is singular, return Cauchy principal value
T prefix, result;
if(y < 0)
{
prefix = sqrt(x / (x - y));
x = x - y;
y = -y;
}
else
prefix = 1;
if(x == 0)
{
result = constants::half_pi<T>() / sqrt(y);
}
else if(x == y)
{
result = 1 / sqrt(x);
}
else if(y > x)
{
result = atan(sqrt((y - x) / x)) / sqrt(y - x);
}
else
{
if(y / x > 0.5)
{
T arg = sqrt((x - y) / x);
result = (boost::math::log1p(arg) - boost::math::log1p(-arg)) / (2 * sqrt(x - y));
}
else
{
result = log((sqrt(x) + sqrt(x - y)) / sqrt(y)) / sqrt(x - y);
}
}
return prefix * result;
}
} // 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,206 @@
// Copyright (c) 2006 Xiaogang Zhang, 2015 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 slightly to fit into the
// Boost.Math conceptual framework better.
// Updated 2015 to use Carlson's latest methods.
#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/special_functions/ellint_rc.hpp>
#include <boost/math/special_functions/pow.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)
{
BOOST_MATH_STD_USING
using std::swap;
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);
}
//
// Special cases from http://dlmf.nist.gov/19.20#iv
//
using std::swap;
if(x == z)
swap(x, y);
if(y == z)
{
if(x == y)
{
return 1 / (x * sqrt(x));
}
else if(x == 0)
{
return 3 * constants::pi<T>() / (4 * y * sqrt(y));
}
else
{
if((std::min)(x, y) / (std::max)(x, y) > 1.3)
return 3 * (ellint_rc_imp(x, y, pol) - sqrt(x) / y) / (2 * (y - x));
// Otherwise fall through to avoid cancellation in the above (RC(x,y) -> 1/x^0.5 as x -> y)
}
}
if(x == y)
{
if((std::min)(x, z) / (std::max)(x, z) > 1.3)
return 3 * (ellint_rc_imp(z, x, pol) - 1 / sqrt(z)) / (z - x);
// Otherwise fall through to avoid cancellation in the above (RC(x,y) -> 1/x^0.5 as x -> y)
}
if(y == 0)
swap(x, y);
if(x == 0)
{
//
// Special handling for common case, from
// Numerical Computation of Real or Complex Elliptic Integrals, eq.47
//
T xn = sqrt(y);
T yn = sqrt(z);
T x0 = xn;
T y0 = yn;
T sum = 0;
T sum_pow = 0.25f;
while(fabs(xn - yn) >= 2.7 * tools::root_epsilon<T>() * fabs(xn))
{
T t = sqrt(xn * yn);
xn = (xn + yn) / 2;
yn = t;
sum_pow *= 2;
sum += sum_pow * boost::math::pow<2>(xn - yn);
}
T RF = constants::pi<T>() / (xn + yn);
//
// This following calculation suffers from serious cancellation when y ~ z
// unless we combine terms. We have:
//
// ( ((x0 + y0)/2)^2 - z ) / (z(y-z))
//
// Substituting y = x0^2 and z = y0^2 and simplifying we get the following:
//
T pt = (x0 + 3 * y0) / (4 * z * (x0 + y0));
//
// Since we've moved the demoninator from eq.47 inside the expression, we
// need to also scale "sum" by the same value:
//
pt -= sum / (z * (y - z));
return pt * RF * 3;
}
T xn = x;
T yn = y;
T zn = z;
T An = (x + y + 3 * z) / 5;
T A0 = An;
// This has an extra 1.2 fudge factor which is really only needed when x, y and z are close in magnitude:
T Q = pow(tools::epsilon<T>() / 4, -T(1) / 8) * (std::max)((std::max)(An - x, An - y), An - z) * 1.2f;
BOOST_MATH_INSTRUMENT_VARIABLE(Q);
T lambda, rx, ry, rz;
unsigned k = 0;
T fn = 1;
T RD_sum = 0;
for(; k < policies::get_max_series_iterations<Policy>(); ++k)
{
rx = sqrt(xn);
ry = sqrt(yn);
rz = sqrt(zn);
lambda = rx * ry + rx * rz + ry * rz;
RD_sum += fn / (rz * (zn + lambda));
An = (An + lambda) / 4;
xn = (xn + lambda) / 4;
yn = (yn + lambda) / 4;
zn = (zn + lambda) / 4;
fn /= 4;
Q /= 4;
BOOST_MATH_INSTRUMENT_VARIABLE(k);
BOOST_MATH_INSTRUMENT_VARIABLE(RD_sum);
BOOST_MATH_INSTRUMENT_VARIABLE(Q);
if(Q < An)
break;
}
policies::check_series_iterations<T, Policy>(function, k, pol);
T X = fn * (A0 - x) / An;
T Y = fn * (A0 - y) / An;
T Z = -(X + Y) / 3;
T E2 = X * Y - 6 * Z * Z;
T E3 = (3 * X * Y - 8 * Z * Z) * Z;
T E4 = 3 * (X * Y - Z * Z) * Z * Z;
T E5 = X * Y * Z * Z * Z;
T result = fn * pow(An, T(-3) / 2) *
(1 - 3 * E2 / 14 + E3 / 6 + 9 * E2 * E2 / 88 - 3 * E4 / 22 - 9 * E2 * E3 / 52 + 3 * E5 / 26 - E2 * E2 * E2 / 16
+ 3 * E3 * E3 / 40 + 3 * E2 * E4 / 20 + 45 * E2 * E2 * E3 / 272 - 9 * (E3 * E4 + E2 * E5) / 68);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
result += 3 * RD_sum;
return result;
}
} // 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,174 @@
// Copyright (c) 2006 Xiaogang Zhang, 2015 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 handle
// types longer than 80-bit reals.
// Updated 2015 to use Carlson's latest methods.
//
#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/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/ellint_rc.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)
{
BOOST_MATH_STD_USING
using namespace boost::math;
using std::swap;
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);
}
//
// Special cases from http://dlmf.nist.gov/19.20#i
//
if(x == y)
{
if(x == z)
{
// x, y, z equal:
return 1 / sqrt(x);
}
else
{
// 2 equal, x and y:
if(z == 0)
return constants::pi<T>() / (2 * sqrt(x));
else
return ellint_rc_imp(z, x, pol);
}
}
if(x == z)
{
if(y == 0)
return constants::pi<T>() / (2 * sqrt(x));
else
return ellint_rc_imp(y, x, pol);
}
if(y == z)
{
if(x == 0)
return constants::pi<T>() / (2 * sqrt(y));
else
return ellint_rc_imp(x, y, pol);
}
if(x == 0)
swap(x, z);
else if(y == 0)
swap(y, z);
if(z == 0)
{
//
// Special case for one value zero:
//
T xn = sqrt(x);
T yn = sqrt(y);
while(fabs(xn - yn) >= 2.7 * tools::root_epsilon<T>() * fabs(xn))
{
T t = sqrt(xn * yn);
xn = (xn + yn) / 2;
yn = t;
}
return constants::pi<T>() / (xn + yn);
}
T xn = x;
T yn = y;
T zn = z;
T An = (x + y + z) / 3;
T A0 = An;
T Q = pow(3 * boost::math::tools::epsilon<T>(), T(-1) / 8) * (std::max)((std::max)(fabs(An - xn), fabs(An - yn)), fabs(An - zn));
T fn = 1;
// duplication
unsigned k = 1;
for(; k < boost::math::policies::get_max_series_iterations<Policy>(); ++k)
{
T root_x = sqrt(xn);
T root_y = sqrt(yn);
T root_z = sqrt(zn);
T lambda = root_x * root_y + root_x * root_z + root_y * root_z;
An = (An + lambda) / 4;
xn = (xn + lambda) / 4;
yn = (yn + lambda) / 4;
zn = (zn + lambda) / 4;
Q /= 4;
fn *= 4;
if(Q < fabs(An))
break;
}
// Check to see if we gave up too soon:
policies::check_series_iterations<T>(function, k, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(k);
T X = (A0 - x) / (An * fn);
T Y = (A0 - y) / (An * fn);
T Z = -X - Y;
// Taylor series expansion to the 7th order
T E2 = X * Y - Z * Z;
T E3 = X * Y * Z;
return (1 + E3 * (T(1) / 14 + 3 * E3 / 104) + E2 * (T(-1) / 10 + E2 / 24 - (3 * E3) / 44 - 5 * E2 * E2 / 208 + E2 * E3 / 16)) / sqrt(An);
}
} // 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,136 @@
// Copyright (c) 2015 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_ELLINT_RG_HPP
#define BOOST_MATH_ELLINT_RG_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/ellint_rd.hpp>
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/pow.hpp>
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rg_imp(T x, T y, T z, const Policy& pol)
{
BOOST_MATH_STD_USING
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);
}
//
// Function is symmetric in x, y and z, but we require
// (x - z)(y - z) >= 0 to avoid cancellation error in the result
// which implies (for example) x >= z >= y
//
using std::swap;
if(x < y)
swap(x, y);
if(x < z)
swap(x, z);
if(y > z)
swap(y, z);
BOOST_ASSERT(x >= z);
BOOST_ASSERT(z >= y);
//
// Special cases from http://dlmf.nist.gov/19.20#ii
//
if(x == z)
{
if(y == z)
{
// x = y = z
// This also works for x = y = z = 0 presumably.
return sqrt(x);
}
else if(y == 0)
{
// x = y, z = 0
return constants::pi<T>() * sqrt(x) / 4;
}
else
{
// x = z, y != 0
swap(x, y);
return (x == 0) ? T(sqrt(z) / 2) : T((z * ellint_rc_imp(x, z, pol) + sqrt(x)) / 2);
}
}
else if(y == z)
{
if(x == 0)
return constants::pi<T>() * sqrt(y) / 4;
else
return (y == 0) ? T(sqrt(x) / 2) : T((y * ellint_rc_imp(x, y, pol) + sqrt(x)) / 2);
}
else if(y == 0)
{
swap(y, z);
//
// Special handling for common case, from
// Numerical Computation of Real or Complex Elliptic Integrals, eq.46
//
T xn = sqrt(x);
T yn = sqrt(y);
T x0 = xn;
T y0 = yn;
T sum = 0;
T sum_pow = 0.25f;
while(fabs(xn - yn) >= 2.7 * tools::root_epsilon<T>() * fabs(xn))
{
T t = sqrt(xn * yn);
xn = (xn + yn) / 2;
yn = t;
sum_pow *= 2;
sum += sum_pow * boost::math::pow<2>(xn - yn);
}
T RF = constants::pi<T>() / (xn + yn);
return ((boost::math::pow<2>((x0 + y0) / 2) - sum) * RF) / 2;
}
return (z * ellint_rf_imp(x, y, z, pol)
- (x - z) * (y - z) * ellint_rd_imp(x, y, z, pol) / 3
+ sqrt(x * y / z)) / 2;
}
} // namespace detail
template <class T1, class T2, class T3, class Policy>
inline typename tools::promote_args<T1, T2, T3>::type
ellint_rg(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_rg_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_rg(T1 x, T2 y, T3 z)
{
return ellint_rg(x, y, z, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_RG_HPP

View File

@@ -0,0 +1,302 @@
// Copyright (c) 2006 Xiaogang Zhang, 2015 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 p < 0 case.
// Updated 2015 to use Carlson's latest methods.
//
#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>
#include <boost/math/special_functions/ellint_rd.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_rc1p_imp(T y, const Policy& pol)
{
using namespace boost::math;
// Calculate RC(1, 1 + x)
BOOST_MATH_STD_USING
static const char* function = "boost::math::ellint_rc<%1%>(%1%,%1%)";
if(y == -1)
{
return policies::raise_domain_error<T>(function,
"Argument y must not be zero but got %1%", y, pol);
}
// for 1 + y < 0, the integral is singular, return Cauchy principal value
T result;
if(y < -1)
{
result = sqrt(1 / -y) * detail::ellint_rc_imp(T(-y), T(-1 - y), pol);
}
else if(y == 0)
{
result = 1;
}
else if(y > 0)
{
result = atan(sqrt(y)) / sqrt(y);
}
else
{
if(y > -0.5)
{
T arg = sqrt(-y);
result = (boost::math::log1p(arg) - boost::math::log1p(-arg)) / (2 * sqrt(-y));
}
else
{
result = log((1 + sqrt(-y)) / sqrt(1 + y)) / sqrt(-y);
}
}
return result;
}
template <typename T, typename Policy>
T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
{
BOOST_MATH_STD_USING
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);
}
// for p < 0, the integral is singular, return Cauchy principal value
if(p < 0)
{
//
// We must ensure that x < y < z.
// 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);
BOOST_ASSERT(x <= y);
BOOST_ASSERT(y <= z);
T q = -p;
p = (z * (x + y + q) - x * y) / (z + q);
BOOST_ASSERT(p >= 0);
T value = (p - z) * ellint_rj_imp(x, y, z, p, pol);
value -= 3 * ellint_rf_imp(x, y, z, pol);
value += 3 * sqrt((x * y * z) / (x * y + p * q)) * ellint_rc_imp(T(x * y + p * q), T(p * q), pol);
value /= (z + q);
return value;
}
//
// Special cases from http://dlmf.nist.gov/19.20#iii
//
if(x == y)
{
if(x == z)
{
if(x == p)
{
// All values equal:
return 1 / (x * sqrt(x));
}
else
{
// x = y = z:
return 3 * (ellint_rc_imp(x, p, pol) - 1 / sqrt(x)) / (x - p);
}
}
else
{
// x = y only, permute so y = z:
using std::swap;
swap(x, z);
if(y == p)
{
return ellint_rd_imp(x, y, y, pol);
}
else if((std::max)(y, p) / (std::min)(y, p) > 1.2)
{
return 3 * (ellint_rc_imp(x, y, pol) - ellint_rc_imp(x, p, pol)) / (p - y);
}
// Otherwise fall through to normal method, special case above will suffer too much cancellation...
}
}
if(y == z)
{
if(y == p)
{
// y = z = p:
return ellint_rd_imp(x, y, y, pol);
}
else if((std::max)(y, p) / (std::min)(y, p) > 1.2)
{
// y = z:
return 3 * (ellint_rc_imp(x, y, pol) - ellint_rc_imp(x, p, pol)) / (p - y);
}
// Otherwise fall through to normal method, special case above will suffer too much cancellation...
}
if(z == p)
{
return ellint_rd_imp(x, y, z, pol);
}
T xn = x;
T yn = y;
T zn = z;
T pn = p;
T An = (x + y + z + 2 * p) / 5;
T A0 = An;
T delta = (p - x) * (p - y) * (p - z);
T Q = pow(tools::epsilon<T>() / 5, -T(1) / 8) * (std::max)((std::max)(fabs(An - x), fabs(An - y)), (std::max)(fabs(An - z), fabs(An - p)));
unsigned n;
T lambda;
T Dn;
T En;
T rx, ry, rz, rp;
T fmn = 1; // 4^-n
T RC_sum = 0;
for(n = 0; n < policies::get_max_series_iterations<Policy>(); ++n)
{
rx = sqrt(xn);
ry = sqrt(yn);
rz = sqrt(zn);
rp = sqrt(pn);
Dn = (rp + rx) * (rp + ry) * (rp + rz);
En = delta / Dn;
En /= Dn;
if((En < -0.5) && (En > -1.5))
{
//
// Occationally En ~ -1, we then have no means of calculating
// RC(1, 1+En) without terrible cancellation error, so we
// need to get to 1+En directly. By substitution we have
//
// 1+E_0 = 1 + (p-x)*(p-y)*(p-z)/((sqrt(p) + sqrt(x))*(sqrt(p)+sqrt(y))*(sqrt(p)+sqrt(z)))^2
// = 2*sqrt(p)*(p+sqrt(x) * (sqrt(y)+sqrt(z)) + sqrt(y)*sqrt(z)) / ((sqrt(p) + sqrt(x))*(sqrt(p) + sqrt(y)*(sqrt(p)+sqrt(z))))
//
// And since this is just an application of the duplication formula for RJ, the same
// expression works for 1+En if we use x,y,z,p_n etc.
// This branch is taken only once or twice at the start of iteration,
// after than En reverts to it's usual very small values.
//
T b = 2 * rp * (pn + rx * (ry + rz) + ry * rz) / Dn;
RC_sum += fmn / Dn * detail::ellint_rc_imp(T(1), b, pol);
}
else
{
RC_sum += fmn / Dn * ellint_rc1p_imp(En, pol);
}
lambda = rx * ry + rx * rz + ry * rz;
// From here on we move to n+1:
An = (An + lambda) / 4;
fmn /= 4;
if(fmn * Q < An)
break;
xn = (xn + lambda) / 4;
yn = (yn + lambda) / 4;
zn = (zn + lambda) / 4;
pn = (pn + lambda) / 4;
delta /= 64;
}
T X = fmn * (A0 - x) / An;
T Y = fmn * (A0 - y) / An;
T Z = fmn * (A0 - z) / An;
T P = (-X - Y - Z) / 2;
T E2 = X * Y + X * Z + Y * Z - 3 * P * P;
T E3 = X * Y * Z + 2 * E2 * P + 4 * P * P * P;
T E4 = (2 * X * Y * Z + E2 * P + 3 * P * P * P) * P;
T E5 = X * Y * Z * P * P;
T result = fmn * pow(An, T(-3) / 2) *
(1 - 3 * E2 / 14 + E3 / 6 + 9 * E2 * E2 / 88 - 3 * E4 / 22 - 9 * E2 * E3 / 52 + 3 * E5 / 26 - E2 * E2 * E2 / 16
+ 3 * E3 * E3 / 40 + 3 * E2 * E4 / 20 + 45 * E2 * E2 * E3 / 272 - 9 * (E3 * E4 + E2 * E5) / 68);
result += 6 * RC_sum;
return result;
}
} // 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,347 @@
// (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/tools/big_constant.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&);
};
template <class T, class Policy, class tag>
struct expm1_initializer
{
struct init
{
init()
{
do_init(tag());
}
template <int N>
static void do_init(const mpl::int_<N>&){}
static void do_init(const mpl::int_<64>&)
{
expm1(T(0.5));
}
static void do_init(const mpl::int_<113>&)
{
expm1(T(0.5));
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy, class tag>
const typename expm1_initializer<T, Policy, tag>::init expm1_initializer<T, Policy, tag>::initializer;
//
// 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((boost::math::isnan)(a))
{
return policies::raise_domain_error<T>("boost::math::expm1<%1%>(%1%)", "expm1 requires a finite argument, but got %1%", a, pol);
}
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[] = { static_cast<T>(-0.28127670288085937e-1), static_cast<T>(0.51278186299064534e0), static_cast<T>(-0.6310029069350198e-1), static_cast<T>(0.11638457975729296e-1), static_cast<T>(-0.52143390687521003e-3), static_cast<T>(0.21491399776965688e-4) };
static const T d[] = { 1, static_cast<T>(-0.45442309511354755e0), static_cast<T>(0.90850389570911714e-1), static_cast<T>(-0.10088963629815502e-1), static_cast<T>(0.63003407478692265e-3), static_cast<T>(-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[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.281276702880859375e-1),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.512980290285154286358e0),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.667758794592881019644e-1),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.131432469658444745835e-1),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.72303795326880286965e-3),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.447441185192951335042e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.714539134024984593011e-6)
};
static const T d[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.461477618025562520389e0),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.961237488025708540713e-1),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.116483957658204450739e-1),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.873308008461557544458e-3),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.387922804997682392562e-4),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.807473180049193557294e-6)
};
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[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.28127670288085937499999999999999999854e-1),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.51278156911210477556524452177540792214e0),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.63263178520747096729500254678819588223e-1),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.14703285606874250425508446801230572252e-1),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.8675686051689527802425310407898459386e-3),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.88126359618291165384647080266133492399e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.25963087867706310844432390015463138953e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.14226691087800461778631773363204081194e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.15995603306536496772374181066765665596e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.45261820069007790520447958280473183582e-10)
};
static const T d[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.45441264709074310514348137469214538853e0),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.96827131936192217313133611655555298106e-1),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.12745248725908178612540554584374876219e-1),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.11473613871583259821612766907781095472e-2),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.73704168477258911962046591907690764416e-4),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.34087499397791555759285503797256103259e-5),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.11114024704296196166272091230695179724e-6),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.23987051614110848595909588343223896577e-8),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.29477341859111589208776402638429026517e-10),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.13222065991022301420255904060628100924e-12)
};
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;
detail::expm1_initializer<value_type, forwarding_policy, tag_type>::force_instantiate();
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 static_cast<float>(::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,268 @@
// 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/math_fwd.hpp>
#include <boost/math/special_functions/gamma.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
#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;
if(x == 0)
{
if(n < 0)
return -boost::math::tgamma_delta_ratio(x + 1, static_cast<T>(-n), pol);
else
return 0;
}
if((x < 1) && (x + n < 0))
{
T val = boost::math::tgamma_delta_ratio(1 - x, static_cast<T>(-n), pol);
return (n & 1) ? T(-val) : val;
}
//
// 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) && (n >= 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 < 0.5f)
{
//
// 1 + x below will throw away digits, so split up calculation:
//
if(n > max_factorial<T>::value - 2)
{
// If the two end of the range are far apart we have a ratio of two very large
// numbers, split the calculation up into two blocks:
T t1 = x * boost::math::falling_factorial(x - 1, max_factorial<T>::value - 2);
T t2 = boost::math::falling_factorial(x - max_factorial<T>::value + 1, n - max_factorial<T>::value + 1);
if(tools::max_value<T>() / fabs(t1) < fabs(t2))
return boost::math::sign(t1) * boost::math::sign(t2) * policies::raise_overflow_error<T>("boost::math::falling_factorial<%1%>", 0, pol);
return t1 * t2;
}
return x * boost::math::falling_factorial(x - 1, n - 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,640 @@
// 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_MATH_USE_FLOAT128
#ifdef __has_include
#if __has_include("quadmath.h")
#include "quadmath.h"
#define BOOST_MATH_HAS_QUADMATH_H
#endif
#endif
#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{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4800)
#endif
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)
(void)t;
return false;
#else // BOOST_HAS_FPCLASSIFY
return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
#endif
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
template <class T>
inline bool is_nan_helper(T, const boost::false_type&)
{
return false;
}
#if defined(BOOST_MATH_USE_FLOAT128)
#if defined(BOOST_MATH_HAS_QUADMATH_H)
inline bool is_nan_helper(__float128 f, const boost::true_type&) { return ::isnanq(f); }
inline bool is_nan_helper(__float128 f, const boost::false_type&) { return ::isnanq(f); }
#elif defined(BOOST_GNU_STDLIB) && BOOST_GNU_STDLIB && \
_GLIBCXX_USE_C99_MATH && !_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC
inline bool is_nan_helper(__float128 f, const boost::true_type&) { return std::isnan(static_cast<double>(f)); }
inline bool is_nan_helper(__float128 f, const boost::false_type&) { return std::isnan(static_cast<double>(f)); }
#else
inline bool is_nan_helper(__float128 f, const boost::true_type&) { return ::isnan(static_cast<double>(f)); }
inline bool is_nan_helper(__float128 f, const boost::false_type&) { return ::isnan(static_cast<double>(f)); }
#endif
#endif
}
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 fpclassify_imp(t, generic_tag<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) || defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS))
inline int fpclassify_imp 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;
typedef typename tools::promote_args_permissive<T>::type value_type;
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
return detail::fpclassify_imp(static_cast<value_type>(t), method());
#else
return detail::fpclassify_imp(static_cast<value_type>(t), method());
#endif
}
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
template <>
inline int fpclassify<long double> BOOST_NO_MACRO_EXPAND(long double t)
{
typedef detail::fp_traits<long double>::type traits;
typedef traits::method method;
typedef long double value_type;
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
if(std::numeric_limits<long double>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
return detail::fpclassify_imp(static_cast<value_type>(t), detail::generic_tag<true>());
return detail::fpclassify_imp(static_cast<value_type>(t), method());
#else
return detail::fpclassify_imp(static_cast<value_type>(t), method());
#endif
}
#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, generic_tag<true>());
#endif
(void)x; // warning suppression.
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)
inline bool isfinite_impl 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;
typedef typename tools::promote_args_permissive<T>::type value_type;
return detail::isfinite_impl(static_cast<value_type>(x), method());
}
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
template<>
inline bool (isfinite)(long double x)
{ //!< \brief return true if floating-point type t is finite.
typedef detail::fp_traits<long double>::type traits;
typedef traits::method method;
//typedef boost::is_floating_point<long double>::type fp_tag;
typedef long double value_type;
return detail::isfinite_impl(static_cast<value_type>(x), method());
}
#endif
//------------------------------------------------------------------------------
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, generic_tag<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)
inline bool isnormal_impl 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;
typedef typename tools::promote_args_permissive<T>::type value_type;
return detail::isnormal_impl(static_cast<value_type>(x), method());
}
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
template<>
inline bool (isnormal)(long double x)
{
typedef detail::fp_traits<long double>::type traits;
typedef traits::method method;
//typedef boost::is_floating_point<long double>::type fp_tag;
typedef long double value_type;
return detail::isnormal_impl(static_cast<value_type>(x), method());
}
#endif
//------------------------------------------------------------------------------
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, generic_tag<true>());
#endif
(void)x; // warning suppression.
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)
inline bool isinf_impl 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;
typedef typename tools::promote_args_permissive<T>::type value_type;
return detail::isinf_impl(static_cast<value_type>(x), method());
}
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
template<>
inline bool (isinf)(long double x)
{
typedef detail::fp_traits<long double>::type traits;
typedef traits::method method;
//typedef boost::is_floating_point<long double>::type fp_tag;
typedef long double value_type;
return detail::isinf_impl(static_cast<value_type>(x), method());
}
#endif
#if defined(BOOST_MATH_USE_FLOAT128) && defined(BOOST_MATH_HAS_QUADMATH_H)
template<>
inline bool (isinf)(__float128 x)
{
return ::isinfq(x);
}
#endif
//------------------------------------------------------------------------------
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, generic_tag<true>());
#endif
(void)x; // warning suppression
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>
inline 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()); }
#elif defined(BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS)
template<>
inline bool (isnan)(long double x)
{ //!< \brief return true if floating-point type t is NaN (Not A Number).
typedef detail::fp_traits<long double>::type traits;
typedef traits::method method;
//typedef boost::is_floating_point<long double>::type fp_tag;
return detail::isnan_impl(x, method());
}
#endif
#if defined(BOOST_MATH_USE_FLOAT128) && defined(BOOST_MATH_HAS_QUADMATH_H)
template<>
inline bool (isnan)(__float128 x)
{
return ::isnanq(x);
}
#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,180 @@
// Copyright John Maddock 2012.
// 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_HANKEL_HPP
#define BOOST_MATH_HANKEL_HPP
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/bessel.hpp>
namespace boost{ namespace math{
namespace detail{
template <class T, class Policy>
std::complex<T> hankel_imp(T v, T x, const bessel_no_int_tag&, const Policy& pol, int sign)
{
BOOST_MATH_STD_USING
static const char* function = "boost::math::cyl_hankel_1<%1%>(%1%,%1%)";
if(x < 0)
{
bool isint_v = floor(v) == v;
T j, y;
bessel_jy(v, -x, &j, &y, need_j | need_y, pol);
std::complex<T> cx(x), cv(v);
std::complex<T> j_result, y_result;
if(isint_v)
{
int s = (iround(v) & 1) ? -1 : 1;
j_result = j * s;
y_result = T(s) * (y - (2 / constants::pi<T>()) * (log(-x) - log(cx)) * j);
}
else
{
j_result = pow(cx, v) * pow(-cx, -v) * j;
T p1 = pow(-x, v);
std::complex<T> p2 = pow(cx, v);
y_result = p1 * y / p2
+ (p2 / p1 - p1 / p2) * j / tan(constants::pi<T>() * v);
}
// multiply y_result by i:
y_result = std::complex<T>(-sign * y_result.imag(), sign * y_result.real());
return j_result + y_result;
}
if(x == 0)
{
if(v == 0)
{
// J is 1, Y is -INF
return std::complex<T>(1, sign * -policies::raise_overflow_error<T>(function, 0, pol));
}
else
{
// At least one of J and Y is complex infinity:
return std::complex<T>(policies::raise_overflow_error<T>(function, 0, pol), sign * policies::raise_overflow_error<T>(function, 0, pol));
}
}
T j, y;
bessel_jy(v, x, &j, &y, need_j | need_y, pol);
return std::complex<T>(j, sign * y);
}
template <class T, class Policy>
std::complex<T> hankel_imp(int v, T x, const bessel_int_tag&, const Policy& pol, int sign);
template <class T, class Policy>
inline std::complex<T> hankel_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol, int sign)
{
BOOST_MATH_STD_USING // ADL of std names.
int ival = detail::iconv(v, pol);
if(0 == v - ival)
{
return hankel_imp(ival, x, bessel_int_tag(), pol, sign);
}
return hankel_imp(v, x, bessel_no_int_tag(), pol, sign);
}
template <class T, class Policy>
inline std::complex<T> hankel_imp(int v, T x, const bessel_int_tag&, const Policy& pol, int sign)
{
BOOST_MATH_STD_USING
if((std::abs(v) < 200) && (x > 0))
return std::complex<T>(bessel_jn(v, x, pol), sign * bessel_yn(v, x, pol));
return hankel_imp(static_cast<T>(v), x, bessel_no_int_tag(), pol, sign);
}
template <class T, class Policy>
inline std::complex<T> sph_hankel_imp(T v, T x, const Policy& pol, int sign)
{
BOOST_MATH_STD_USING
return constants::root_half_pi<T>() * hankel_imp(v + 0.5f, x, bessel_no_int_tag(), pol, sign) / sqrt(std::complex<T>(x));
}
} // namespace detail
template <class T1, class T2, class Policy>
inline std::complex<typename detail::bessel_traits<T1, T2, Policy>::result_type> cyl_hankel_1(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<std::complex<result_type>, Policy>(detail::hankel_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol, 1), "boost::math::cyl_hankel_1<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline std::complex<typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type> cyl_hankel_1(T1 v, T2 x)
{
return cyl_hankel_1(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline std::complex<typename detail::bessel_traits<T1, T2, Policy>::result_type> cyl_hankel_2(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<std::complex<result_type>, Policy>(detail::hankel_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol, -1), "boost::math::cyl_hankel_1<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline std::complex<typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type> cyl_hankel_2(T1 v, T2 x)
{
return cyl_hankel_2(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline std::complex<typename detail::bessel_traits<T1, T2, Policy>::result_type> sph_hankel_1(T1 v, T2 x, const Policy&)
{
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;
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<std::complex<result_type>, Policy>(detail::sph_hankel_imp<value_type>(static_cast<value_type>(v), static_cast<value_type>(x), forwarding_policy(), 1), "boost::math::sph_hankel_1<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline std::complex<typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type> sph_hankel_1(T1 v, T2 x)
{
return sph_hankel_1(v, x, policies::policy<>());
}
template <class T1, class T2, class Policy>
inline std::complex<typename detail::bessel_traits<T1, T2, Policy>::result_type> sph_hankel_2(T1 v, T2 x, const Policy&)
{
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;
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<std::complex<result_type>, Policy>(detail::sph_hankel_imp<value_type>(static_cast<value_type>(v), static_cast<value_type>(x), forwarding_policy(), -1), "boost::math::sph_hankel_1<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline std::complex<typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type> sph_hankel_2(T1 v, T2 x)
{
return sph_hankel_2(v, x, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_HANKEL_HPP

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,87 @@
// Copyright (c) 2015 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_ELLINT_HL_HPP
#define BOOST_MATH_ELLINT_HL_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/special_functions/ellint_1.hpp>
#include <boost/math/special_functions/jacobi_zeta.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integral the Jacobi Zeta function.
namespace boost { namespace math {
namespace detail{
// Elliptic integral - Jacobi Zeta
template <typename T, typename Policy>
T heuman_lambda_imp(T phi, T k, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
const char* function = "boost::math::heuman_lambda<%1%>(%1%, %1%)";
if(fabs(k) > 1)
return policies::raise_domain_error<T>(function, "We require |k| <= 1 but got k = %1%", k, pol);
T result;
T sinp = sin(phi);
T cosp = cos(phi);
T s2 = sinp * sinp;
T k2 = k * k;
T kp = 1 - k2;
T delta = sqrt(1 - (kp * s2));
if(fabs(phi) <= constants::half_pi<T>())
{
result = kp * sinp * cosp / (delta * constants::half_pi<T>());
result *= ellint_rf_imp(T(0), kp, T(1), pol) + k2 * ellint_rj(T(0), kp, T(1), T(1 - k2 / (delta * delta)), pol) / (3 * delta * delta);
}
else
{
T rkp = sqrt(kp);
T ratio;
if(rkp == 1)
{
return policies::raise_domain_error<T>(function, "When 1-k^2 == 1 then phi must be < Pi/2, but got phi = %1%", phi, pol);
}
else
ratio = ellint_f_imp(phi, rkp, pol) / ellint_k_imp(rkp, pol);
result = ratio + ellint_k_imp(k, pol) * jacobi_zeta_imp(phi, rkp, pol) / constants::half_pi<T>();
}
return result;
}
} // detail
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type heuman_lambda(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::heuman_lambda_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::heuman_lambda<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type heuman_lambda(T1 k, T2 phi)
{
return boost::math::heuman_lambda(k, phi, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_D_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,321 @@
// Copyright John Maddock 2012.
// 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_JACOBI_ELLIPTIC_HPP
#define BOOST_MATH_JACOBI_ELLIPTIC_HPP
#include <boost/math/tools/precision.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
namespace boost{ namespace math{
namespace detail{
template <class T, class Policy>
T jacobi_recurse(const T& x, const T& k, T anm1, T bnm1, unsigned N, T* pTn, const Policy& pol)
{
BOOST_MATH_STD_USING
++N;
T Tn;
T cn = (anm1 - bnm1) / 2;
T an = (anm1 + bnm1) / 2;
if(cn < policies::get_epsilon<T, Policy>())
{
Tn = ldexp(T(1), (int)N) * x * an;
}
else
Tn = jacobi_recurse<T>(x, k, an, sqrt(anm1 * bnm1), N, 0, pol);
if(pTn)
*pTn = Tn;
return (Tn + asin((cn / an) * sin(Tn))) / 2;
}
template <class T, class Policy>
T jacobi_imp(const T& x, const T& k, T* cn, T* dn, const Policy& pol, const char* function)
{
BOOST_MATH_STD_USING
if(k < 0)
{
*cn = policies::raise_domain_error<T>(function, "Modulus k must be positive but got %1%.", k, pol);
*dn = *cn;
return *cn;
}
if(k > 1)
{
T xp = x * k;
T kp = 1 / k;
T snp, cnp, dnp;
snp = jacobi_imp(xp, kp, &cnp, &dnp, pol, function);
*cn = dnp;
*dn = cnp;
return snp * kp;
}
//
// Special cases first:
//
if(x == 0)
{
*cn = *dn = 1;
return 0;
}
if(k == 0)
{
*cn = cos(x);
*dn = 1;
return sin(x);
}
if(k == 1)
{
*cn = *dn = 1 / cosh(x);
return tanh(x);
}
//
// Asymptotic forms from A&S 16.13:
//
if(k < tools::forth_root_epsilon<T>())
{
T su = sin(x);
T cu = cos(x);
T m = k * k;
*dn = 1 - m * su * su / 2;
*cn = cu + m * (x - su * cu) * su / 4;
return su - m * (x - su * cu) * cu / 4;
}
/* Can't get this to work to adequate precision - disabled for now...
//
// Asymptotic forms from A&S 16.15:
//
if(k > 1 - tools::root_epsilon<T>())
{
T tu = tanh(x);
T su = sinh(x);
T cu = cosh(x);
T sec = 1 / cu;
T kp = 1 - k;
T m1 = 2 * kp - kp * kp;
*dn = sec + m1 * (su * cu + x) * tu * sec / 4;
*cn = sec - m1 * (su * cu - x) * tu * sec / 4;
T sn = tu;
T sn2 = m1 * (x * sec * sec - tu) / 4;
T sn3 = (72 * x * cu + 4 * (8 * x * x - 5) * su - 19 * sinh(3 * x) + sinh(5 * x)) * sec * sec * sec * m1 * m1 / 512;
return sn + sn2 - sn3;
}*/
T T1;
T kc = 1 - k;
T k_prime = k < 0.5 ? T(sqrt(1 - k * k)) : T(sqrt(2 * kc - kc * kc));
T T0 = jacobi_recurse(x, k, T(1), k_prime, 0, &T1, pol);
*cn = cos(T0);
*dn = cos(T0) / cos(T1 - T0);
return sin(T0);
}
} // namespace detail
template <class T, class U, class V, class Policy>
inline typename tools::promote_args<T, U, V>::type jacobi_elliptic(T k, U theta, V* pcn, V* pdn, const Policy&)
{
BOOST_FPU_EXCEPTION_GUARD
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;
static const char* function = "boost::math::jacobi_elliptic<%1%>(%1%)";
value_type sn, cn, dn;
sn = detail::jacobi_imp<value_type>(static_cast<value_type>(theta), static_cast<value_type>(k), &cn, &dn, forwarding_policy(), function);
if(pcn)
*pcn = policies::checked_narrowing_cast<result_type, Policy>(cn, function);
if(pdn)
*pdn = policies::checked_narrowing_cast<result_type, Policy>(dn, function);
return policies::checked_narrowing_cast<result_type, Policy>(sn, function);;
}
template <class T, class U, class V>
inline typename tools::promote_args<T, U, V>::type jacobi_elliptic(T k, U theta, V* pcn, V* pdn)
{
return jacobi_elliptic(k, theta, pcn, pdn, policies::policy<>());
}
template <class U, class T, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_sn(U k, T theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
return jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(0), static_cast<result_type*>(0), pol);
}
template <class U, class T>
inline typename tools::promote_args<T, U>::type jacobi_sn(U k, T theta)
{
return jacobi_sn(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_cn(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type cn;
jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, static_cast<result_type*>(0), pol);
return cn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_cn(T k, U theta)
{
return jacobi_cn(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_dn(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type dn;
jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(0), &dn, pol);
return dn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_dn(T k, U theta)
{
return jacobi_dn(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_cd(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type cn, dn;
jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, &dn, pol);
return cn / dn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_cd(T k, U theta)
{
return jacobi_cd(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_dc(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type cn, dn;
jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, &dn, pol);
return dn / cn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_dc(T k, U theta)
{
return jacobi_dc(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_ns(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
return 1 / jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(0), static_cast<result_type*>(0), pol);
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_ns(T k, U theta)
{
return jacobi_ns(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_sd(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type sn, dn;
sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(0), &dn, pol);
return sn / dn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_sd(T k, U theta)
{
return jacobi_sd(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_ds(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type sn, dn;
sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), static_cast<result_type*>(0), &dn, pol);
return dn / sn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_ds(T k, U theta)
{
return jacobi_ds(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_nc(T k, U theta, const Policy& pol)
{
return 1 / jacobi_cn(k, theta, pol);
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_nc(T k, U theta)
{
return jacobi_nc(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_nd(T k, U theta, const Policy& pol)
{
return 1 / jacobi_dn(k, theta, pol);
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_nd(T k, U theta)
{
return jacobi_nd(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_sc(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type sn, cn;
sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, static_cast<result_type*>(0), pol);
return sn / cn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_sc(T k, U theta)
{
return jacobi_sc(k, theta, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type jacobi_cs(T k, U theta, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
result_type sn, cn;
sn = jacobi_elliptic(static_cast<result_type>(k), static_cast<result_type>(theta), &cn, static_cast<result_type*>(0), pol);
return cn / sn;
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type jacobi_cs(T k, U theta)
{
return jacobi_cs(k, theta, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_JACOBI_ELLIPTIC_HPP

View File

@@ -0,0 +1,74 @@
// Copyright (c) 2015 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_ELLINT_JZ_HPP
#define BOOST_MATH_ELLINT_JZ_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/ellint_1.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integral the Jacobi Zeta function.
namespace boost { namespace math {
namespace detail{
// Elliptic integral - Jacobi Zeta
template <typename T, typename Policy>
T jacobi_zeta_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;
T sinp = sin(phi);
T cosp = cos(phi);
T s2 = sinp * sinp;
T k2 = k * k;
T kp = 1 - k2;
if(k == 1)
result = sinp * (boost::math::sign)(cosp); // We get here by simplifying JacobiZeta[w, 1] in Mathematica, and the fact that 0 <= phi.
else
result = k2 * sinp * cosp * sqrt(1 - k2 * s2) * ellint_rj_imp(T(0), kp, T(1), T(1 - k2 * s2), pol) / (3 * ellint_k_imp(k, pol));
return invert ? T(-result) : result;
}
} // detail
template <class T1, class T2, class Policy>
inline typename tools::promote_args<T1, T2>::type jacobi_zeta(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::jacobi_zeta_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::jacobi_zeta<%1%>(%1%,%1%)");
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type jacobi_zeta(T1 k, T2 phi)
{
return boost::math::jacobi_zeta(k, phi, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_D_HPP

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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,373 @@
// (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 <utility>
#include <vector>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/tools/roots.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;
}
template <class T, class Policy>
T legendre_p_prime_imp(unsigned l, T x, const Policy& pol, T* Pn
#ifdef BOOST_NO_CXX11_NULLPTR
= 0
#else
= nullptr
#endif
)
{
static const char* function = "boost::math::legrendre_p_prime<%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);
if (l == 0)
{
if (Pn)
{
*Pn = 1;
}
return 0;
}
T p0 = 1;
T p1 = x;
T p_prime;
bool odd = l & 1;
// If the order is odd, we sum all the even polynomials:
if (odd)
{
p_prime = p0;
}
else // Otherwise we sum the odd polynomials * (2n+1)
{
p_prime = 3*p1;
}
unsigned n = 1;
while(n < l - 1)
{
std::swap(p0, p1);
p1 = boost::math::legendre_next(n, x, p0, p1);
++n;
if (odd)
{
p_prime += (2*n+1)*p1;
odd = false;
}
else
{
odd = true;
}
}
// This allows us to evaluate the derivative and the function for the same cost.
if (Pn)
{
std::swap(p0, p1);
*Pn = boost::math::legendre_next(n, x, p0, p1);
}
return p_prime;
}
template <class T, class Policy>
struct legendre_p_zero_func
{
int n;
const Policy& pol;
legendre_p_zero_func(int n_, const Policy& p) : n(n_), pol(p) {}
std::pair<T, T> operator()(T x) const
{
T Pn;
T Pn_prime = detail::legendre_p_prime_imp(n, x, pol, &Pn);
return std::pair<T, T>(Pn, Pn_prime);
};
};
template <class T, class Policy>
std::vector<T> legendre_p_zeros_imp(int n, const Policy& pol)
{
using std::cos;
using std::sin;
using std::ceil;
using std::sqrt;
using boost::math::constants::pi;
using boost::math::constants::half;
using boost::math::tools::newton_raphson_iterate;
BOOST_ASSERT(n >= 0);
std::vector<T> zeros;
if (n == 0)
{
// There are no zeros of P_0(x) = 1.
return zeros;
}
int k;
if (n & 1)
{
zeros.resize((n-1)/2 + 1, std::numeric_limits<T>::quiet_NaN());
zeros[0] = 0;
k = 1;
}
else
{
zeros.resize(n/2, std::numeric_limits<T>::quiet_NaN());
k = 0;
}
T half_n = ceil(n*half<T>());
while (k < (int)zeros.size())
{
// Bracket the root: Szego:
// Gabriel Szego, Inequalities for the Zeros of Legendre Polynomials and Related Functions, Transactions of the American Mathematical Society, Vol. 39, No. 1 (1936)
T theta_nk = ((half_n - half<T>()*half<T>() - static_cast<T>(k))*pi<T>())/(static_cast<T>(n)+half<T>());
T lower_bound = cos( (half_n - static_cast<T>(k))*pi<T>()/static_cast<T>(n + 1));
T cos_nk = cos(theta_nk);
T upper_bound = cos_nk;
// First guess follows from:
// F. G. Tricomi, Sugli zeri dei polinomi sferici ed ultrasferici, Ann. Mat. Pura Appl., 31 (1950), pp. 93-97;
T inv_n_sq = 1/static_cast<T>(n*n);
T sin_nk = sin(theta_nk);
T x_nk_guess = (1 - inv_n_sq/static_cast<T>(8) + inv_n_sq /static_cast<T>(8*n) - (inv_n_sq*inv_n_sq/384)*(39 - 28 / (sin_nk*sin_nk) ) )*cos_nk;
boost::uintmax_t number_of_iterations = policies::get_max_root_iterations<Policy>();
legendre_p_zero_func<T, Policy> f(n, pol);
const T x_nk = newton_raphson_iterate(f, x_nk_guess,
lower_bound, upper_bound,
policies::digits<T, Policy>(),
number_of_iterations);
BOOST_ASSERT(lower_bound < x_nk);
BOOST_ASSERT(upper_bound > x_nk);
zeros[k] = x_nk;
++k;
}
return zeros;
}
} // namespace detail
template <class T, class Policy>
inline typename boost::enable_if_c<policies::is_policy<Policy>::value, typename tools::promote_args<T>::type>::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, class Policy>
inline typename boost::enable_if_c<policies::is_policy<Policy>::value, typename tools::promote_args<T>::type>::type
legendre_p_prime(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_prime<%1%>(unsigned, %1%)";
if(l < 0)
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_p_prime_imp(-l-1, static_cast<value_type>(x), pol), function);
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_p_prime_imp(l, static_cast<value_type>(x), pol), 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>
inline typename tools::promote_args<T>::type
legendre_p_prime(int l, T x)
{
return boost::math::legendre_p_prime(l, x, policies::policy<>());
}
template <class T, class Policy>
inline std::vector<T> legendre_p_zeros(int l, const Policy& pol)
{
if(l < 0)
return detail::legendre_p_zeros_imp<T>(-l-1, pol);
return detail::legendre_p_zeros_imp<T>(l, pol);
}
template <class T>
inline std::vector<T> legendre_p_zeros(int l)
{
return boost::math::legendre_p_zeros<T>(l, policies::policy<>());
}
template <class T, class Policy>
inline typename boost::enable_if_c<policies::is_policy<Policy>::value, typename tools::promote_args<T>::type>::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,235 @@
// Copyright Nick Thompson 2017.
// 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_STIELTJES_HPP
#define BOOST_MATH_SPECIAL_LEGENDRE_STIELTJES_HPP
/*
* Constructs the Legendre-Stieltjes polynomial of degree m.
* The Legendre-Stieltjes polynomials are used to create extensions for Gaussian quadratures,
* commonly called "Gauss-Konrod" quadratures.
*
* References:
* Patterson, TNL. "The optimum addition of points to quadrature formulae." Mathematics of Computation 22.104 (1968): 847-856.
*/
#include <iostream>
#include <vector>
#include <boost/math/tools/roots.hpp>
#include <boost/math/special_functions/legendre.hpp>
namespace boost{
namespace math{
template<class Real>
class legendre_stieltjes
{
public:
legendre_stieltjes(size_t m)
{
if (m == 0)
{
throw std::domain_error("The Legendre-Stieltjes polynomial is defined for order m > 0.\n");
}
m_m = static_cast<int>(m);
std::ptrdiff_t n = m - 1;
std::ptrdiff_t q;
std::ptrdiff_t r;
bool odd = n & 1;
if (odd)
{
q = 1;
r = (n-1)/2 + 2;
}
else
{
q = 0;
r = n/2 + 1;
}
m_a.resize(r + 1);
// We'll keep the ones-based indexing at the cost of storing a superfluous element
// so that we can follow Patterson's notation exactly.
m_a[r] = static_cast<Real>(1);
// Make sure using the zero index is a bug:
m_a[0] = std::numeric_limits<Real>::quiet_NaN();
for (std::ptrdiff_t k = 1; k < r; ++k)
{
Real ratio = 1;
m_a[r - k] = 0;
for (std::ptrdiff_t i = r + 1 - k; i <= r; ++i)
{
// See Patterson, equation 12
std::ptrdiff_t num = (n - q + 2*(i + k - 1))*(n + q + 2*(k - i + 1))*(n-1-q+2*(i-k))*(2*(k+i-1) -1 -q -n);
std::ptrdiff_t den = (n - q + 2*(i - k))*(2*(k + i - 1) - q - n)*(n + 1 + q + 2*(k - i))*(n - 1 - q + 2*(i + k));
ratio *= static_cast<Real>(num)/static_cast<Real>(den);
m_a[r - k] -= ratio*m_a[i];
}
}
}
Real norm_sq() const
{
Real t = 0;
bool odd = m_m & 1;
for (size_t i = 1; i < m_a.size(); ++i)
{
if(odd)
{
t += 2*m_a[i]*m_a[i]/static_cast<Real>(4*i-1);
}
else
{
t += 2*m_a[i]*m_a[i]/static_cast<Real>(4*i-3);
}
}
return t;
}
Real operator()(Real x) const
{
// Trivial implementation:
// Em += m_a[i]*legendre_p(2*i - 1, x); m odd
// Em += m_a[i]*legendre_p(2*i - 2, x); m even
size_t r = m_a.size() - 1;
Real p0 = 1;
Real p1 = x;
Real Em;
bool odd = m_m & 1;
if (odd)
{
Em = m_a[1]*p1;
}
else
{
Em = m_a[1]*p0;
}
unsigned n = 1;
for (size_t i = 2; i <= r; ++i)
{
std::swap(p0, p1);
p1 = boost::math::legendre_next(n, x, p0, p1);
++n;
if (!odd)
{
Em += m_a[i]*p1;
}
std::swap(p0, p1);
p1 = boost::math::legendre_next(n, x, p0, p1);
++n;
if(odd)
{
Em += m_a[i]*p1;
}
}
return Em;
}
Real prime(Real x) const
{
Real Em_prime = 0;
for (size_t i = 1; i < m_a.size(); ++i)
{
if(m_m & 1)
{
Em_prime += m_a[i]*detail::legendre_p_prime_imp(static_cast<unsigned>(2*i - 1), x, policies::policy<>());
}
else
{
Em_prime += m_a[i]*detail::legendre_p_prime_imp(static_cast<unsigned>(2*i - 2), x, policies::policy<>());
}
}
return Em_prime;
}
std::vector<Real> zeros() const
{
using boost::math::constants::half;
std::vector<Real> stieltjes_zeros;
std::vector<Real> legendre_zeros = legendre_p_zeros<Real>(m_m - 1);
int k;
if (m_m & 1)
{
stieltjes_zeros.resize(legendre_zeros.size() + 1, std::numeric_limits<Real>::quiet_NaN());
stieltjes_zeros[0] = 0;
k = 1;
}
else
{
stieltjes_zeros.resize(legendre_zeros.size(), std::numeric_limits<Real>::quiet_NaN());
k = 0;
}
while (k < (int)stieltjes_zeros.size())
{
Real lower_bound;
Real upper_bound;
if (m_m & 1)
{
lower_bound = legendre_zeros[k - 1];
if (k == (int)legendre_zeros.size())
{
upper_bound = 1;
}
else
{
upper_bound = legendre_zeros[k];
}
}
else
{
lower_bound = legendre_zeros[k];
if (k == (int)legendre_zeros.size() - 1)
{
upper_bound = 1;
}
else
{
upper_bound = legendre_zeros[k+1];
}
}
// The root bracketing is not very tight; to keep weird stuff from happening
// in the Newton's method, let's tighten up the tolerance using a few bisections.
boost::math::tools::eps_tolerance<Real> tol(6);
auto g = [&](Real t) { return this->operator()(t); };
auto p = boost::math::tools::bisect(g, lower_bound, upper_bound, tol);
Real x_nk_guess = p.first + (p.second - p.first)*half<Real>();
boost::uintmax_t number_of_iterations = 500;
auto f = [&] (Real x) { Real Pn = this->operator()(x);
Real Pn_prime = this->prime(x);
return std::pair<Real, Real>(Pn, Pn_prime); };
const Real x_nk = boost::math::tools::newton_raphson_iterate(f, x_nk_guess,
p.first, p.second,
2*std::numeric_limits<Real>::digits10,
number_of_iterations);
BOOST_ASSERT(p.first < x_nk);
BOOST_ASSERT(x_nk < p.second);
stieltjes_zeros[k] = x_nk;
++k;
}
return stieltjes_zeros;
}
private:
// Coefficients of Legendre expansion
std::vector<Real> m_a;
int m_m;
};
}}
#endif

View File

@@ -0,0 +1,509 @@
// (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
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#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/tools/big_constant.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) || (boost::math::isnan)(x))
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[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.807533446680736736712e-19),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.490881544804798926426e-18),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.333333333333333373941),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.17141290782087994162),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.62790522814926264694),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.13156411870766876113),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.408087379932853785336),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0706537026422828914622),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00441709903782239229447)
};
static const T Q[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.26423872346263928361),
BOOST_MATH_BIG_CONSTANT(T, 64, 7.48189472704477708962),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.94757016732904280913),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.6493508622280767304),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.06884863623790638317),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.158292216998514145947),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.00885295524069924328658),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.560026216133415663808e-6)
};
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;
}
template <class T, class Policy, class tag>
struct log1p_initializer
{
struct init
{
init()
{
do_init(tag());
}
template <int N>
static void do_init(const mpl::int_<N>&){}
static void do_init(const mpl::int_<64>&)
{
boost::math::log1p(static_cast<T>(0.25), Policy());
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy, class tag>
const typename log1p_initializer<T, Policy, tag>::init log1p_initializer<T, Policy, tag>::initializer;
} // 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;
detail::log1p_initializer<value_type, forwarding_policy, tag_type>::force_instantiate();
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
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // BOOST_MATH_LOG1P_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
// 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/special_functions/math_fwd.hpp>
#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,858 @@
// (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/special_functions/math_fwd.hpp>
#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>
#include <float.h>
#if !defined(_CRAYC) && !defined(__CUDACC__) && (!defined(__GNUC__) || (__GNUC__ > 3) || ((__GNUC__ == 3) && (__GNUC_MINOR__ > 3)))
#if (defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) || defined(__SSE2__)
#include "xmmintrin.h"
#define BOOST_MATH_CHECK_SSE2
#endif
#endif
namespace boost{ namespace math{
namespace concepts {
class real_concept;
class std_real_concept;
}
namespace detail{
template <class T>
struct has_hidden_guard_digits;
template <>
struct has_hidden_guard_digits<float> : public mpl::false_ {};
template <>
struct has_hidden_guard_digits<double> : public mpl::false_ {};
template <>
struct has_hidden_guard_digits<long double> : public mpl::false_ {};
#ifdef BOOST_HAS_FLOAT128
template <>
struct has_hidden_guard_digits<__float128> : public mpl::false_ {};
#endif
template <>
struct has_hidden_guard_digits<boost::math::concepts::real_concept> : public mpl::false_ {};
template <>
struct has_hidden_guard_digits<boost::math::concepts::std_real_concept> : public mpl::false_ {};
template <class T, bool b>
struct has_hidden_guard_digits_10 : public mpl::false_ {};
template <class T>
struct has_hidden_guard_digits_10<T, true> : public mpl::bool_<(std::numeric_limits<T>::digits10 != std::numeric_limits<T>::max_digits10)> {};
template <class T>
struct has_hidden_guard_digits
: public has_hidden_guard_digits_10<T,
std::numeric_limits<T>::is_specialized
&& (std::numeric_limits<T>::radix == 10) >
{};
template <class T>
inline const T& normalize_value(const T& val, const mpl::false_&) { return val; }
template <class T>
inline T normalize_value(const T& val, const mpl::true_&)
{
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized);
BOOST_STATIC_ASSERT(std::numeric_limits<T>::radix != 2);
boost::intmax_t shift = (boost::intmax_t)std::numeric_limits<T>::digits - (boost::intmax_t)ilogb(val) - 1;
T result = scalbn(val, shift);
result = round(result);
return scalbn(result, -shift);
}
template <class T>
inline T get_smallest_value(mpl::true_ const&)
{
//
// numeric_limits lies about denorms being present - particularly
// when this can be turned on or off at runtime, as is the case
// when using the SSE2 registers in DAZ or FTZ mode.
//
static const T m = std::numeric_limits<T>::denorm_min();
#ifdef BOOST_MATH_CHECK_SSE2
return (_mm_getcsr() & (_MM_FLUSH_ZERO_ON | 0x40)) ? tools::min_value<T>() : m;;
#else
return ((tools::min_value<T>() / 2) == 0) ? tools::min_value<T>() : m;
#endif
}
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
}
//
// Returns the smallest value that won't generate denorms when
// we calculate the value of the least-significant-bit:
//
template <class T>
T get_min_shift_value();
template <class T>
struct min_shift_initializer
{
struct init
{
init()
{
do_init();
}
static void do_init()
{
get_min_shift_value<T>();
}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T>
const typename min_shift_initializer<T>::init min_shift_initializer<T>::initializer;
template <class T>
inline T calc_min_shifted(const mpl::true_&)
{
BOOST_MATH_STD_USING
return ldexp(tools::min_value<T>(), tools::digits<T>() + 1);
}
template <class T>
inline T calc_min_shifted(const mpl::false_&)
{
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized);
BOOST_STATIC_ASSERT(std::numeric_limits<T>::radix != 2);
return scalbn(tools::min_value<T>(), std::numeric_limits<T>::digits + 1);
}
template <class T>
inline T get_min_shift_value()
{
static const T val = calc_min_shifted<T>(mpl::bool_<!std::numeric_limits<T>::is_specialized || std::numeric_limits<T>::radix == 2>());
min_shift_initializer<T>::force_instantiate();
return val;
}
template <class T, class Policy>
T float_next_imp(const T& val, const mpl::true_&, const Policy& pol)
{
BOOST_MATH_STD_USING
int expon;
static const char* function = "float_next<%1%>(%1%)";
int fpclass = (boost::math::fpclassify)(val);
if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
{
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((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != -tools::min_value<T>()))
{
//
// Special case: if the value of the least significant bit is a denorm, and the result
// would not be a denorm, then shift the input, increment, and shift back.
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
//
return ldexp(float_next(T(ldexp(val, 2 * tools::digits<T>())), pol), -2 * tools::digits<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;
} // float_next_imp
//
// Special version for some base other than 2:
//
template <class T, class Policy>
T float_next_imp(const T& val, const mpl::false_&, const Policy& pol)
{
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized);
BOOST_STATIC_ASSERT(std::numeric_limits<T>::radix != 2);
BOOST_MATH_STD_USING
boost::intmax_t expon;
static const char* function = "float_next<%1%>(%1%)";
int fpclass = (boost::math::fpclassify)(val);
if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
{
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((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != -tools::min_value<T>()))
{
//
// Special case: if the value of the least significant bit is a denorm, and the result
// would not be a denorm, then shift the input, increment, and shift back.
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
//
return scalbn(float_next(T(scalbn(val, 2 * std::numeric_limits<T>::digits)), pol), -2 * std::numeric_limits<T>::digits);
}
expon = 1 + ilogb(val);
if(-1 == scalbn(val, -expon) * std::numeric_limits<T>::radix)
--expon; // reduce exponent when val is a power of base, and negative.
T diff = scalbn(T(1), expon - std::numeric_limits<T>::digits);
if(diff == 0)
diff = detail::get_smallest_value<T>();
return val + diff;
} // float_next_imp
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type float_next(const T& val, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
return detail::float_next_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), mpl::bool_<!std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
}
#if 0 //def BOOST_MSVC
//
// We used to use ::_nextafter here, but doing so fails when using
// the SSE2 registers if the FTZ or DAZ flags are set, so use our own
// - albeit slower - code instead as at least that gives the correct answer.
//
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 typename tools::promote_args<T>::type float_next(const T& val)
{
return float_next(val, policies::policy<>());
}
namespace detail{
template <class T, class Policy>
T float_prior_imp(const T& val, const mpl::true_&, const Policy& pol)
{
BOOST_MATH_STD_USING
int expon;
static const char* function = "float_prior<%1%>(%1%)";
int fpclass = (boost::math::fpclassify)(val);
if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
{
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((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != tools::min_value<T>()))
{
//
// Special case: if the value of the least significant bit is a denorm, and the result
// would not be a denorm, then shift the input, increment, and shift back.
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
//
return ldexp(float_prior(T(ldexp(val, 2 * tools::digits<T>())), pol), -2 * tools::digits<T>());
}
T remain = frexp(val, &expon);
if(remain == 0.5f)
--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;
} // float_prior_imp
//
// Special version for bases other than 2:
//
template <class T, class Policy>
T float_prior_imp(const T& val, const mpl::false_&, const Policy& pol)
{
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized);
BOOST_STATIC_ASSERT(std::numeric_limits<T>::radix != 2);
BOOST_MATH_STD_USING
boost::intmax_t expon;
static const char* function = "float_prior<%1%>(%1%)";
int fpclass = (boost::math::fpclassify)(val);
if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
{
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((fpclass != (int)FP_SUBNORMAL) && (fpclass != (int)FP_ZERO) && (fabs(val) < detail::get_min_shift_value<T>()) && (val != tools::min_value<T>()))
{
//
// Special case: if the value of the least significant bit is a denorm, and the result
// would not be a denorm, then shift the input, increment, and shift back.
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
//
return scalbn(float_prior(T(scalbn(val, 2 * std::numeric_limits<T>::digits)), pol), -2 * std::numeric_limits<T>::digits);
}
expon = 1 + ilogb(val);
T remain = scalbn(val, -expon);
if(remain * std::numeric_limits<T>::radix == 1)
--expon; // when val is a power of two we must reduce the exponent
T diff = scalbn(T(1), expon - std::numeric_limits<T>::digits);
if(diff == 0)
diff = detail::get_smallest_value<T>();
return val - diff;
} // float_prior_imp
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type float_prior(const T& val, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
return detail::float_prior_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), mpl::bool_<!std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
}
#if 0 //def BOOST_MSVC
//
// We used to use ::_nextafter here, but doing so fails when using
// the SSE2 registers if the FTZ or DAZ flags are set, so use our own
// - albeit slower - code instead as at least that gives the correct answer.
//
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 typename tools::promote_args<T>::type float_prior(const T& val)
{
return float_prior(val, policies::policy<>());
}
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type nextafter(const T& val, const U& direction, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
return val < direction ? boost::math::float_next<result_type>(val, pol) : val == direction ? val : boost::math::float_prior<result_type>(val, pol);
}
template <class T, class U>
inline typename tools::promote_args<T, U>::type nextafter(const T& val, const U& direction)
{
return nextafter(val, direction, policies::policy<>());
}
namespace detail{
template <class T, class Policy>
T float_distance_imp(const T& a, const T& b, const mpl::true_&, 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, pol);
if(a == b)
return T(0);
if(a == 0)
return 1 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol));
if(b == 0)
return 1 + fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), a, pol));
if(boost::math::sign(a) != boost::math::sign(b))
return 2 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol))
+ fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : 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), pol);
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) == (int)FP_SUBNORMAL) ? tools::min_value<T>() : a, &expon);
T upper = ldexp(T(1), expon);
T result = T(0);
//
// 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)
{
int expon2;
frexp(b, &expon2);
T upper2 = ldexp(T(0.5), expon2);
result = float_distance(upper2, b);
result += (expon2 - expon - 1) * ldexp(T(1), tools::digits<T>() - 1);
}
//
// Use compensated double-double addition to avoid rounding
// errors in the subtraction:
//
expon = tools::digits<T>() - expon;
T mb, x, y, z;
if(((boost::math::fpclassify)(a) == (int)FP_SUBNORMAL) || (b - a < tools::min_value<T>()))
{
//
// Special case - either one end of the range is a denormal, or else the difference is.
// The regular code will fail if we're using the SSE2 registers on Intel and either
// the FTZ or DAZ flags are set.
//
T a2 = ldexp(a, tools::digits<T>());
T b2 = ldexp(b, tools::digits<T>());
mb = -(std::min)(T(ldexp(upper, tools::digits<T>())), b2);
x = a2 + mb;
z = x - a2;
y = (a2 - (x - z)) + (mb - z);
expon -= tools::digits<T>();
}
else
{
mb = -(std::min)(upper, b);
x = a + mb;
z = x - a;
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;
} // float_distance_imp
//
// Special versions for bases other than 2:
//
template <class T, class Policy>
T float_distance_imp(const T& a, const T& b, const mpl::false_&, const Policy& pol)
{
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized);
BOOST_STATIC_ASSERT(std::numeric_limits<T>::radix != 2);
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, pol);
if(a == b)
return T(0);
if(a == 0)
return 1 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol));
if(b == 0)
return 1 + fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), a, pol));
if(boost::math::sign(a) != boost::math::sign(b))
return 2 + fabs(float_distance(static_cast<T>((b < 0) ? T(-detail::get_smallest_value<T>()) : detail::get_smallest_value<T>()), b, pol))
+ fabs(float_distance(static_cast<T>((a < 0) ? T(-detail::get_smallest_value<T>()) : 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), pol);
BOOST_ASSERT(a >= 0);
BOOST_ASSERT(b >= a);
boost::intmax_t 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:
//
expon = 1 + ilogb(((boost::math::fpclassify)(a) == (int)FP_SUBNORMAL) ? tools::min_value<T>() : a);
T upper = scalbn(T(1), expon);
T result = T(0);
//
// 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)
{
boost::intmax_t expon2 = 1 + ilogb(b);
T upper2 = scalbn(T(1), expon2 - 1);
result = float_distance(upper2, b);
result += (expon2 - expon - 1) * scalbn(T(1), std::numeric_limits<T>::digits - 1);
}
//
// Use compensated double-double addition to avoid rounding
// errors in the subtraction:
//
expon = std::numeric_limits<T>::digits - expon;
T mb, x, y, z;
if(((boost::math::fpclassify)(a) == (int)FP_SUBNORMAL) || (b - a < tools::min_value<T>()))
{
//
// Special case - either one end of the range is a denormal, or else the difference is.
// The regular code will fail if we're using the SSE2 registers on Intel and either
// the FTZ or DAZ flags are set.
//
T a2 = scalbn(a, std::numeric_limits<T>::digits);
T b2 = scalbn(b, std::numeric_limits<T>::digits);
mb = -(std::min)(T(scalbn(upper, std::numeric_limits<T>::digits)), b2);
x = a2 + mb;
z = x - a2;
y = (a2 - (x - z)) + (mb - z);
expon -= std::numeric_limits<T>::digits;
}
else
{
mb = -(std::min)(upper, b);
x = a + mb;
z = x - a;
y = (a - (x - z)) + (mb - z);
}
if(x < 0)
{
x = -x;
y = -y;
}
result += scalbn(x, expon) + scalbn(y, expon);
//
// Result must be an integer:
//
BOOST_ASSERT(result == floor(result));
return result;
} // float_distance_imp
} // namespace detail
template <class T, class U, class Policy>
inline typename tools::promote_args<T, U>::type float_distance(const T& a, const U& b, const Policy& pol)
{
typedef typename tools::promote_args<T, U>::type result_type;
return detail::float_distance_imp(detail::normalize_value(static_cast<result_type>(a), typename detail::has_hidden_guard_digits<result_type>::type()), detail::normalize_value(static_cast<result_type>(b), typename detail::has_hidden_guard_digits<result_type>::type()), mpl::bool_<!std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
}
template <class T, class U>
typename tools::promote_args<T, U>::type float_distance(const T& a, const U& b)
{
return boost::math::float_distance(a, b, policies::policy<>());
}
namespace detail{
template <class T, class Policy>
T float_advance_imp(T val, int distance, const mpl::true_&, const Policy& pol)
{
BOOST_MATH_STD_USING
//
// Error handling:
//
static const char* function = "float_advance<%1%>(%1%, int)";
int fpclass = (boost::math::fpclassify)(val);
if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
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);
if(fabs(val) < detail::get_min_shift_value<T>())
{
//
// Special case: if the value of the least significant bit is a denorm,
// implement in terms of float_next/float_prior.
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
//
if(distance > 0)
{
do{ val = float_next(val, pol); } while(--distance);
}
else
{
do{ val = float_prior(val, pol); } while(++distance);
}
return val;
}
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(distance && (limit_distance == 0))
{
return policies::raise_evaluation_error<T>(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol);
}
}
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;
} // float_advance_imp
//
// Special version for bases other than 2:
//
template <class T, class Policy>
T float_advance_imp(T val, int distance, const mpl::false_&, const Policy& pol)
{
BOOST_STATIC_ASSERT(std::numeric_limits<T>::is_specialized);
BOOST_STATIC_ASSERT(std::numeric_limits<T>::radix != 2);
BOOST_MATH_STD_USING
//
// Error handling:
//
static const char* function = "float_advance<%1%>(%1%, int)";
int fpclass = (boost::math::fpclassify)(val);
if((fpclass == (int)FP_NAN) || (fpclass == (int)FP_INFINITE))
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);
if(fabs(val) < detail::get_min_shift_value<T>())
{
//
// Special case: if the value of the least significant bit is a denorm,
// implement in terms of float_next/float_prior.
// This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
//
if(distance > 0)
{
do{ val = float_next(val, pol); } while(--distance);
}
else
{
do{ val = float_prior(val, pol); } while(++distance);
}
return val;
}
boost::intmax_t expon = 1 + ilogb(val);
T limit = scalbn(T(1), distance < 0 ? expon - 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 /= std::numeric_limits<T>::radix;
expon--;
}
else
{
limit *= std::numeric_limits<T>::radix;
expon++;
}
limit_distance = float_distance(val, limit);
if(distance && (limit_distance == 0))
{
return policies::raise_evaluation_error<T>(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol);
}
}
/*expon = 1 + ilogb(val);
if((1 == scalbn(val, 1 + expon)) && (distance < 0))
--expon;*/
T diff = 0;
if(val != 0)
diff = distance * scalbn(T(1), expon - std::numeric_limits<T>::digits);
if(diff == 0)
diff = distance * detail::get_smallest_value<T>();
return val += diff;
} // float_advance_imp
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type float_advance(T val, int distance, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
return detail::float_advance_imp(detail::normalize_value(static_cast<result_type>(val), typename detail::has_hidden_guard_digits<result_type>::type()), distance, mpl::bool_<!std::numeric_limits<result_type>::is_specialized || (std::numeric_limits<result_type>::radix == 2)>(), pol);
}
template <class T>
inline typename tools::promote_args<T>::type float_advance(const T& val, int distance)
{
return boost::math::float_advance(val, distance, policies::policy<>());
}
}} // boost math namespaces
#endif // BOOST_MATH_SPECIAL_NEXT_HPP

View File

@@ -0,0 +1,593 @@
#ifndef BOOST_MATH_NONFINITE_NUM_FACETS_HPP
#define BOOST_MATH_NONFINITE_NUM_FACETS_HPP
// Copyright 2006 Johan Rade
// Copyright 2012 K R Walker
// Copyright 2011, 2012 Paul A. Bristow
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
/*
\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/throw_exception.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.
#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
{
static const CharType prefix_plus[2] = { '+', '\0' };
static const CharType prefix_minus[2] = { '-', '\0' };
static const CharType body_inf[4] = { 'i', 'n', 'f', '\0' };
static const CharType body_nan[4] = { 'n', 'a', 'n', '\0' };
static const CharType* null_string = 0;
switch((boost::math::fpclassify)(val))
{
case FP_INFINITE:
if(flags_ & trap_infinity)
{
BOOST_THROW_EXCEPTION(std::ios_base::failure("Infinity"));
}
else if((boost::math::signbit)(val))
{ // negative infinity.
put_num_and_fill(it, iosb, prefix_minus, body_inf, fill, val);
}
else if(iosb.flags() & std::ios_base::showpos)
{ // Explicit "+inf" wanted.
put_num_and_fill(it, iosb, prefix_plus, body_inf, fill, val);
}
else
{ // just "inf" wanted.
put_num_and_fill(it, iosb, null_string, body_inf, fill, val);
}
break;
case FP_NAN:
if(flags_ & trap_nan)
{
BOOST_THROW_EXCEPTION(std::ios_base::failure("NaN"));
}
else if((boost::math::signbit)(val))
{ // negative so "-nan".
put_num_and_fill(it, iosb, prefix_minus, body_nan, fill, val);
}
else if(iosb.flags() & std::ios_base::showpos)
{ // explicit "+nan" wanted.
put_num_and_fill(it, iosb, prefix_plus, body_nan, fill, val);
}
else
{ // Just "nan".
put_num_and_fill(it, iosb, null_string, body_nan, fill, val);
}
break;
case FP_ZERO:
if((flags_ & signed_zero) && ((boost::math::signbit)(val)))
{ // Flag set to distinguish between positive and negative zero.
// But string "0" should have stuff after decimal point if setprecision and/or exp format.
std::basic_ostringstream<CharType> zeros; // Needs to be CharType version.
// Copy flags, fill, width and precision.
zeros.flags(iosb.flags());
zeros.unsetf(std::ios::showpos); // Ignore showpos because must be negative.
zeros.precision(iosb.precision());
//zeros.width is set by put_num_and_fill
zeros.fill(static_cast<char>(fill));
zeros << ValType(0);
put_num_and_fill(it, iosb, prefix_minus, zeros.str().c_str(), fill, val);
}
else
{ // Output the platform default for positive and negative zero.
put_num_and_fill(it, iosb, null_string, null_string, fill, val);
}
break;
default: // Normal non-zero finite value.
it = std::num_put<CharType, OutputIterator>::do_put(it, iosb, fill, val);
break;
}
}
template<class ValType>
void put_num_and_fill(
OutputIterator& it, std::ios_base& iosb, const CharType* prefix,
const CharType* body, CharType fill, ValType val) const
{
int prefix_length = prefix ? (int)std::char_traits<CharType>::length(prefix) : 0;
int body_length = body ? (int)std::char_traits<CharType>::length(body) : 0;
int width = prefix_length + body_length;
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(body || prefix)
{ // adjust == std::ios_base::right, so leading fill needed.
if(adjust != std::ios_base::internal && adjust != std::ios_base::left)
put_fill(it, iosb, fill, width);
}
if(prefix)
{ // Adjust width for prefix.
while(*prefix)
*it = *(prefix++);
iosb.width( iosb.width() - prefix_length );
width -= prefix_length;
}
if(body)
{ //
if(adjust == std::ios_base::internal)
{ // Put fill between sign and digits.
put_fill(it, iosb, fill, width);
}
if(iosb.flags() & std::ios_base::uppercase)
{
while(*body)
*it = ct.toupper(*(body++));
}
else
{
while(*body)
*it = *(body++);
}
if(adjust == std::ios_base::left)
put_fill(it, iosb, fill, width);
}
else
{
it = std::num_put<CharType, OutputIterator>::do_put(it, iosb, fill, val);
}
}
void put_fill(
OutputIterator& it, std::ios_base& iosb, CharType fill, int width) const
{ // Insert fill chars.
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 // BOOST_MATH_NONFINITE_NUM_FACETS_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright 2013 Nikhar Agrawal
// Copyright 2013 Christopher Kormanyos
// Copyright 2014 John Maddock
// Copyright 2013 Paul Bristow
// Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef _BOOST_POLYGAMMA_2013_07_30_HPP_
#define _BOOST_POLYGAMMA_2013_07_30_HPP_
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/detail/polygamma.hpp>
#include <boost/math/special_functions/trigamma.hpp>
namespace boost { namespace math {
template<class T, class Policy>
inline typename tools::promote_args<T>::type polygamma(const int n, T x, const Policy& pol)
{
//
// Filter off special cases right at the start:
//
if(n == 0)
return boost::math::digamma(x, pol);
if(n == 1)
return boost::math::trigamma(x, pol);
//
// We've found some standard library functions to misbehave if any FPU exception flags
// are set prior to their call, this code will clear those flags, then reset them
// on exit:
//
BOOST_FPU_EXCEPTION_GUARD
//
// The type of the result - the common type of T and U after
// any integer types have been promoted to double:
//
typedef typename tools::promote_args<T>::type result_type;
//
// The type used for the calculation. This may be a wider type than
// the result in order to ensure full precision:
//
typedef typename policies::evaluation<result_type, Policy>::type value_type;
//
// The type of the policy to forward to the actual implementation.
// We disable promotion of float and double as that's [possibly]
// happened already in the line above. Also reset to the default
// any policies we don't use (reduces code bloat if we're called
// multiple times with differing policies we don't actually use).
// Also normalise the type, again to reduce code bloat in case we're
// called multiple times with functionally identical policies that happen
// to be different types.
//
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
//
// Whew. Now we can make the actual call to the implementation.
// Arguments are explicitly cast to the evaluation type, and the result
// passed through checked_narrowing_cast which handles things like overflow
// according to the policy passed:
//
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::polygamma_imp(n, static_cast<value_type>(x), forwarding_policy()),
"boost::math::polygamma<%1%>(int, %1%)");
}
template<class T>
inline typename tools::promote_args<T>::type polygamma(const int n, T x)
{
return boost::math::polygamma(n, x, policies::policy<>());
}
} } // namespace boost::math
#endif // _BOOST_BERNOULLI_2013_05_30_HPP_

View File

@@ -0,0 +1,148 @@
// 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/special_functions/math_fwd.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 {
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code, only triggered in release mode and /W4
#endif
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<>()); }
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,84 @@
// (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
#pragma warning(push)
#pragma warning(disable:4702) // Unreachable code (release mode only warning)
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/assert.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
inline T powm1_imp(const T x, const T y, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* function = "boost::math::powm1<%1%>(%1%, %1%)";
if (x > 0)
{
if ((fabs(y * (x - 1)) < 0.5) || (fabs(y) < 0.2))
{
// We don't have any good/quick approximation for log(x) * y
// so just try it and see:
T l = y * log(x);
if (l < 0.5)
return boost::math::expm1(l);
if (l > boost::math::tools::log_max_value<T>())
return boost::math::policies::raise_overflow_error<T>(function, 0, pol);
// fall through....
}
}
else
{
// y had better be an integer:
if (boost::math::trunc(y) != y)
return boost::math::policies::raise_domain_error<T>(function, "For non-integral exponent, expected base > 0 but got %1%", x, pol);
if (boost::math::trunc(y / 2) == y / 2)
return powm1_imp(T(-x), y, pol);
}
return pow(x, y) - 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
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // BOOST_MATH_POWM1

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,134 @@
// (C) Copyright John Maddock 2006, 2015
// 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_RELATIVE_ERROR
#define BOOST_MATH_RELATIVE_ERROR
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/tools/precision.hpp>
namespace boost{
namespace math{
template <class T, class U>
typename boost::math::tools::promote_args<T,U>::type relative_difference(const T& arg_a, const U& arg_b)
{
typedef typename boost::math::tools::promote_args<T, U>::type result_type;
result_type a = arg_a;
result_type b = arg_b;
BOOST_MATH_STD_USING
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
//
// If math.h has no long double support we can't rely
// on the math functions generating exponents outside
// the range of a double:
//
result_type min_val = (std::max)(
tools::min_value<result_type>(),
static_cast<result_type>((std::numeric_limits<double>::min)()));
result_type max_val = (std::min)(
tools::max_value<result_type>(),
static_cast<result_type>((std::numeric_limits<double>::max)()));
#else
result_type min_val = tools::min_value<result_type>();
result_type max_val = tools::max_value<result_type>();
#endif
// Screen out NaN's first, if either value is a NaN then the distance is "infinite":
if((boost::math::isnan)(a) || (boost::math::isnan)(b))
return max_val;
// Screen out infinites:
if(fabs(b) > max_val)
{
if(fabs(a) > max_val)
return (a < 0) == (b < 0) ? 0 : max_val; // one infinity is as good as another!
else
return max_val; // one infinity and one finite value implies infinite difference
}
else if(fabs(a) > max_val)
return max_val; // one infinity and one finite value implies infinite difference
//
// If the values have different signs, treat as infinite difference:
//
if(((a < 0) != (b < 0)) && (a != 0) && (b != 0))
return max_val;
a = fabs(a);
b = fabs(b);
//
// Now deal with zero's, if one value is zero (or denorm) then treat it the same as
// min_val for the purposes of the calculation that follows:
//
if(a < min_val)
a = min_val;
if(b < min_val)
b = min_val;
return (std::max)(fabs((a - b) / a), fabs((a - b) / b));
}
#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && (LDBL_MAX_EXP <= DBL_MAX_EXP)
template <>
inline boost::math::tools::promote_args<double, double>::type relative_difference(const double& arg_a, const double& arg_b)
{
BOOST_MATH_STD_USING
double a = arg_a;
double b = arg_b;
//
// On Mac OS X we evaluate "double" functions at "long double" precision,
// but "long double" actually has a very slightly narrower range than "double"!
// Therefore use the range of "long double" as our limits since results outside
// that range may have been truncated to 0 or INF:
//
double min_val = (std::max)((double)tools::min_value<long double>(), tools::min_value<double>());
double max_val = (std::min)((double)tools::max_value<long double>(), tools::max_value<double>());
// Screen out NaN's first, if either value is a NaN then the distance is "infinite":
if((boost::math::isnan)(a) || (boost::math::isnan)(b))
return max_val;
// Screen out infinites:
if(fabs(b) > max_val)
{
if(fabs(a) > max_val)
return 0; // one infinity is as good as another!
else
return max_val; // one infinity and one finite value implies infinite difference
}
else if(fabs(a) > max_val)
return max_val; // one infinity and one finite value implies infinite difference
//
// If the values have different signs, treat as infinite difference:
//
if(((a < 0) != (b < 0)) && (a != 0) && (b != 0))
return max_val;
a = fabs(a);
b = fabs(b);
//
// Now deal with zero's, if one value is zero (or denorm) then treat it the same as
// min_val for the purposes of the calculation that follows:
//
if(a < min_val)
a = min_val;
if(b < min_val)
b = min_val;
return (std::max)(fabs((a - b) / a), fabs((a - b) / b));
}
#endif
template <class T, class U>
inline typename boost::math::tools::promote_args<T, U>::type epsilon_difference(const T& arg_a, const U& arg_b)
{
typedef typename boost::math::tools::promote_args<T, U>::type result_type;
result_type r = relative_difference(arg_a, arg_b);
if(tools::max_value<result_type>() * boost::math::tools::epsilon<result_type>() < r)
return tools::max_value<result_type>();
return r / boost::math::tools::epsilon<result_type>();
}
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,132 @@
// 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/math_fwd.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
namespace boost{ namespace math{
namespace detail{
template <class T, class Policy>
inline typename tools::promote_args<T>::type round(const T& v, const Policy& pol, const mpl::false_)
{
BOOST_MATH_STD_USING
typedef typename tools::promote_args<T>::type result_type;
if(!(boost::math::isfinite)(v))
return policies::raise_rounding_error("boost::math::round<%1%>(%1%)", 0, static_cast<result_type>(v), static_cast<result_type>(v), pol);
//
// The logic here is rather convoluted, but avoids a number of traps,
// see discussion here https://github.com/boostorg/math/pull/8
//
if (-0.5 < v && v < 0.5)
{
// special case to avoid rounding error on the direct
// predecessor of +0.5 resp. the direct successor of -0.5 in
// IEEE floating point types
return 0;
}
else if (v > 0)
{
// subtract v from ceil(v) first in order to avoid rounding
// errors on largest representable integer numbers
result_type c(ceil(v));
return 0.5 < c - v ? c - 1 : c;
}
else
{
// see former branch
result_type f(floor(v));
return 0.5 < v - f ? f + 1 : f;
}
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type round(const T& v, const Policy&, const mpl::true_)
{
return v;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type round(const T& v, const Policy& pol)
{
return detail::round(v, pol, mpl::bool_<detail::is_integer_for_rounding<T>::value>());
}
template <class T>
inline typename tools::promote_args<T>::type 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, static_cast<boost::long_long_type>(0), 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,194 @@
// (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) ? 1 : 0;
}
#endif
// Generic versions first, note that these do not handle
// signed zero or NaN.
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;
}
#if defined(__GNUC__) && (LDBL_MANT_DIG == 106)
//
// Special handling for GCC's "double double" type,
// in this case the sign is the same as the sign we
// get by casting to double, no overflow/underflow
// can occur since the exponents are the same magnitude
// for the two types:
//
inline int signbit_impl(long double x, generic_tag<true> const&)
{
return (boost::math::signbit)(static_cast<double>(x));
}
inline int signbit_impl(long double x, generic_tag<false> const&)
{
return (boost::math::signbit)(static_cast<double>(x));
}
#endif
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
// Generic versions first, note that these do not handle
// signed zero or NaN.
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;
}
#if defined(__GNUC__) && (LDBL_MANT_DIG == 106)
//
// Special handling for GCC's "double double" type,
// in this case we need to change the sign of both
// components of the "double double":
//
inline long double (changesign_impl)(long double x, generic_tag<true> const&)
{
double* pd = reinterpret_cast<double*>(&x);
pd[0] = boost::math::changesign(pd[0]);
pd[1] = boost::math::changesign(pd[1]);
return x;
}
inline long double (changesign_impl)(long double x, generic_tag<false> const&)
{
double* pd = reinterpret_cast<double*>(&x);
pd[0] = boost::math::changesign(pd[0]);
pd[1] = boost::math::changesign(pd[1]);
return x;
}
#endif
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;
typedef typename tools::promote_args_permissive<T>::type result_type;
return detail::signbit_impl(static_cast<result_type>(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> typename tools::promote_args_permissive<T>::type (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;
typedef typename tools::promote_args_permissive<T>::type result_type;
return detail::changesign_impl(static_cast<result_type>(x), method());
}
template <class T, class U>
inline typename tools::promote_args_permissive<T, U>::type
copysign BOOST_NO_MACRO_EXPAND(const T& x, const U& y)
{
BOOST_MATH_STD_USING
typedef typename tools::promote_args_permissive<T, U>::type result_type;
return (boost::math::signbit)(static_cast<result_type>(x)) != (boost::math::signbit)(static_cast<result_type>(y))
? (boost::math::changesign)(static_cast<result_type>(x)) : static_cast<result_type>(x);
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_TOOLS_SIGN_HPP

View File

@@ -0,0 +1,78 @@
// 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/math_fwd.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&)
{
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>(boost::math::detail::sin_pi_imp<value_type>(x, forwarding_policy()), "cos_pi");
}
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,125 @@
// 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
{
// This is the "Sinus Cardinal" of index Pi.
template<typename T>
inline T sinc_pi_imp(const T x)
{
BOOST_MATH_STD_USING
if (abs(x) >= 3.3 * tools::forth_root_epsilon<T>())
{
return(sin(x)/x);
}
else
{
// |x| < (eps*120)^(1/4)
return 1 - x * x / 6;
}
}
} // 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));
}
#ifndef BOOST_NO_TEMPLATE_TEMPLATES
template<typename T, template<typename> class U>
inline U<T> sinc_pi(const U<T> x)
{
BOOST_MATH_STD_USING
using ::std::numeric_limits;
T const taylor_0_bound = tools::epsilon<T>();
T const taylor_2_bound = tools::root_epsilon<T>();
T const taylor_n_bound = tools::forth_root_epsilon<T>();
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,156 @@
// 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
{
// 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,205 @@
// (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/math_fwd.hpp>
#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, U(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/math_fwd.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.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,469 @@
// (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_TRIGAMMA_HPP
#define BOOST_MATH_SF_TRIGAMMA_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/series.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>
#include <boost/math/tools/big_constant.hpp>
#include <boost/math/special_functions/polygamma.hpp>
namespace boost{
namespace math{
namespace detail{
template<class T, class Policy>
T polygamma_imp(const int n, T x, const Policy &pol);
template <class T, class Policy>
T trigamma_prec(T x, const mpl::int_<53>*, const Policy&)
{
// Max error in interpolated form: 3.736e-017
static const T offset = BOOST_MATH_BIG_CONSTANT(T, 53, 2.1093254089355469);
static const T P_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, -1.1093280605946045),
BOOST_MATH_BIG_CONSTANT(T, 53, -3.8310674472619321),
BOOST_MATH_BIG_CONSTANT(T, 53, -3.3703848401898283),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.28080574467981213),
BOOST_MATH_BIG_CONSTANT(T, 53, 1.6638069578676164),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.64468386819102836),
};
static const T Q_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 53, 3.4535389668541151),
BOOST_MATH_BIG_CONSTANT(T, 53, 4.5208926987851437),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.7012734178351534),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.64468798399785611),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.20314516859987728e-6),
};
// Max error in interpolated form: 1.159e-017
static const T P_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, -0.13803835004508849e-7),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.50000049158540261),
BOOST_MATH_BIG_CONSTANT(T, 53, 1.6077979838469348),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.5645435828098254),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.0534873203680393),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.74566981111565923),
};
static const T Q_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 53, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.8822787662376169),
BOOST_MATH_BIG_CONSTANT(T, 53, 4.1681660554090917),
BOOST_MATH_BIG_CONSTANT(T, 53, 2.7853527819234466),
BOOST_MATH_BIG_CONSTANT(T, 53, 0.74967671848044792),
BOOST_MATH_BIG_CONSTANT(T, 53, -0.00057069112416246805),
};
// Maximum Deviation Found: 6.896e-018
// Expected Error Term : -6.895e-018
// Maximum Relative Change in Control Points : 8.497e-004
static const T P_4_inf[] = {
static_cast<T>(0.68947581948701249e-17L),
static_cast<T>(0.49999999999998975L),
static_cast<T>(1.0177274392923795L),
static_cast<T>(2.498208511343429L),
static_cast<T>(2.1921221359427595L),
static_cast<T>(1.5897035272532764L),
static_cast<T>(0.40154388356961734L),
};
static const T Q_4_inf[] = {
static_cast<T>(1.0L),
static_cast<T>(1.7021215452463932L),
static_cast<T>(4.4290431747556469L),
static_cast<T>(2.9745631894384922L),
static_cast<T>(2.3013614809773616L),
static_cast<T>(0.28360399799075752L),
static_cast<T>(0.022892987908906897L),
};
if(x <= 2)
{
return (offset + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x);
}
else if(x <= 4)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_2_4, y) / tools::evaluate_polynomial(Q_2_4, y)) / x;
}
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_4_inf, y) / tools::evaluate_polynomial(Q_4_inf, y)) / x;
}
template <class T, class Policy>
T trigamma_prec(T x, const mpl::int_<64>*, const Policy&)
{
// Max error in interpolated form: 1.178e-020
static const T offset_1_2 = BOOST_MATH_BIG_CONSTANT(T, 64, 2.109325408935546875);
static const T P_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -1.10932535608960258341),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.18793841543017129052),
BOOST_MATH_BIG_CONSTANT(T, 64, -4.63865531898487734531),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.919832884430500908047),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.68074038333180423012),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.21172611429185622377),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.259635673503366427284),
};
static const T Q_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.77521119359546982995),
BOOST_MATH_BIG_CONSTANT(T, 64, 5.664338024578956321),
BOOST_MATH_BIG_CONSTANT(T, 64, 4.25995134879278028361),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.62956638448940402182),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.259635512844691089868),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.629642219810618032207e-8),
};
// Max error in interpolated form: 3.912e-020
static const T P_2_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.387540035162952880976e-11),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.500000000276430504),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.21926880986360957306),
BOOST_MATH_BIG_CONSTANT(T, 64, 10.2550347708483445775),
BOOST_MATH_BIG_CONSTANT(T, 64, 18.9002075150709144043),
BOOST_MATH_BIG_CONSTANT(T, 64, 21.0357215832399705625),
BOOST_MATH_BIG_CONSTANT(T, 64, 13.4346512182925923978),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98656291026448279118),
};
static const T Q_2_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, 6.10520430478613667724),
BOOST_MATH_BIG_CONSTANT(T, 64, 18.475001060603645512),
BOOST_MATH_BIG_CONSTANT(T, 64, 31.7087534567758405638),
BOOST_MATH_BIG_CONSTANT(T, 64, 31.908814523890465398),
BOOST_MATH_BIG_CONSTANT(T, 64, 17.4175479039227084798),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.98749106958394941276),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.000115917322224411128566),
};
// Maximum Deviation Found: 2.635e-020
// Expected Error Term : 2.635e-020
// Maximum Relative Change in Control Points : 1.791e-003
static const T P_8_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, -0.263527875092466899848e-19),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.500000000000000058145),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0730121433777364138677),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.94505878379957149534),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.0517092358874932620529),
BOOST_MATH_BIG_CONSTANT(T, 64, 1.07995383547483921121),
};
static const T Q_8_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 64, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.187309046577818095504),
BOOST_MATH_BIG_CONSTANT(T, 64, 3.95255391645238842975),
BOOST_MATH_BIG_CONSTANT(T, 64, -1.14743283327078949087),
BOOST_MATH_BIG_CONSTANT(T, 64, 2.52989799376344914499),
BOOST_MATH_BIG_CONSTANT(T, 64, -0.627414303172402506396),
BOOST_MATH_BIG_CONSTANT(T, 64, 0.141554248216425512536),
};
if(x <= 2)
{
return (offset_1_2 + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x);
}
else if(x <= 8)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_2_8, y) / tools::evaluate_polynomial(Q_2_8, y)) / x;
}
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_8_inf, y) / tools::evaluate_polynomial(Q_8_inf, y)) / x;
}
template <class T, class Policy>
T trigamma_prec(T x, const mpl::int_<113>*, const Policy&)
{
// Max error in interpolated form: 1.916e-035
static const T P_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.999999999999999082554457936871832533),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.71237311120865266379041700054847734),
BOOST_MATH_BIG_CONSTANT(T, 113, -7.94125711970499027763789342500817316),
BOOST_MATH_BIG_CONSTANT(T, 113, -5.74657746697664735258222071695644535),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.404213349456398905981223965160595687),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.47877781178642876561595890095758896),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.07714151702455125992166949812126433),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.858877899162360138844032265418028567),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.20499222604410032375789018837922397),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0272103140348194747360175268778415049),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0015764849020876949848954081173520686),
};
static const T Q_1_2[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.71237311120863419878375031457715223),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.58619118655339853449127952145877467),
BOOST_MATH_BIG_CONSTANT(T, 113, 11.0940067269829372437561421279054968),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.09075424749327792073276309969037885),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.87705890159891405185343806884451286),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.22758678701914477836330837816976782),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.249092040606385004109672077814668716),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0295750413900655597027079600025569048),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00157648490200498142247694709728858139),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.161264050344059471721062360645432809e-14),
};
// Max error in interpolated form: 8.958e-035
static const T P_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -2.55843734739907925764326773972215085),
BOOST_MATH_BIG_CONSTANT(T, 113, -12.2830208240542011967952466273455887),
BOOST_MATH_BIG_CONSTANT(T, 113, -23.9195022162767993526575786066414403),
BOOST_MATH_BIG_CONSTANT(T, 113, -24.9256431504823483094158828285470862),
BOOST_MATH_BIG_CONSTANT(T, 113, -14.7979122765478779075108064826412285),
BOOST_MATH_BIG_CONSTANT(T, 113, -4.46654453928610666393276765059122272),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0191439033405649675717082465687845002),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.515412052554351265708917209749037352),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.195378348786064304378247325360320038),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0334761282624174313035014426794245393),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.002373665205942206348500250056602687),
};
static const T Q_2_4[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.80098558454419907830670928248659245),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.99220727843170133895059300223445265),
BOOST_MATH_BIG_CONSTANT(T, 113, 11.8896146167631330735386697123464976),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.96613256683809091593793565879092581),
BOOST_MATH_BIG_CONSTANT(T, 113, 4.47254136149624110878909334574485751),
BOOST_MATH_BIG_CONSTANT(T, 113, 1.48600982028196527372434773913633152),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.319570735766764237068541501137990078),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0407358345787680953107374215319322066),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.00237366520593271641375755486420859837),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.239554887903526152679337256236302116e-15),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.294749244740618656265237072002026314e-17),
};
static const T y_offset_2_4 = BOOST_MATH_BIG_CONSTANT(T, 113, 3.558437347412109375);
// Max error in interpolated form: 4.319e-035
static const T P_4_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.166626112697021464248967707021688845e-16),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.499999999999997739552090249208808197),
BOOST_MATH_BIG_CONSTANT(T, 113, 6.40270945019053817915772473771553187),
BOOST_MATH_BIG_CONSTANT(T, 113, 41.3833374155000608013677627389343329),
BOOST_MATH_BIG_CONSTANT(T, 113, 166.803341854562809335667241074035245),
BOOST_MATH_BIG_CONSTANT(T, 113, 453.39964786925369319960722793414521),
BOOST_MATH_BIG_CONSTANT(T, 113, 851.153712317697055375935433362983944),
BOOST_MATH_BIG_CONSTANT(T, 113, 1097.70657567285059133109286478004458),
BOOST_MATH_BIG_CONSTANT(T, 113, 938.431232478455316020076349367632922),
BOOST_MATH_BIG_CONSTANT(T, 113, 487.268001604651932322080970189930074),
BOOST_MATH_BIG_CONSTANT(T, 113, 119.953445242335730062471193124820659),
};
static const T Q_4_8[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 12.4720855670474488978638945855932398),
BOOST_MATH_BIG_CONSTANT(T, 113, 78.6093129753298570701376952709727391),
BOOST_MATH_BIG_CONSTANT(T, 113, 307.470246050318322489781182863190127),
BOOST_MATH_BIG_CONSTANT(T, 113, 805.140686101151538537565264188630079),
BOOST_MATH_BIG_CONSTANT(T, 113, 1439.12019760292146454787601409644413),
BOOST_MATH_BIG_CONSTANT(T, 113, 1735.6105285756048831268586001383127),
BOOST_MATH_BIG_CONSTANT(T, 113, 1348.32500712856328019355198611280536),
BOOST_MATH_BIG_CONSTANT(T, 113, 607.225985860570846699704222144650563),
BOOST_MATH_BIG_CONSTANT(T, 113, 119.952317857277045332558673164517227),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.000140165918355036060868680809129436084),
};
// Maximum Deviation Found: 2.867e-035
// Expected Error Term : 2.866e-035
// Maximum Relative Change in Control Points : 2.662e-004
static const T P_8_16[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, -0.184828315274146610610872315609837439e-19),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.500000000000000004122475157735807738),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.02533865247313349284875558880415875),
BOOST_MATH_BIG_CONSTANT(T, 113, 13.5995927517457371243039532492642734),
BOOST_MATH_BIG_CONSTANT(T, 113, 35.3132224283087906757037999452941588),
BOOST_MATH_BIG_CONSTANT(T, 113, 67.1639424550714159157603179911505619),
BOOST_MATH_BIG_CONSTANT(T, 113, 83.5767733658513967581959839367419891),
BOOST_MATH_BIG_CONSTANT(T, 113, 71.073491212235705900866411319363501),
BOOST_MATH_BIG_CONSTANT(T, 113, 35.8621515614725564575893663483998663),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.72152231639983491987779743154333318),
};
static const T Q_8_16[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 5.71734397161293452310624822415866372),
BOOST_MATH_BIG_CONSTANT(T, 113, 25.293404179620438179337103263274815),
BOOST_MATH_BIG_CONSTANT(T, 113, 62.2619767967468199111077640625328469),
BOOST_MATH_BIG_CONSTANT(T, 113, 113.955048909238993473389714972250235),
BOOST_MATH_BIG_CONSTANT(T, 113, 130.807138328938966981862203944329408),
BOOST_MATH_BIG_CONSTANT(T, 113, 102.423146902337654110717764213057753),
BOOST_MATH_BIG_CONSTANT(T, 113, 44.0424772805245202514468199602123565),
BOOST_MATH_BIG_CONSTANT(T, 113, 8.89898032477904072082994913461386099),
BOOST_MATH_BIG_CONSTANT(T, 113, -0.0296627336872039988632793863671456398),
};
// Maximum Deviation Found: 1.079e-035
// Expected Error Term : -1.079e-035
// Maximum Relative Change in Control Points : 7.884e-003
static const T P_16_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 0.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.500000000000000000000000000000087317),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.345625669885456215194494735902663968),
BOOST_MATH_BIG_CONSTANT(T, 113, 9.62895499360842232127552650044647769),
BOOST_MATH_BIG_CONSTANT(T, 113, 3.5936085382439026269301003761320812),
BOOST_MATH_BIG_CONSTANT(T, 113, 49.459599118438883265036646019410669),
BOOST_MATH_BIG_CONSTANT(T, 113, 7.77519237321893917784735690560496607),
BOOST_MATH_BIG_CONSTANT(T, 113, 74.4536074488178075948642351179304121),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.75209340397069050436806159297952699),
BOOST_MATH_BIG_CONSTANT(T, 113, 23.9292359711471667884504840186561598),
};
static const T Q_16_inf[] = {
BOOST_MATH_BIG_CONSTANT(T, 113, 1.0),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.357918006437579097055656138920742037),
BOOST_MATH_BIG_CONSTANT(T, 113, 19.1386039850709849435325005484512944),
BOOST_MATH_BIG_CONSTANT(T, 113, 0.874349081464143606016221431763364517),
BOOST_MATH_BIG_CONSTANT(T, 113, 98.6516097434855572678195488061432509),
BOOST_MATH_BIG_CONSTANT(T, 113, -16.1051972833382893468655223662534306),
BOOST_MATH_BIG_CONSTANT(T, 113, 154.316860216253720989145047141653727),
BOOST_MATH_BIG_CONSTANT(T, 113, -40.2026880424378986053105969312264534),
BOOST_MATH_BIG_CONSTANT(T, 113, 60.1679136674264778074736441126810223),
BOOST_MATH_BIG_CONSTANT(T, 113, -13.3414844622256422644504472438320114),
BOOST_MATH_BIG_CONSTANT(T, 113, 2.53795636200649908779512969030363442),
};
if(x <= 2)
{
return (2 + boost::math::tools::evaluate_polynomial(P_1_2, x) / tools::evaluate_polynomial(Q_1_2, x)) / (x * x);
}
else if(x <= 4)
{
return (y_offset_2_4 + boost::math::tools::evaluate_polynomial(P_2_4, x) / tools::evaluate_polynomial(Q_2_4, x)) / (x * x);
}
else if(x <= 8)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_4_8, y) / tools::evaluate_polynomial(Q_4_8, y)) / x;
}
else if(x <= 16)
{
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_8_16, y) / tools::evaluate_polynomial(Q_8_16, y)) / x;
}
T y = 1 / x;
return (1 + tools::evaluate_polynomial(P_16_inf, y) / tools::evaluate_polynomial(Q_16_inf, y)) / x;
}
template <class T, class Tag, class Policy>
T trigamma_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:
T z = 1 - x;
// Argument reduction for tan:
if(floor(x) == x)
{
return policies::raise_pole_error<T>("boost::math::trigamma<%1%>(%1%)", 0, (1-x), pol);
}
T s = fabs(x) < fabs(z) ? boost::math::sin_pi(x, pol) : boost::math::sin_pi(z, pol);
return -trigamma_imp(z, t, pol) + boost::math::pow<2>(constants::pi<T>()) / (s * s);
}
if(x < 1)
{
result = 1 / (x * x);
x += 1;
}
return result + trigamma_prec(x, t, pol);
}
template <class T, class Policy>
T trigamma_imp(T x, const mpl::int_<0>*, const Policy& pol)
{
return polygamma_imp(1, x, pol);
}
//
// Initializer: ensure all our constants are initialized prior to the first call of main:
//
template <class T, class Policy>
struct trigamma_initializer
{
struct init
{
init()
{
typedef typename policies::precision<T, Policy>::type precision_type;
do_init(mpl::bool_<precision_type::value && (precision_type::value <= 113)>());
}
void do_init(const mpl::true_&)
{
boost::math::trigamma(T(2.5), Policy());
}
void do_init(const mpl::false_&){}
void force_instantiate()const{}
};
static const init initializer;
static void force_instantiate()
{
initializer.force_instantiate();
}
};
template <class T, class Policy>
const typename trigamma_initializer<T, Policy>::init trigamma_initializer<T, Policy>::initializer;
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type
trigamma(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<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_<114> >
>,
mpl::int_<0>,
typename mpl::if_<
mpl::less<precision_type, mpl::int_<54> >,
mpl::int_<53>,
typename mpl::if_<
mpl::less<precision_type, mpl::int_<65> >,
mpl::int_<64>,
mpl::int_<113>
>::type
>::type
>::type tag_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
// Force initialization of constants:
detail::trigamma_initializer<value_type, forwarding_policy>::force_instantiate();
return policies::checked_narrowing_cast<result_type, Policy>(detail::trigamma_imp(
static_cast<value_type>(x),
static_cast<const tag_type*>(0), forwarding_policy()), "boost::math::trigamma<%1%>(%1%)");
}
template <class T>
inline typename tools::promote_args<T>::type
trigamma(T x)
{
return trigamma(x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,111 @@
// 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/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
inline typename tools::promote_args<T>::type trunc(const T& v, const Policy& pol, const mpl::false_&)
{
BOOST_MATH_STD_USING
typedef typename tools::promote_args<T>::type result_type;
if(!(boost::math::isfinite)(v))
return policies::raise_rounding_error("boost::math::trunc<%1%>(%1%)", 0, static_cast<result_type>(v), static_cast<result_type>(v), pol);
return (v >= 0) ? static_cast<result_type>(floor(v)) : static_cast<result_type>(ceil(v));
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type trunc(const T& v, const Policy&, const mpl::true_&)
{
return v;
}
}
template <class T, class Policy>
inline typename tools::promote_args<T>::type trunc(const T& v, const Policy& pol)
{
return detail::trunc(v, pol, mpl::bool_<detail::is_integer_for_rounding<T>::value>());
}
template <class T>
inline typename tools::promote_args<T>::type 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
typedef typename tools::promote_args<T>::type result_type;
result_type 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, static_cast<result_type>(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
typedef typename tools::promote_args<T>::type result_type;
result_type 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, static_cast<result_type>(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
typedef typename tools::promote_args<T>::type result_type;
result_type 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, static_cast<boost::long_long_type>(0), 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

Some files were not shown because too many files have changed in this diff Show More