summaryrefslogtreecommitdiff
path: root/boost/math/special_functions
diff options
context:
space:
mode:
Diffstat (limited to 'boost/math/special_functions')
-rw-r--r--boost/math/special_functions/acosh.hpp114
-rw-r--r--boost/math/special_functions/asinh.hpp116
-rw-r--r--boost/math/special_functions/atanh.hpp128
-rw-r--r--boost/math/special_functions/bessel.hpp469
-rw-r--r--boost/math/special_functions/beta.hpp1447
-rw-r--r--boost/math/special_functions/binomial.hpp81
-rw-r--r--boost/math/special_functions/cbrt.hpp180
-rw-r--r--boost/math/special_functions/cos_pi.hpp68
-rw-r--r--boost/math/special_functions/detail/bessel_i0.hpp102
-rw-r--r--boost/math/special_functions/detail/bessel_i1.hpp105
-rw-r--r--boost/math/special_functions/detail/bessel_ik.hpp428
-rw-r--r--boost/math/special_functions/detail/bessel_j0.hpp153
-rw-r--r--boost/math/special_functions/detail/bessel_j1.hpp158
-rw-r--r--boost/math/special_functions/detail/bessel_jn.hpp127
-rw-r--r--boost/math/special_functions/detail/bessel_jy.hpp553
-rw-r--r--boost/math/special_functions/detail/bessel_jy_asym.hpp315
-rw-r--r--boost/math/special_functions/detail/bessel_jy_series.hpp261
-rw-r--r--boost/math/special_functions/detail/bessel_k0.hpp122
-rw-r--r--boost/math/special_functions/detail/bessel_k1.hpp118
-rw-r--r--boost/math/special_functions/detail/bessel_kn.hpp85
-rw-r--r--boost/math/special_functions/detail/bessel_y0.hpp183
-rw-r--r--boost/math/special_functions/detail/bessel_y1.hpp156
-rw-r--r--boost/math/special_functions/detail/bessel_yn.hpp103
-rw-r--r--boost/math/special_functions/detail/erf_inv.hpp471
-rw-r--r--boost/math/special_functions/detail/fp_traits.hpp570
-rw-r--r--boost/math/special_functions/detail/gamma_inva.hpp233
-rw-r--r--boost/math/special_functions/detail/ibeta_inv_ab.hpp324
-rw-r--r--boost/math/special_functions/detail/ibeta_inverse.hpp944
-rw-r--r--boost/math/special_functions/detail/iconv.hpp42
-rw-r--r--boost/math/special_functions/detail/igamma_inverse.hpp551
-rw-r--r--boost/math/special_functions/detail/igamma_large.hpp769
-rw-r--r--boost/math/special_functions/detail/lanczos_sse2.hpp201
-rw-r--r--boost/math/special_functions/detail/lgamma_small.hpp514
-rw-r--r--boost/math/special_functions/detail/round_fwd.hpp80
-rw-r--r--boost/math/special_functions/detail/t_distribution_inv.hpp544
-rw-r--r--boost/math/special_functions/detail/unchecked_factorial.hpp415
-rw-r--r--boost/math/special_functions/digamma.hpp451
-rw-r--r--boost/math/special_functions/ellint_1.hpp187
-rw-r--r--boost/math/special_functions/ellint_2.hpp168
-rw-r--r--boost/math/special_functions/ellint_3.hpp318
-rw-r--r--boost/math/special_functions/ellint_rc.hpp115
-rw-r--r--boost/math/special_functions/ellint_rd.hpp130
-rw-r--r--boost/math/special_functions/ellint_rf.hpp132
-rw-r--r--boost/math/special_functions/ellint_rj.hpp180
-rw-r--r--boost/math/special_functions/erf.hpp1092
-rw-r--r--boost/math/special_functions/expint.hpp1579
-rw-r--r--boost/math/special_functions/expm1.hpp344
-rw-r--r--boost/math/special_functions/factorials.hpp240
-rw-r--r--boost/math/special_functions/fpclassify.hpp533
-rw-r--r--boost/math/special_functions/gamma.hpp1551
-rw-r--r--boost/math/special_functions/hermite.hpp76
-rw-r--r--boost/math/special_functions/hypot.hpp86
-rw-r--r--boost/math/special_functions/laguerre.hpp139
-rw-r--r--boost/math/special_functions/lanczos.hpp1243
-rw-r--r--boost/math/special_functions/legendre.hpp194
-rw-r--r--boost/math/special_functions/log1p.hpp472
-rw-r--r--boost/math/special_functions/math_fwd.hpp1070
-rw-r--r--boost/math/special_functions/modf.hpp70
-rw-r--r--boost/math/special_functions/next.hpp320
-rw-r--r--boost/math/special_functions/nonfinite_num_facets.hpp543
-rw-r--r--boost/math/special_functions/pow.hpp140
-rw-r--r--boost/math/special_functions/powm1.hpp61
-rw-r--r--boost/math/special_functions/prime.hpp1219
-rw-r--r--boost/math/special_functions/round.hpp92
-rw-r--r--boost/math/special_functions/sign.hpp145
-rw-r--r--boost/math/special_functions/sin_pi.hpp70
-rw-r--r--boost/math/special_functions/sinc.hpp177
-rw-r--r--boost/math/special_functions/sinhc.hpp167
-rw-r--r--boost/math/special_functions/spherical_harmonic.hpp204
-rw-r--r--boost/math/special_functions/sqrt1pm1.hpp48
-rw-r--r--boost/math/special_functions/trunc.hpp92
-rw-r--r--boost/math/special_functions/zeta.hpp950
72 files changed, 25828 insertions, 0 deletions
diff --git a/boost/math/special_functions/acosh.hpp b/boost/math/special_functions/acosh.hpp
new file mode 100644
index 0000000000..40ca985edc
--- /dev/null
+++ b/boost/math/special_functions/acosh.hpp
@@ -0,0 +1,114 @@
+// boost asinh.hpp header file
+
+// (C) Copyright Eric Ford 2001 & Hubert Holin.
+// (C) Copyright John Maddock 2008.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for updates, documentation, and revision history.
+
+#ifndef BOOST_ACOSH_HPP
+#define BOOST_ACOSH_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/config.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+
+// This is the inverse of the hyperbolic cosine function.
+
+namespace boost
+{
+ namespace math
+ {
+ namespace detail
+ {
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ // gcc 2.x ignores function scope using declarations,
+ // put them in the scope of the enclosing namespace instead:
+
+ using ::std::abs;
+ using ::std::sqrt;
+ using ::std::log;
+
+ using ::std::numeric_limits;
+#endif
+
+ template<typename T, typename Policy>
+ inline T acosh_imp(const T x, const Policy& pol)
+ {
+ BOOST_MATH_STD_USING
+
+ if(x < 1)
+ {
+ return policies::raise_domain_error<T>(
+ "boost::math::acosh<%1%>(%1%)",
+ "acosh requires x >= 1, but got x = %1%.", x, pol);
+ }
+ else if ((x - 1) >= tools::root_epsilon<T>())
+ {
+ if (x > 1 / tools::root_epsilon<T>())
+ {
+ // http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/06/01/0001/
+ // approximation by laurent series in 1/x at 0+ order from -1 to 0
+ return( log( x * 2) );
+ }
+ else if(x < 1.5f)
+ {
+ // This is just a rearrangement of the standard form below
+ // devised to minimse loss of precision when x ~ 1:
+ T y = x - 1;
+ return boost::math::log1p(y + sqrt(y * y + 2 * y), pol);
+ }
+ else
+ {
+ // http://functions.wolfram.com/ElementaryFunctions/ArcCosh/02/
+ return( log( x + sqrt(x * x - 1) ) );
+ }
+ }
+ else
+ {
+ // see http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/04/01/0001/
+ T y = x - 1;
+
+ // approximation by taylor series in y at 0 up to order 2
+ T result = sqrt(2 * y) * (1 - y /12 + 3 * y * y / 160);
+ return result;
+ }
+ }
+ }
+
+ template<typename T, typename Policy>
+ inline typename tools::promote_args<T>::type acosh(T x, const Policy&)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::acosh_imp(static_cast<value_type>(x), forwarding_policy()),
+ "boost::math::acosh<%1%>(%1%)");
+ }
+ template<typename T>
+ inline typename tools::promote_args<T>::type acosh(T x)
+ {
+ return boost::math::acosh(x, policies::policy<>());
+ }
+
+ }
+}
+
+#endif /* BOOST_ACOSH_HPP */
+
+
diff --git a/boost/math/special_functions/asinh.hpp b/boost/math/special_functions/asinh.hpp
new file mode 100644
index 0000000000..14289688b4
--- /dev/null
+++ b/boost/math/special_functions/asinh.hpp
@@ -0,0 +1,116 @@
+// boost asinh.hpp header file
+
+// (C) Copyright Eric Ford & Hubert Holin 2001.
+// (C) Copyright John Maddock 2008.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for updates, documentation, and revision history.
+
+#ifndef BOOST_ASINH_HPP
+#define BOOST_ASINH_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/config.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/sqrt1pm1.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+
+// This is the inverse of the hyperbolic sine function.
+
+namespace boost
+{
+ namespace math
+ {
+ namespace detail{
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ // gcc 2.x ignores function scope using declarations,
+ // put them in the scope of the enclosing namespace instead:
+
+ using ::std::abs;
+ using ::std::sqrt;
+ using ::std::log;
+
+ using ::std::numeric_limits;
+#endif
+
+ template<typename T, class Policy>
+ inline T asinh_imp(const T x, const Policy& pol)
+ {
+ BOOST_MATH_STD_USING
+
+ if (x >= tools::forth_root_epsilon<T>())
+ {
+ if (x > 1 / tools::root_epsilon<T>())
+ {
+ // http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/06/01/0001/
+ // approximation by laurent series in 1/x at 0+ order from -1 to 1
+ return log(x * 2) + 1/ (4 * x * x);
+ }
+ else if(x < 0.5f)
+ {
+ // As below, but rearranged to preserve digits:
+ return boost::math::log1p(x + boost::math::sqrt1pm1(x * x, pol), pol);
+ }
+ else
+ {
+ // http://functions.wolfram.com/ElementaryFunctions/ArcSinh/02/
+ return( log( x + sqrt(x*x+1) ) );
+ }
+ }
+ else if (x <= -tools::forth_root_epsilon<T>())
+ {
+ return(-asinh(-x));
+ }
+ else
+ {
+ // http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/03/01/0001/
+ // approximation by taylor series in x at 0 up to order 2
+ T result = x;
+
+ if (abs(x) >= tools::root_epsilon<T>())
+ {
+ T x3 = x*x*x;
+
+ // approximation by taylor series in x at 0 up to order 4
+ result -= x3/static_cast<T>(6);
+ }
+
+ return(result);
+ }
+ }
+ }
+
+ template<typename T>
+ inline typename tools::promote_args<T>::type asinh(T x)
+ {
+ return boost::math::asinh(x, policies::policy<>());
+ }
+ template<typename T, typename Policy>
+ inline typename tools::promote_args<T>::type asinh(T x, const Policy&)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::asinh_imp(static_cast<value_type>(x), forwarding_policy()),
+ "boost::math::asinh<%1%>(%1%)");
+ }
+
+ }
+}
+
+#endif /* BOOST_ASINH_HPP */
+
diff --git a/boost/math/special_functions/atanh.hpp b/boost/math/special_functions/atanh.hpp
new file mode 100644
index 0000000000..d447e2057b
--- /dev/null
+++ b/boost/math/special_functions/atanh.hpp
@@ -0,0 +1,128 @@
+// boost atanh.hpp header file
+
+// (C) Copyright Hubert Holin 2001.
+// (C) Copyright John Maddock 2008.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for updates, documentation, and revision history.
+
+#ifndef BOOST_ATANH_HPP
+#define BOOST_ATANH_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/config.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+
+// This is the inverse of the hyperbolic tangent function.
+
+namespace boost
+{
+ namespace math
+ {
+ namespace detail
+ {
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ // gcc 2.x ignores function scope using declarations,
+ // put them in the scope of the enclosing namespace instead:
+
+ using ::std::abs;
+ using ::std::sqrt;
+ using ::std::log;
+
+ using ::std::numeric_limits;
+#endif
+
+ // This is the main fare
+
+ template<typename T, typename Policy>
+ inline T atanh_imp(const T x, const Policy& pol)
+ {
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::atanh<%1%>(%1%)";
+
+ if(x < -1)
+ {
+ return policies::raise_domain_error<T>(
+ function,
+ "atanh requires x >= -1, but got x = %1%.", x, pol);
+ }
+ else if(x < -1 + tools::epsilon<T>())
+ {
+ // -Infinity:
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else if(x > 1 - tools::epsilon<T>())
+ {
+ // Infinity:
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else if(x > 1)
+ {
+ return policies::raise_domain_error<T>(
+ function,
+ "atanh requires x <= 1, but got x = %1%.", x, pol);
+ }
+ else if(abs(x) >= tools::forth_root_epsilon<T>())
+ {
+ // http://functions.wolfram.com/ElementaryFunctions/ArcTanh/02/
+ if(abs(x) < 0.5f)
+ return (boost::math::log1p(x, pol) - boost::math::log1p(-x, pol)) / 2;
+ return(log( (1 + x) / (1 - x) ) / 2);
+ }
+ else
+ {
+ // http://functions.wolfram.com/ElementaryFunctions/ArcTanh/06/01/03/01/
+ // approximation by taylor series in x at 0 up to order 2
+ T result = x;
+
+ if (abs(x) >= tools::root_epsilon<T>())
+ {
+ T x3 = x*x*x;
+
+ // approximation by taylor series in x at 0 up to order 4
+ result += x3/static_cast<T>(3);
+ }
+
+ return(result);
+ }
+ }
+ }
+
+ template<typename T, typename Policy>
+ inline typename tools::promote_args<T>::type atanh(T x, const Policy&)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::atanh_imp(static_cast<value_type>(x), forwarding_policy()),
+ "boost::math::atanh<%1%>(%1%)");
+ }
+ template<typename T>
+ inline typename tools::promote_args<T>::type atanh(T x)
+ {
+ return boost::math::atanh(x, policies::policy<>());
+ }
+
+ }
+}
+
+#endif /* BOOST_ATANH_HPP */
+
+
+
diff --git a/boost/math/special_functions/bessel.hpp b/boost/math/special_functions/bessel.hpp
new file mode 100644
index 0000000000..d9d3c60bd0
--- /dev/null
+++ b/boost/math/special_functions/bessel.hpp
@@ -0,0 +1,469 @@
+// Copyright (c) 2007 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// This header just defines the function entry points, and adds dispatch
+// to the right implementation method. Most of the implementation details
+// are in separate headers and copyright Xiaogang Zhang.
+//
+#ifndef BOOST_MATH_BESSEL_HPP
+#define BOOST_MATH_BESSEL_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/detail/bessel_jy.hpp>
+#include <boost/math/special_functions/detail/bessel_jn.hpp>
+#include <boost/math/special_functions/detail/bessel_yn.hpp>
+#include <boost/math/special_functions/detail/bessel_ik.hpp>
+#include <boost/math/special_functions/detail/bessel_i0.hpp>
+#include <boost/math/special_functions/detail/bessel_i1.hpp>
+#include <boost/math/special_functions/detail/bessel_kn.hpp>
+#include <boost/math/special_functions/detail/iconv.hpp>
+#include <boost/math/special_functions/sin_pi.hpp>
+#include <boost/math/special_functions/cos_pi.hpp>
+#include <boost/math/special_functions/sinc.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/math/tools/series.hpp>
+
+namespace boost{ namespace math{
+
+namespace detail{
+
+template <class T, class Policy>
+struct sph_bessel_j_small_z_series_term
+{
+ typedef T result_type;
+
+ sph_bessel_j_small_z_series_term(unsigned v_, T x)
+ : N(0), v(v_)
+ {
+ BOOST_MATH_STD_USING
+ mult = x / 2;
+ term = pow(mult, T(v)) / boost::math::tgamma(v+1+T(0.5f), Policy());
+ mult *= -mult;
+ }
+ T operator()()
+ {
+ T r = term;
+ ++N;
+ term *= mult / (N * T(N + v + 0.5f));
+ return r;
+ }
+private:
+ unsigned N;
+ unsigned v;
+ T mult;
+ T term;
+};
+
+template <class T, class Policy>
+inline T sph_bessel_j_small_z_series(unsigned v, T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ sph_bessel_j_small_z_series_term<T, Policy> s(v, x);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ T zero = 0;
+ T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
+#else
+ T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
+#endif
+ policies::check_series_iterations<T>("boost::math::sph_bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
+ return result * sqrt(constants::pi<T>() / 4);
+}
+
+template <class T, class Policy>
+T cyl_bessel_j_imp(T v, T x, const bessel_no_int_tag& t, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::bessel_j<%1%>(%1%,%1%)";
+ if(x < 0)
+ {
+ // better have integer v:
+ if(floor(v) == v)
+ {
+ T r = cyl_bessel_j_imp(v, T(-x), t, pol);
+ if(iround(v, pol) & 1)
+ r = -r;
+ return r;
+ }
+ else
+ return policies::raise_domain_error<T>(
+ function,
+ "Got x = %1%, but we need x >= 0", x, pol);
+ }
+ if(x == 0)
+ return (v == 0) ? 1 : (v > 0) ? 0 :
+ policies::raise_domain_error<T>(
+ function,
+ "Got v = %1%, but require v >= 0 or a negative integer: the result would be complex.", v, pol);
+
+
+ if((v >= 0) && ((x < 1) || (v > x * x / 4) || (x < 5)))
+ {
+ //
+ // This series will actually converge rapidly for all small
+ // x - say up to x < 20 - but the first few terms are large
+ // and divergent which leads to large errors :-(
+ //
+ return bessel_j_small_z_series(v, x, pol);
+ }
+
+ T j, y;
+ bessel_jy(v, x, &j, &y, need_j, pol);
+ return j;
+}
+
+template <class T, class Policy>
+inline T cyl_bessel_j_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names.
+ int ival = detail::iconv(v, pol);
+ if((abs(ival) < 200) && (0 == v - ival))
+ {
+ return bessel_jn(ival/*iround(v, pol)*/, x, pol);
+ }
+ return cyl_bessel_j_imp(v, x, bessel_no_int_tag(), pol);
+}
+
+template <class T, class Policy>
+inline T cyl_bessel_j_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ return bessel_jn(v, x, pol);
+}
+
+template <class T, class Policy>
+inline T sph_bessel_j_imp(unsigned n, T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ if(x < 0)
+ return policies::raise_domain_error<T>(
+ "boost::math::sph_bessel_j<%1%>(%1%,%1%)",
+ "Got x = %1%, but function requires x > 0.", x, pol);
+ //
+ // Special case, n == 0 resolves down to the sinus cardinal of x:
+ //
+ if(n == 0)
+ return boost::math::sinc_pi(x, pol);
+ //
+ // When x is small we may end up with 0/0, use series evaluation
+ // instead, especially as it converges rapidly:
+ //
+ if(x < 1)
+ return sph_bessel_j_small_z_series(n, x, pol);
+ //
+ // Default case is just a naive evaluation of the definition:
+ //
+ return sqrt(constants::pi<T>() / (2 * x))
+ * cyl_bessel_j_imp(T(T(n)+T(0.5f)), x, bessel_no_int_tag(), pol);
+}
+
+template <class T, class Policy>
+T cyl_bessel_i_imp(T v, T x, const Policy& pol)
+{
+ //
+ // This handles all the bessel I functions, note that we don't optimise
+ // for integer v, other than the v = 0 or 1 special cases, as Millers
+ // algorithm is at least as inefficient as the general case (the general
+ // case has better error handling too).
+ //
+ BOOST_MATH_STD_USING
+ if(x < 0)
+ {
+ // better have integer v:
+ if(floor(v) == v)
+ {
+ T r = cyl_bessel_i_imp(v, T(-x), pol);
+ if(iround(v, pol) & 1)
+ r = -r;
+ return r;
+ }
+ else
+ return policies::raise_domain_error<T>(
+ "boost::math::cyl_bessel_i<%1%>(%1%,%1%)",
+ "Got x = %1%, but we need x >= 0", x, pol);
+ }
+ if(x == 0)
+ {
+ return (v == 0) ? 1 : 0;
+ }
+ if(v == 0.5f)
+ {
+ // common special case, note try and avoid overflow in exp(x):
+ if(x >= tools::log_max_value<T>())
+ {
+ T e = exp(x / 2);
+ return e * (e / sqrt(2 * x * constants::pi<T>()));
+ }
+ return sqrt(2 / (x * constants::pi<T>())) * sinh(x);
+ }
+ if(policies::digits<T, Policy>() <= 64)
+ {
+ if(v == 0)
+ {
+ return bessel_i0(x);
+ }
+ if(v == 1)
+ {
+ return bessel_i1(x);
+ }
+ }
+ if((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
+ typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(v);
+ BOOST_MATH_INSTRUMENT_VARIABLE(x);
+
+ if(floor(v) == v)
+ {
+ if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
+ {
+ T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
+ if((v < 0) && (itrunc(v, pol) & 1))
+ r = -r;
+ BOOST_MATH_INSTRUMENT_VARIABLE(r);
+ return r;
+ }
+ else
+ {
+ T r = bessel_yn(itrunc(v, pol), x, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(r);
+ return r;
+ }
+ }
+ T r = cyl_neumann_imp<T>(v, x, bessel_no_int_tag(), pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(r);
+ return r;
+}
+
+template <class T, class Policy>
+inline T cyl_neumann_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(v);
+ BOOST_MATH_INSTRUMENT_VARIABLE(x);
+
+ if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
+ {
+ T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
+ if((v < 0) && (v & 1))
+ r = -r;
+ return r;
+ }
+ else
+ return bessel_yn(v, x, pol);
+}
+
+template <class T, class Policy>
+inline T sph_neumann_imp(unsigned v, T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ static const char* function = "boost::math::sph_neumann<%1%>(%1%,%1%)";
+ //
+ // Nothing much to do here but check for errors, and
+ // evaluate the function's definition directly:
+ //
+ if(x < 0)
+ return policies::raise_domain_error<T>(
+ function,
+ "Got x = %1%, but function requires x > 0.", x, pol);
+
+ if(x < 2 * tools::min_value<T>())
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+
+ T result = cyl_neumann_imp(T(T(v)+0.5f), x, bessel_no_int_tag(), pol);
+ T tx = sqrt(constants::pi<T>() / (2 * x));
+
+ if((tx > 1) && (tools::max_value<T>() / tx < result))
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+
+ return result * tx;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class Policy>
+inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_j(T1 v, T2 x, const Policy& pol)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
+ typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_j_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_bessel_j<%1%>(%1%,%1%)");
+}
+
+template <class T1, class T2>
+inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_j(T1 v, T2 x)
+{
+ return cyl_bessel_j(v, x, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline typename detail::bessel_traits<T, T, Policy>::result_type sph_bessel(unsigned v, T x, const Policy& pol)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename detail::bessel_traits<T, T, Policy>::result_type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_bessel_j_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::sph_bessel<%1%>(%1%,%1%)");
+}
+
+template <class T>
+inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_bessel(unsigned v, T x)
+{
+ return sph_bessel(v, x, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_i(T1 v, T2 x, const Policy& pol)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_i_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::cyl_bessel_i<%1%>(%1%,%1%)");
+}
+
+template <class T1, class T2>
+inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_i(T1 v, T2 x)
+{
+ return cyl_bessel_i(v, x, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_k(T1 v, T2 x, const Policy& pol)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
+ typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_k_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_bessel_k<%1%>(%1%,%1%)");
+}
+
+template <class T1, class T2>
+inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_k(T1 v, T2 x)
+{
+ return cyl_bessel_k(v, x, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_neumann(T1 v, T2 x, const Policy& pol)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
+ typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_neumann_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_neumann<%1%>(%1%,%1%)");
+}
+
+template <class T1, class T2>
+inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_neumann(T1 v, T2 x)
+{
+ return cyl_neumann(v, x, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline typename detail::bessel_traits<T, T, Policy>::result_type sph_neumann(unsigned v, T x, const Policy& pol)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename detail::bessel_traits<T, T, Policy>::result_type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_neumann_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::sph_neumann<%1%>(%1%,%1%)");
+}
+
+template <class T>
+inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_neumann(unsigned v, T x)
+{
+ return sph_neumann(v, x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_BESSEL_HPP
+
diff --git a/boost/math/special_functions/beta.hpp b/boost/math/special_functions/beta.hpp
new file mode 100644
index 0000000000..1177f44d60
--- /dev/null
+++ b/boost/math/special_functions/beta.hpp
@@ -0,0 +1,1447 @@
+// (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_BETA_HPP
+#define BOOST_MATH_SPECIAL_BETA_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/gamma.hpp>
+#include <boost/math/special_functions/factorials.hpp>
+#include <boost/math/special_functions/erf.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+#include <boost/math/special_functions/expm1.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <boost/math/tools/roots.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/config/no_tr1/cmath.hpp>
+
+namespace boost{ namespace math{
+
+namespace detail{
+
+//
+// Implementation of Beta(a,b) using the Lanczos approximation:
+//
+template <class T, class Lanczos, class Policy>
+T beta_imp(T a, T b, const Lanczos&, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // for ADL of std names
+
+ if(a <= 0)
+ policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got a=%1%).", a, pol);
+ if(b <= 0)
+ policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got b=%1%).", b, pol);
+
+ T result;
+
+ T prefix = 1;
+ T c = a + b;
+
+ // Special cases:
+ if((c == a) && (b < tools::epsilon<T>()))
+ return boost::math::tgamma(b, pol);
+ else if((c == b) && (a < tools::epsilon<T>()))
+ return boost::math::tgamma(a, pol);
+ if(b == 1)
+ return 1/a;
+ else if(a == 1)
+ return 1/b;
+
+ /*
+ //
+ // This code appears to be no longer necessary: it was
+ // used to offset errors introduced from the Lanczos
+ // approximation, but the current Lanczos approximations
+ // are sufficiently accurate for all z that we can ditch
+ // this. It remains in the file for future reference...
+ //
+ // If a or b are less than 1, shift to greater than 1:
+ if(a < 1)
+ {
+ prefix *= c / a;
+ c += 1;
+ a += 1;
+ }
+ if(b < 1)
+ {
+ prefix *= c / b;
+ c += 1;
+ b += 1;
+ }
+ */
+
+ if(a < b)
+ std::swap(a, b);
+
+ // Lanczos calculation:
+ T agh = a + Lanczos::g() - T(0.5);
+ T bgh = b + Lanczos::g() - T(0.5);
+ T cgh = c + Lanczos::g() - T(0.5);
+ result = Lanczos::lanczos_sum_expG_scaled(a) * Lanczos::lanczos_sum_expG_scaled(b) / Lanczos::lanczos_sum_expG_scaled(c);
+ T ambh = a - T(0.5) - b;
+ if((fabs(b * ambh) < (cgh * 100)) && (a > 100))
+ {
+ // Special case where the base of the power term is close to 1
+ // compute (1+x)^y instead:
+ result *= exp(ambh * boost::math::log1p(-b / cgh, pol));
+ }
+ else
+ {
+ result *= pow(agh / cgh, a - T(0.5) - b);
+ }
+ if(cgh > 1e10f)
+ // this avoids possible overflow, but appears to be marginally less accurate:
+ result *= pow((agh / cgh) * (bgh / cgh), b);
+ else
+ result *= pow((agh * bgh) / (cgh * cgh), b);
+ result *= sqrt(boost::math::constants::e<T>() / bgh);
+
+ // If a and b were originally less than 1 we need to scale the result:
+ result *= prefix;
+
+ return result;
+} // template <class T, class Lanczos> beta_imp(T a, T b, const Lanczos&)
+
+//
+// Generic implementation of Beta(a,b) without Lanczos approximation support
+// (Caution this is slow!!!):
+//
+template <class T, class Policy>
+T beta_imp(T a, T b, const lanczos::undefined_lanczos& /* l */, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ if(a <= 0)
+ policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got a=%1%).", a, pol);
+ if(b <= 0)
+ policies::raise_domain_error<T>("boost::math::beta<%1%>(%1%,%1%)", "The arguments to the beta function must be greater than zero (got b=%1%).", b, pol);
+
+ T result;
+
+ T prefix = 1;
+ T c = a + b;
+
+ // special cases:
+ if((c == a) && (b < tools::epsilon<T>()))
+ return boost::math::tgamma(b, pol);
+ else if((c == b) && (a < tools::epsilon<T>()))
+ return boost::math::tgamma(a, pol);
+ if(b == 1)
+ return 1/a;
+ else if(a == 1)
+ return 1/b;
+
+ // shift to a and b > 1 if required:
+ if(a < 1)
+ {
+ prefix *= c / a;
+ c += 1;
+ a += 1;
+ }
+ if(b < 1)
+ {
+ prefix *= c / b;
+ c += 1;
+ b += 1;
+ }
+ if(a < b)
+ std::swap(a, b);
+
+ // set integration limits:
+ T la = (std::max)(T(10), a);
+ T lb = (std::max)(T(10), b);
+ T lc = (std::max)(T(10), T(a+b));
+
+ // calculate the fraction parts:
+ T sa = detail::lower_gamma_series(a, la, pol) / a;
+ sa += detail::upper_gamma_fraction(a, la, ::boost::math::policies::get_epsilon<T, Policy>());
+ T sb = detail::lower_gamma_series(b, lb, pol) / b;
+ sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::get_epsilon<T, Policy>());
+ T sc = detail::lower_gamma_series(c, lc, pol) / c;
+ sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::get_epsilon<T, Policy>());
+
+ // and the exponent part:
+ result = exp(lc - la - lb) * pow(la/lc, a) * pow(lb/lc, b);
+
+ // and combine:
+ result *= sa * sb / sc;
+
+ // if a and b were originally less than 1 we need to scale the result:
+ result *= prefix;
+
+ return result;
+} // template <class T>T beta_imp(T a, T b, const lanczos::undefined_lanczos& l)
+
+
+//
+// Compute the leading power terms in the incomplete Beta:
+//
+// (x^a)(y^b)/Beta(a,b) when normalised, and
+// (x^a)(y^b) otherwise.
+//
+// Almost all of the error in the incomplete beta comes from this
+// function: particularly when a and b are large. Computing large
+// powers are *hard* though, and using logarithms just leads to
+// horrendous cancellation errors.
+//
+template <class T, class Lanczos, class Policy>
+T ibeta_power_terms(T a,
+ T b,
+ T x,
+ T y,
+ const Lanczos&,
+ bool normalised,
+ const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ if(!normalised)
+ {
+ // can we do better here?
+ return pow(x, a) * pow(y, b);
+ }
+
+ T result;
+
+ T prefix = 1;
+ T c = a + b;
+
+ // combine power terms with Lanczos approximation:
+ T agh = a + Lanczos::g() - T(0.5);
+ T bgh = b + Lanczos::g() - T(0.5);
+ T cgh = c + Lanczos::g() - T(0.5);
+ result = Lanczos::lanczos_sum_expG_scaled(c) / (Lanczos::lanczos_sum_expG_scaled(a) * Lanczos::lanczos_sum_expG_scaled(b));
+
+ // l1 and l2 are the base of the exponents minus one:
+ T l1 = (x * b - y * agh) / agh;
+ T l2 = (y * a - x * bgh) / bgh;
+ if(((std::min)(fabs(l1), fabs(l2)) < 0.2))
+ {
+ // when the base of the exponent is very near 1 we get really
+ // gross errors unless extra care is taken:
+ if((l1 * l2 > 0) || ((std::min)(a, b) < 1))
+ {
+ //
+ // This first branch handles the simple cases where either:
+ //
+ // * The two power terms both go in the same direction
+ // (towards zero or towards infinity). In this case if either
+ // term overflows or underflows, then the product of the two must
+ // do so also.
+ // *Alternatively if one exponent is less than one, then we
+ // can't productively use it to eliminate overflow or underflow
+ // from the other term. Problems with spurious overflow/underflow
+ // can't be ruled out in this case, but it is *very* unlikely
+ // since one of the power terms will evaluate to a number close to 1.
+ //
+ if(fabs(l1) < 0.1)
+ {
+ result *= exp(a * boost::math::log1p(l1, pol));
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ result *= pow((x * cgh) / agh, a);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ if(fabs(l2) < 0.1)
+ {
+ result *= exp(b * boost::math::log1p(l2, pol));
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ result *= pow((y * cgh) / bgh, b);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ }
+ else if((std::max)(fabs(l1), fabs(l2)) < 0.5)
+ {
+ //
+ // Both exponents are near one and both the exponents are
+ // greater than one and further these two
+ // power terms tend in opposite directions (one towards zero,
+ // the other towards infinity), so we have to combine the terms
+ // to avoid any risk of overflow or underflow.
+ //
+ // We do this by moving one power term inside the other, we have:
+ //
+ // (1 + l1)^a * (1 + l2)^b
+ // = ((1 + l1)*(1 + l2)^(b/a))^a
+ // = (1 + l1 + l3 + l1*l3)^a ; l3 = (1 + l2)^(b/a) - 1
+ // = exp((b/a) * log(1 + l2)) - 1
+ //
+ // The tricky bit is deciding which term to move inside :-)
+ // By preference we move the larger term inside, so that the
+ // size of the largest exponent is reduced. However, that can
+ // only be done as long as l3 (see above) is also small.
+ //
+ bool small_a = a < b;
+ T ratio = b / a;
+ if((small_a && (ratio * l2 < 0.1)) || (!small_a && (l1 / ratio > 0.1)))
+ {
+ T l3 = boost::math::expm1(ratio * boost::math::log1p(l2, pol), pol);
+ l3 = l1 + l3 + l3 * l1;
+ l3 = a * boost::math::log1p(l3, pol);
+ result *= exp(l3);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ T l3 = boost::math::expm1(boost::math::log1p(l1, pol) / ratio, pol);
+ l3 = l2 + l3 + l3 * l2;
+ l3 = b * boost::math::log1p(l3, pol);
+ result *= exp(l3);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ }
+ else if(fabs(l1) < fabs(l2))
+ {
+ // First base near 1 only:
+ T l = a * boost::math::log1p(l1, pol)
+ + b * log((y * cgh) / bgh);
+ result *= exp(l);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ // Second base near 1 only:
+ T l = b * boost::math::log1p(l2, pol)
+ + a * log((x * cgh) / agh);
+ result *= exp(l);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ }
+ else
+ {
+ // general case:
+ T b1 = (x * cgh) / agh;
+ T b2 = (y * cgh) / bgh;
+ l1 = a * log(b1);
+ l2 = b * log(b2);
+ BOOST_MATH_INSTRUMENT_VARIABLE(b1);
+ BOOST_MATH_INSTRUMENT_VARIABLE(b2);
+ BOOST_MATH_INSTRUMENT_VARIABLE(l1);
+ BOOST_MATH_INSTRUMENT_VARIABLE(l2);
+ if((l1 >= tools::log_max_value<T>())
+ || (l1 <= tools::log_min_value<T>())
+ || (l2 >= tools::log_max_value<T>())
+ || (l2 <= tools::log_min_value<T>())
+ )
+ {
+ // Oops, overflow, sidestep:
+ if(a < b)
+ result *= pow(pow(b2, b/a) * b1, a);
+ else
+ result *= pow(pow(b1, a/b) * b2, b);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ // finally the normal case:
+ result *= pow(b1, a) * pow(b2, b);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ }
+ // combine with the leftover terms from the Lanczos approximation:
+ result *= sqrt(bgh / boost::math::constants::e<T>());
+ result *= sqrt(agh / cgh);
+ result *= prefix;
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+
+ return result;
+}
+//
+// Compute the leading power terms in the incomplete Beta:
+//
+// (x^a)(y^b)/Beta(a,b) when normalised, and
+// (x^a)(y^b) otherwise.
+//
+// Almost all of the error in the incomplete beta comes from this
+// function: particularly when a and b are large. Computing large
+// powers are *hard* though, and using logarithms just leads to
+// horrendous cancellation errors.
+//
+// This version is generic, slow, and does not use the Lanczos approximation.
+//
+template <class T, class Policy>
+T ibeta_power_terms(T a,
+ T b,
+ T x,
+ T y,
+ const boost::math::lanczos::undefined_lanczos&,
+ bool normalised,
+ const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ if(!normalised)
+ {
+ return pow(x, a) * pow(y, b);
+ }
+
+ T result= 0; // assignment here silences warnings later
+
+ T c = a + b;
+
+ // integration limits for the gamma functions:
+ //T la = (std::max)(T(10), a);
+ //T lb = (std::max)(T(10), b);
+ //T lc = (std::max)(T(10), a+b);
+ T la = a + 5;
+ T lb = b + 5;
+ T lc = a + b + 5;
+ // gamma function partials:
+ T sa = detail::lower_gamma_series(a, la, pol) / a;
+ sa += detail::upper_gamma_fraction(a, la, ::boost::math::policies::get_epsilon<T, Policy>());
+ T sb = detail::lower_gamma_series(b, lb, pol) / b;
+ sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::get_epsilon<T, Policy>());
+ T sc = detail::lower_gamma_series(c, lc, pol) / c;
+ sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::get_epsilon<T, Policy>());
+ // gamma function powers combined with incomplete beta powers:
+
+ T b1 = (x * lc) / la;
+ T b2 = (y * lc) / lb;
+ T e1 = lc - la - lb;
+ T lb1 = a * log(b1);
+ T lb2 = b * log(b2);
+
+ if((lb1 >= tools::log_max_value<T>())
+ || (lb1 <= tools::log_min_value<T>())
+ || (lb2 >= tools::log_max_value<T>())
+ || (lb2 <= tools::log_min_value<T>())
+ || (e1 >= tools::log_max_value<T>())
+ || (e1 <= tools::log_min_value<T>())
+ )
+ {
+ result = exp(lb1 + lb2 - e1);
+ }
+ else
+ {
+ T p1, p2;
+ if((fabs(b1 - 1) * a < 10) && (a > 1))
+ p1 = exp(a * boost::math::log1p((x * b - y * la) / la, pol));
+ else
+ p1 = pow(b1, a);
+ if((fabs(b2 - 1) * b < 10) && (b > 1))
+ p2 = exp(b * boost::math::log1p((y * a - x * lb) / lb, pol));
+ else
+ p2 = pow(b2, b);
+ T p3 = exp(e1);
+ result = p1 * p2 / p3;
+ }
+ // and combine with the remaining gamma function components:
+ result /= sa * sb / sc;
+
+ return result;
+}
+//
+// Series approximation to the incomplete beta:
+//
+template <class T>
+struct ibeta_series_t
+{
+ typedef T result_type;
+ ibeta_series_t(T a_, T b_, T x_, T mult) : result(mult), x(x_), apn(a_), poch(1-b_), n(1) {}
+ T operator()()
+ {
+ T r = result / apn;
+ apn += 1;
+ result *= poch * x / n;
+ ++n;
+ poch += 1;
+ return r;
+ }
+private:
+ T result, x, apn, poch;
+ int n;
+};
+
+template <class T, class Lanczos, class Policy>
+T ibeta_series(T a, T b, T x, T s0, const Lanczos&, bool normalised, T* p_derivative, T y, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ T result;
+
+ BOOST_ASSERT((p_derivative == 0) || normalised);
+
+ if(normalised)
+ {
+ T c = a + b;
+
+ // incomplete beta power term, combined with the Lanczos approximation:
+ T agh = a + Lanczos::g() - T(0.5);
+ T bgh = b + Lanczos::g() - T(0.5);
+ T cgh = c + Lanczos::g() - T(0.5);
+ result = Lanczos::lanczos_sum_expG_scaled(c) / (Lanczos::lanczos_sum_expG_scaled(a) * Lanczos::lanczos_sum_expG_scaled(b));
+ if(a * b < bgh * 10)
+ result *= exp((b - 0.5f) * boost::math::log1p(a / bgh, pol));
+ else
+ result *= pow(cgh / bgh, b - 0.5f);
+ result *= pow(x * cgh / agh, a);
+ result *= sqrt(agh / boost::math::constants::e<T>());
+
+ if(p_derivative)
+ {
+ *p_derivative = result * pow(y, b);
+ BOOST_ASSERT(*p_derivative >= 0);
+ }
+ }
+ else
+ {
+ // Non-normalised, just compute the power:
+ result = pow(x, a);
+ }
+ if(result < tools::min_value<T>())
+ return s0; // Safeguard: series can't cope with denorms.
+ ibeta_series_t<T> s(a, b, x, result);
+ 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, s0);
+ policies::check_series_iterations<T>("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (with lanczos)", max_iter, pol);
+ return result;
+}
+//
+// Incomplete Beta series again, this time without Lanczos support:
+//
+template <class T, class Policy>
+T ibeta_series(T a, T b, T x, T s0, const boost::math::lanczos::undefined_lanczos&, bool normalised, T* p_derivative, T y, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ T result;
+ BOOST_ASSERT((p_derivative == 0) || normalised);
+
+ if(normalised)
+ {
+ T c = a + b;
+
+ // figure out integration limits for the gamma function:
+ //T la = (std::max)(T(10), a);
+ //T lb = (std::max)(T(10), b);
+ //T lc = (std::max)(T(10), a+b);
+ T la = a + 5;
+ T lb = b + 5;
+ T lc = a + b + 5;
+
+ // calculate the gamma parts:
+ T sa = detail::lower_gamma_series(a, la, pol) / a;
+ sa += detail::upper_gamma_fraction(a, la, ::boost::math::policies::get_epsilon<T, Policy>());
+ T sb = detail::lower_gamma_series(b, lb, pol) / b;
+ sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::get_epsilon<T, Policy>());
+ T sc = detail::lower_gamma_series(c, lc, pol) / c;
+ sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::get_epsilon<T, Policy>());
+
+ // and their combined power-terms:
+ T b1 = (x * lc) / la;
+ T b2 = lc/lb;
+ T e1 = lc - la - lb;
+ T lb1 = a * log(b1);
+ T lb2 = b * log(b2);
+
+ if((lb1 >= tools::log_max_value<T>())
+ || (lb1 <= tools::log_min_value<T>())
+ || (lb2 >= tools::log_max_value<T>())
+ || (lb2 <= tools::log_min_value<T>())
+ || (e1 >= tools::log_max_value<T>())
+ || (e1 <= tools::log_min_value<T>()) )
+ {
+ T p = lb1 + lb2 - e1;
+ result = exp(p);
+ }
+ else
+ {
+ result = pow(b1, a);
+ if(a * b < lb * 10)
+ result *= exp(b * boost::math::log1p(a / lb, pol));
+ else
+ result *= pow(b2, b);
+ result /= exp(e1);
+ }
+ // and combine the results:
+ result /= sa * sb / sc;
+
+ if(p_derivative)
+ {
+ *p_derivative = result * pow(y, b);
+ BOOST_ASSERT(*p_derivative >= 0);
+ }
+ }
+ else
+ {
+ // Non-normalised, just compute the power:
+ result = pow(x, a);
+ }
+ if(result < tools::min_value<T>())
+ return s0; // Safeguard: series can't cope with denorms.
+ ibeta_series_t<T> s(a, b, x, result);
+ 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, s0);
+ policies::check_series_iterations<T>("boost::math::ibeta<%1%>(%1%, %1%, %1%) in ibeta_series (without lanczos)", max_iter, pol);
+ return result;
+}
+
+//
+// Continued fraction for the incomplete beta:
+//
+template <class T>
+struct ibeta_fraction2_t
+{
+ typedef std::pair<T, T> result_type;
+
+ ibeta_fraction2_t(T a_, T b_, T x_) : a(a_), b(b_), x(x_), m(0) {}
+
+ result_type operator()()
+ {
+ T aN = (a + m - 1) * (a + b + m - 1) * m * (b - m) * x * x;
+ T denom = (a + 2 * m - 1);
+ aN /= denom * denom;
+
+ T bN = m;
+ bN += (m * (b - m) * x) / (a + 2*m - 1);
+ bN += ((a + m) * (a - (a + b) * x + 1 + m *(2 - x))) / (a + 2*m + 1);
+
+ ++m;
+
+ return std::make_pair(aN, bN);
+ }
+
+private:
+ T a, b, x;
+ int m;
+};
+//
+// Evaluate the incomplete beta via the continued fraction representation:
+//
+template <class T, class Policy>
+inline T ibeta_fraction2(T a, T b, T x, T y, const Policy& pol, bool normalised, T* p_derivative)
+{
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+ BOOST_MATH_STD_USING
+ T result = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol);
+ if(p_derivative)
+ {
+ *p_derivative = result;
+ BOOST_ASSERT(*p_derivative >= 0);
+ }
+ if(result == 0)
+ return result;
+
+ ibeta_fraction2_t<T> f(a, b, x);
+ T fract = boost::math::tools::continued_fraction_b(f, boost::math::policies::get_epsilon<T, Policy>());
+ return result / fract;
+}
+//
+// Computes the difference between ibeta(a,b,x) and ibeta(a+k,b,x):
+//
+template <class T, class Policy>
+T ibeta_a_step(T a, T b, T x, T y, int k, const Policy& pol, bool normalised, T* p_derivative)
+{
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(k);
+
+ T prefix = ibeta_power_terms(a, b, x, y, lanczos_type(), normalised, pol);
+ if(p_derivative)
+ {
+ *p_derivative = prefix;
+ BOOST_ASSERT(*p_derivative >= 0);
+ }
+ prefix /= a;
+ if(prefix == 0)
+ return prefix;
+ T sum = 1;
+ T term = 1;
+ // series summation from 0 to k-1:
+ for(int i = 0; i < k-1; ++i)
+ {
+ term *= (a+b+i) * x / (a+i+1);
+ sum += term;
+ }
+ prefix *= sum;
+
+ return prefix;
+}
+//
+// This function is only needed for the non-regular incomplete beta,
+// it computes the delta in:
+// beta(a,b,x) = prefix + delta * beta(a+k,b,x)
+// it is currently only called for small k.
+//
+template <class T>
+inline T rising_factorial_ratio(T a, T b, int k)
+{
+ // calculate:
+ // (a)(a+1)(a+2)...(a+k-1)
+ // _______________________
+ // (b)(b+1)(b+2)...(b+k-1)
+
+ // This is only called with small k, for large k
+ // it is grossly inefficient, do not use outside it's
+ // intended purpose!!!
+ BOOST_MATH_INSTRUMENT_VARIABLE(k);
+ if(k == 0)
+ return 1;
+ T result = 1;
+ for(int i = 0; i < k; ++i)
+ result *= (a+i) / (b+i);
+ return result;
+}
+//
+// Routine for a > 15, b < 1
+//
+// Begin by figuring out how large our table of Pn's should be,
+// quoted accuracies are "guestimates" based on empiracal observation.
+// Note that the table size should never exceed the size of our
+// tables of factorials.
+//
+template <class T>
+struct Pn_size
+{
+ // This is likely to be enough for ~35-50 digit accuracy
+ // but it's hard to quantify exactly:
+ BOOST_STATIC_CONSTANT(unsigned, value = 50);
+ BOOST_STATIC_ASSERT(::boost::math::max_factorial<T>::value >= 100);
+};
+template <>
+struct Pn_size<float>
+{
+ BOOST_STATIC_CONSTANT(unsigned, value = 15); // ~8-15 digit accuracy
+ BOOST_STATIC_ASSERT(::boost::math::max_factorial<float>::value >= 30);
+};
+template <>
+struct Pn_size<double>
+{
+ BOOST_STATIC_CONSTANT(unsigned, value = 30); // 16-20 digit accuracy
+ BOOST_STATIC_ASSERT(::boost::math::max_factorial<double>::value >= 60);
+};
+template <>
+struct Pn_size<long double>
+{
+ BOOST_STATIC_CONSTANT(unsigned, value = 50); // ~35-50 digit accuracy
+ BOOST_STATIC_ASSERT(::boost::math::max_factorial<long double>::value >= 100);
+};
+
+template <class T, class Policy>
+T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Policy& pol, bool normalised)
+{
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+ BOOST_MATH_STD_USING
+ //
+ // This is DiDonato and Morris's BGRAT routine, see Eq's 9 through 9.6.
+ //
+ // Some values we'll need later, these are Eq 9.1:
+ //
+ T bm1 = b - 1;
+ T t = a + bm1 / 2;
+ T lx, u;
+ if(y < 0.35)
+ lx = boost::math::log1p(-y, pol);
+ else
+ lx = log(x);
+ u = -t * lx;
+ // and from from 9.2:
+ T prefix;
+ T h = regularised_gamma_prefix(b, u, pol, lanczos_type());
+ if(h <= tools::min_value<T>())
+ return s0;
+ if(normalised)
+ {
+ prefix = h / boost::math::tgamma_delta_ratio(a, b, pol);
+ prefix /= pow(t, b);
+ }
+ else
+ {
+ prefix = full_igamma_prefix(b, u, pol) / pow(t, b);
+ }
+ prefix *= mult;
+ //
+ // now we need the quantity Pn, unfortunatately this is computed
+ // recursively, and requires a full history of all the previous values
+ // so no choice but to declare a big table and hope it's big enough...
+ //
+ T p[ ::boost::math::detail::Pn_size<T>::value ] = { 1 }; // see 9.3.
+ //
+ // Now an initial value for J, see 9.6:
+ //
+ T j = boost::math::gamma_q(b, u, pol) / h;
+ //
+ // Now we can start to pull things together and evaluate the sum in Eq 9:
+ //
+ T sum = s0 + prefix * j; // Value at N = 0
+ // some variables we'll need:
+ unsigned tnp1 = 1; // 2*N+1
+ T lx2 = lx / 2;
+ lx2 *= lx2;
+ T lxp = 1;
+ T t4 = 4 * t * t;
+ T b2n = b;
+
+ for(unsigned n = 1; n < sizeof(p)/sizeof(p[0]); ++n)
+ {
+ /*
+ // debugging code, enable this if you want to determine whether
+ // the table of Pn's is large enough...
+ //
+ static int max_count = 2;
+ if(n > max_count)
+ {
+ max_count = n;
+ std::cerr << "Max iterations in BGRAT was " << n << std::endl;
+ }
+ */
+ //
+ // begin by evaluating the next Pn from Eq 9.4:
+ //
+ tnp1 += 2;
+ p[n] = 0;
+ T mbn = b - n;
+ unsigned tmp1 = 3;
+ for(unsigned m = 1; m < n; ++m)
+ {
+ mbn = m * b - n;
+ p[n] += mbn * p[n-m] / boost::math::unchecked_factorial<T>(tmp1);
+ tmp1 += 2;
+ }
+ p[n] /= n;
+ p[n] += bm1 / boost::math::unchecked_factorial<T>(tnp1);
+ //
+ // Now we want Jn from Jn-1 using Eq 9.6:
+ //
+ j = (b2n * (b2n + 1) * j + (u + b2n + 1) * lxp) / t4;
+ lxp *= lx2;
+ b2n += 2;
+ //
+ // pull it together with Eq 9:
+ //
+ T r = prefix * p[n] * j;
+ sum += r;
+ if(r > 1)
+ {
+ if(fabs(r) < fabs(tools::epsilon<T>() * sum))
+ break;
+ }
+ else
+ {
+ if(fabs(r / tools::epsilon<T>()) < fabs(sum))
+ break;
+ }
+ }
+ return sum;
+} // template <class T, class Lanczos>T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const Lanczos& l, bool normalised)
+
+//
+// For integer arguments we can relate the incomplete beta to the
+// complement of the binomial distribution cdf and use this finite sum.
+//
+template <class T>
+inline T binomial_ccdf(T n, T k, T x, T y)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ T result = pow(x, n);
+ T term = result;
+ for(unsigned i = itrunc(T(n - 1)); i > k; --i)
+ {
+ term *= ((i + 1) * y) / ((n - i) * x) ;
+ result += term;
+ }
+
+ return result;
+}
+
+
+//
+// The incomplete beta function implementation:
+// This is just a big bunch of spagetti code to divide up the
+// input range and select the right implementation method for
+// each domain:
+//
+template <class T, class Policy>
+T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised, T* p_derivative)
+{
+ static const char* function = "boost::math::ibeta<%1%>(%1%, %1%, %1%)";
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+ BOOST_MATH_STD_USING // for ADL of std math functions.
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(a);
+ BOOST_MATH_INSTRUMENT_VARIABLE(b);
+ BOOST_MATH_INSTRUMENT_VARIABLE(x);
+ BOOST_MATH_INSTRUMENT_VARIABLE(inv);
+ BOOST_MATH_INSTRUMENT_VARIABLE(normalised);
+
+ bool invert = inv;
+ T fract;
+ T y = 1 - x;
+
+ BOOST_ASSERT((p_derivative == 0) || normalised);
+
+ if(p_derivative)
+ *p_derivative = -1; // value not set.
+
+ if((x < 0) || (x > 1))
+ policies::raise_domain_error<T>(function, "Parameter x outside the range [0,1] in the incomplete beta function (got x=%1%).", x, pol);
+
+ if(normalised)
+ {
+ if(a < 0)
+ policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be >= zero (got a=%1%).", a, pol);
+ if(b < 0)
+ policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be >= zero (got b=%1%).", b, pol);
+ // extend to a few very special cases:
+ if(a == 0)
+ {
+ if(b == 0)
+ policies::raise_domain_error<T>(function, "The arguments a and b to the incomplete beta function cannot both be zero, with x=%1%.", x, pol);
+ if(b > 0)
+ return inv ? 0 : 1;
+ }
+ else if(b == 0)
+ {
+ if(a > 0)
+ return inv ? 1 : 0;
+ }
+ }
+ else
+ {
+ if(a <= 0)
+ policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be greater than zero (got a=%1%).", a, pol);
+ if(b <= 0)
+ policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be greater than zero (got b=%1%).", b, pol);
+ }
+
+ if(x == 0)
+ {
+ if(p_derivative)
+ {
+ *p_derivative = (a == 1) ? (T)1 : (a < 1) ? T(tools::max_value<T>() / 2) : T(tools::min_value<T>() * 2);
+ }
+ return (invert ? (normalised ? T(1) : boost::math::beta(a, b, pol)) : T(0));
+ }
+ if(x == 1)
+ {
+ if(p_derivative)
+ {
+ *p_derivative = (b == 1) ? T(1) : (b < 1) ? T(tools::max_value<T>() / 2) : T(tools::min_value<T>() * 2);
+ }
+ return (invert == 0 ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0);
+ }
+
+ if((std::min)(a, b) <= 1)
+ {
+ if(x > 0.5)
+ {
+ std::swap(a, b);
+ std::swap(x, y);
+ invert = !invert;
+ BOOST_MATH_INSTRUMENT_VARIABLE(invert);
+ }
+ if((std::max)(a, b) <= 1)
+ {
+ // Both a,b < 1:
+ if((a >= (std::min)(T(0.2), b)) || (pow(x, a) <= 0.9))
+ {
+ if(!invert)
+ {
+ fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ else
+ {
+ std::swap(a, b);
+ std::swap(x, y);
+ invert = !invert;
+ if(y >= 0.3)
+ {
+ if(!invert)
+ {
+ fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ else
+ {
+ // Sidestep on a, and then use the series representation:
+ T prefix;
+ if(!normalised)
+ {
+ prefix = rising_factorial_ratio(T(a+b), a, 20);
+ }
+ else
+ {
+ prefix = 1;
+ }
+ fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative);
+ if(!invert)
+ {
+ fract = beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ }
+ }
+ else
+ {
+ // One of a, b < 1 only:
+ if((b <= 1) || ((x < 0.1) && (pow(b * x, a) <= 0.7)))
+ {
+ if(!invert)
+ {
+ fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ else
+ {
+ std::swap(a, b);
+ std::swap(x, y);
+ invert = !invert;
+
+ if(y >= 0.3)
+ {
+ if(!invert)
+ {
+ fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ else if(a >= 15)
+ {
+ if(!invert)
+ {
+ fract = beta_small_b_large_a_series(a, b, x, y, T(0), T(1), pol, normalised);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -beta_small_b_large_a_series(a, b, x, y, fract, T(1), pol, normalised);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ else
+ {
+ // Sidestep to improve errors:
+ T prefix;
+ if(!normalised)
+ {
+ prefix = rising_factorial_ratio(T(a+b), a, 20);
+ }
+ else
+ {
+ prefix = 1;
+ }
+ fract = ibeta_a_step(a, b, x, y, 20, pol, normalised, p_derivative);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ if(!invert)
+ {
+ fract = beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -beta_small_b_large_a_series(T(a + 20), b, x, y, fract, prefix, pol, normalised);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Both a,b >= 1:
+ T lambda;
+ if(a < b)
+ {
+ lambda = a - (a + b) * x;
+ }
+ else
+ {
+ lambda = (a + b) * y - b;
+ }
+ if(lambda < 0)
+ {
+ std::swap(a, b);
+ std::swap(x, y);
+ invert = !invert;
+ BOOST_MATH_INSTRUMENT_VARIABLE(invert);
+ }
+
+ if(b < 40)
+ {
+ if((floor(a) == a) && (floor(b) == b))
+ {
+ // relate to the binomial distribution and use a finite sum:
+ T k = a - 1;
+ T n = b + k;
+ fract = binomial_ccdf(n, k, x, y);
+ if(!normalised)
+ fract *= boost::math::beta(a, b, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else if(b * x <= 0.7)
+ {
+ if(!invert)
+ {
+ fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract = -(normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -ibeta_series(a, b, x, fract, lanczos_type(), normalised, p_derivative, y, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ else if(a > 15)
+ {
+ // sidestep so we can use the series representation:
+ int n = itrunc(T(floor(b)), pol);
+ if(n == b)
+ --n;
+ T bbar = b - n;
+ T prefix;
+ if(!normalised)
+ {
+ prefix = rising_factorial_ratio(T(a+bbar), bbar, n);
+ }
+ else
+ {
+ prefix = 1;
+ }
+ fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast<T*>(0));
+ fract = beta_small_b_large_a_series(a, bbar, x, y, fract, T(1), pol, normalised);
+ fract /= prefix;
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else if(normalised)
+ {
+ // the formula here for the non-normalised case is tricky to figure
+ // out (for me!!), and requires two pochhammer calculations rather
+ // than one, so leave it for now....
+ int n = itrunc(T(floor(b)), pol);
+ T bbar = b - n;
+ if(bbar <= 0)
+ {
+ --n;
+ bbar += 1;
+ }
+ fract = ibeta_a_step(bbar, a, y, x, n, pol, normalised, static_cast<T*>(0));
+ fract += ibeta_a_step(a, bbar, x, y, 20, pol, normalised, static_cast<T*>(0));
+ if(invert)
+ fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
+ //fract = ibeta_series(a+20, bbar, x, fract, l, normalised, p_derivative, y);
+ fract = beta_small_b_large_a_series(T(a+20), bbar, x, y, fract, T(1), pol, normalised);
+ if(invert)
+ {
+ fract = -fract;
+ invert = false;
+ }
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ else
+ {
+ fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ else
+ {
+ fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
+ BOOST_MATH_INSTRUMENT_VARIABLE(fract);
+ }
+ }
+ if(p_derivative)
+ {
+ if(*p_derivative < 0)
+ {
+ *p_derivative = ibeta_power_terms(a, b, x, y, lanczos_type(), true, pol);
+ }
+ T div = y * x;
+
+ if(*p_derivative != 0)
+ {
+ if((tools::max_value<T>() * div < *p_derivative))
+ {
+ // overflow, return an arbitarily large value:
+ *p_derivative = tools::max_value<T>() / 2;
+ }
+ else
+ {
+ *p_derivative /= div;
+ }
+ }
+ }
+ return invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) - fract : fract;
+} // template <class T, class Lanczos>T ibeta_imp(T a, T b, T x, const Lanczos& l, bool inv, bool normalised)
+
+template <class T, class Policy>
+inline T ibeta_imp(T a, T b, T x, const Policy& pol, bool inv, bool normalised)
+{
+ return ibeta_imp(a, b, x, pol, inv, normalised, static_cast<T*>(0));
+}
+
+template <class T, class Policy>
+T ibeta_derivative_imp(T a, T b, T x, const Policy& pol)
+{
+ static const char* function = "ibeta_derivative<%1%>(%1%,%1%,%1%)";
+ //
+ // start with the usual error checks:
+ //
+ if(a <= 0)
+ policies::raise_domain_error<T>(function, "The argument a to the incomplete beta function must be greater than zero (got a=%1%).", a, pol);
+ if(b <= 0)
+ policies::raise_domain_error<T>(function, "The argument b to the incomplete beta function must be greater than zero (got b=%1%).", b, pol);
+ if((x < 0) || (x > 1))
+ policies::raise_domain_error<T>(function, "Parameter x outside the range [0,1] in the incomplete beta function (got x=%1%).", x, pol);
+ //
+ // Now the corner cases:
+ //
+ if(x == 0)
+ {
+ return (a > 1) ? 0 :
+ (a == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else if(x == 1)
+ {
+ return (b > 1) ? 0 :
+ (b == 1) ? 1 / boost::math::beta(a, b, pol) : policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ //
+ // Now the regular cases:
+ //
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+ T f1 = ibeta_power_terms<T>(a, b, x, 1 - x, lanczos_type(), true, pol);
+ T y = (1 - x) * x;
+
+ if(f1 == 0)
+ return 0;
+
+ if((tools::max_value<T>() * y < f1))
+ {
+ // overflow:
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+
+ f1 /= y;
+
+ return f1;
+}
+//
+// Some forwarding functions that dis-ambiguate the third argument type:
+//
+template <class RT1, class RT2, class Policy>
+inline typename tools::promote_args<RT1, RT2>::type
+ beta(RT1 a, RT2 b, const Policy&, const mpl::true_*)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<RT1, RT2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename lanczos::lanczos<value_type, 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::beta_imp(static_cast<value_type>(a), static_cast<value_type>(b), evaluation_type(), forwarding_policy()), "boost::math::beta<%1%>(%1%,%1%)");
+}
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ beta(RT1 a, RT2 b, RT3 x, const mpl::false_*)
+{
+ return boost::math::beta(a, b, x, policies::policy<>());
+}
+} // namespace detail
+
+//
+// The actual function entry-points now follow, these just figure out
+// which Lanczos approximation to use
+// and forward to the implementation functions:
+//
+template <class RT1, class RT2, class A>
+inline typename tools::promote_args<RT1, RT2, A>::type
+ beta(RT1 a, RT2 b, A arg)
+{
+ typedef typename policies::is_policy<A>::type tag;
+ return boost::math::detail::beta(a, b, arg, static_cast<tag*>(0));
+}
+
+template <class RT1, class RT2>
+inline typename tools::promote_args<RT1, RT2>::type
+ beta(RT1 a, RT2 b)
+{
+ return boost::math::beta(a, b, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ beta(RT1 a, RT2 b, RT3 x, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename lanczos::lanczos<value_type, 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), false, false), "boost::math::beta<%1%>(%1%,%1%,%1%)");
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ betac(RT1 a, RT2 b, RT3 x, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename lanczos::lanczos<value_type, 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), true, false), "boost::math::betac<%1%>(%1%,%1%,%1%)");
+}
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ betac(RT1 a, RT2 b, RT3 x)
+{
+ return boost::math::betac(a, b, x, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta(RT1 a, RT2 b, RT3 x, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), false, true), "boost::math::ibeta<%1%>(%1%,%1%,%1%)");
+}
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta(RT1 a, RT2 b, RT3 x)
+{
+ return boost::math::ibeta(a, b, x, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac(RT1 a, RT2 b, RT3 x, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy(), true, true), "boost::math::ibetac<%1%>(%1%,%1%,%1%)");
+}
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac(RT1 a, RT2 b, RT3 x)
+{
+ return boost::math::ibetac(a, b, x, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::ibeta_derivative_imp(static_cast<value_type>(a), static_cast<value_type>(b), static_cast<value_type>(x), forwarding_policy()), "boost::math::ibeta_derivative<%1%>(%1%,%1%,%1%)");
+}
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_derivative(RT1 a, RT2 b, RT3 x)
+{
+ return boost::math::ibeta_derivative(a, b, x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#include <boost/math/special_functions/detail/ibeta_inverse.hpp>
+#include <boost/math/special_functions/detail/ibeta_inv_ab.hpp>
+
+#endif // BOOST_MATH_SPECIAL_BETA_HPP
+
+
+
+
+
diff --git a/boost/math/special_functions/binomial.hpp b/boost/math/special_functions/binomial.hpp
new file mode 100644
index 0000000000..16b4f3305d
--- /dev/null
+++ b/boost/math/special_functions/binomial.hpp
@@ -0,0 +1,81 @@
+// Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SF_BINOMIAL_HPP
+#define BOOST_MATH_SF_BINOMIAL_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/factorials.hpp>
+#include <boost/math/special_functions/beta.hpp>
+#include <boost/math/policies/error_handling.hpp>
+
+namespace boost{ namespace math{
+
+template <class T, class Policy>
+T binomial_coefficient(unsigned n, unsigned k, const Policy& pol)
+{
+ BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::binomial_coefficient<%1%>(unsigned, unsigned)";
+ if(k > n)
+ return policies::raise_domain_error<T>(
+ function,
+ "The binomial coefficient is undefined for k > n, but got k = %1%.",
+ k, pol);
+ T result;
+ if((k == 0) || (k == n))
+ return 1;
+ if((k == 1) || (k == n-1))
+ return n;
+
+ if(n <= max_factorial<T>::value)
+ {
+ // Use fast table lookup:
+ result = unchecked_factorial<T>(n);
+ result /= unchecked_factorial<T>(n-k);
+ result /= unchecked_factorial<T>(k);
+ }
+ else
+ {
+ // Use the beta function:
+ if(k < n - k)
+ result = k * beta(static_cast<T>(k), static_cast<T>(n-k+1), pol);
+ else
+ result = (n - k) * beta(static_cast<T>(k+1), static_cast<T>(n-k), pol);
+ if(result == 0)
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ result = 1 / result;
+ }
+ // convert to nearest integer:
+ return ceil(result - 0.5f);
+}
+//
+// Type float can only store the first 35 factorials, in order to
+// increase the chance that we can use a table driven implementation
+// we'll promote to double:
+//
+template <>
+inline float binomial_coefficient<float, policies::policy<> >(unsigned n, unsigned k, const policies::policy<>& pol)
+{
+ return policies::checked_narrowing_cast<float, policies::policy<> >(binomial_coefficient<double>(n, k, pol), "boost::math::binomial_coefficient<%1%>(unsigned,unsigned)");
+}
+
+template <class T>
+inline T binomial_coefficient(unsigned n, unsigned k)
+{
+ return binomial_coefficient<T>(n, k, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+
+#endif // BOOST_MATH_SF_BINOMIAL_HPP
+
+
+
diff --git a/boost/math/special_functions/cbrt.hpp b/boost/math/special_functions/cbrt.hpp
new file mode 100644
index 0000000000..0fc6e0742a
--- /dev/null
+++ b/boost/math/special_functions/cbrt.hpp
@@ -0,0 +1,180 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SF_CBRT_HPP
+#define BOOST_MATH_SF_CBRT_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/mpl/divides.hpp>
+#include <boost/mpl/plus.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+
+namespace boost{ namespace math{
+
+namespace detail
+{
+
+struct big_int_type
+{
+ operator boost::uintmax_t()const;
+};
+
+template <class T>
+struct largest_cbrt_int_type
+{
+ typedef typename mpl::if_<
+ boost::is_convertible<big_int_type, T>,
+ boost::uintmax_t,
+ unsigned int
+ >::type type;
+};
+
+template <class T, class Policy>
+T cbrt_imp(T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ //
+ // cbrt approximation for z in the range [0.5,1]
+ // It's hard to say what number of terms gives the optimum
+ // trade off between precision and performance, this seems
+ // to be about the best for double precision.
+ //
+ // Maximum Deviation Found: 1.231e-006
+ // Expected Error Term: -1.231e-006
+ // Maximum Relative Change in Control Points: 5.982e-004
+ //
+ static const T P[] = {
+ static_cast<T>(0.37568269008611818),
+ static_cast<T>(1.3304968705558024),
+ static_cast<T>(-1.4897101632445036),
+ static_cast<T>(1.2875573098219835),
+ static_cast<T>(-0.6398703759826468),
+ static_cast<T>(0.13584489959258635),
+ };
+ static const T correction[] = {
+ static_cast<T>(0.62996052494743658238360530363911), // 2^-2/3
+ static_cast<T>(0.79370052598409973737585281963615), // 2^-1/3
+ static_cast<T>(1),
+ static_cast<T>(1.2599210498948731647672106072782), // 2^1/3
+ static_cast<T>(1.5874010519681994747517056392723), // 2^2/3
+ };
+
+ if(!(boost::math::isfinite)(z))
+ {
+ return policies::raise_domain_error("boost::math::cbrt<%1%>(%1%)", "Argument to function must be finite but got %1%.", z, pol);
+ }
+
+ int i_exp, sign(1);
+ if(z < 0)
+ {
+ z = -z;
+ sign = -sign;
+ }
+ if(z == 0)
+ return 0;
+
+ T guess = frexp(z, &i_exp);
+ int original_i_exp = i_exp; // save for later
+ guess = tools::evaluate_polynomial(P, guess);
+ int i_exp3 = i_exp / 3;
+
+ typedef typename largest_cbrt_int_type<T>::type shift_type;
+
+ BOOST_STATIC_ASSERT( ::std::numeric_limits<shift_type>::radix == 2);
+
+ if(abs(i_exp3) < std::numeric_limits<shift_type>::digits)
+ {
+ if(i_exp3 > 0)
+ guess *= shift_type(1u) << i_exp3;
+ else
+ guess /= shift_type(1u) << -i_exp3;
+ }
+ else
+ {
+ guess = ldexp(guess, i_exp3);
+ }
+ i_exp %= 3;
+ guess *= correction[i_exp + 2];
+ //
+ // Now inline Halley iteration.
+ // We do this here rather than calling tools::halley_iterate since we can
+ // simplify the expressions algebraically, and don't need most of the error
+ // checking of the boilerplate version as we know in advance that the function
+ // is well behaved...
+ //
+ typedef typename policies::precision<T, Policy>::type prec;
+ typedef typename mpl::divides<prec, mpl::int_<3> >::type prec3;
+ typedef typename mpl::plus<prec3, mpl::int_<3> >::type new_prec;
+ typedef typename policies::normalise<Policy, policies::digits2<new_prec::value> >::type new_policy;
+ //
+ // Epsilon calculation uses compile time arithmetic when it's available for type T,
+ // otherwise uses ldexp to calculate at runtime:
+ //
+ T eps = (new_prec::value > 3) ? policies::get_epsilon<T, new_policy>() : ldexp(T(1), -2 - tools::digits<T>() / 3);
+ T diff;
+
+ if(original_i_exp < std::numeric_limits<T>::max_exponent - 3)
+ {
+ //
+ // Safe from overflow, use the fast method:
+ //
+ do
+ {
+ T g3 = guess * guess * guess;
+ diff = (g3 + z + z) / (g3 + g3 + z);
+ guess *= diff;
+ }
+ while(fabs(1 - diff) > eps);
+ }
+ else
+ {
+ //
+ // Either we're ready to overflow, or we can't tell because numeric_limits isn't
+ // available for type T:
+ //
+ do
+ {
+ T g2 = guess * guess;
+ diff = (g2 - z / guess) / (2 * guess + z / g2);
+ guess -= diff;
+ }
+ while((guess * eps) < fabs(diff));
+ }
+
+ return sign * guess;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type cbrt(T z, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return static_cast<result_type>(detail::cbrt_imp(value_type(z), pol));
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type cbrt(T z)
+{
+ return cbrt(z, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SF_CBRT_HPP
+
+
+
+
diff --git a/boost/math/special_functions/cos_pi.hpp b/boost/math/special_functions/cos_pi.hpp
new file mode 100644
index 0000000000..93102c1cb3
--- /dev/null
+++ b/boost/math/special_functions/cos_pi.hpp
@@ -0,0 +1,68 @@
+// Copyright (c) 2007 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_COS_PI_HPP
+#define BOOST_MATH_COS_PI_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/math/constants/constants.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+template <class T, class Policy>
+T cos_pi_imp(T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ // cos of pi*x:
+ bool invert = false;
+ if(fabs(x) < 0.5)
+ return cos(constants::pi<T>() * x);
+
+ if(x < 1)
+ {
+ x = -x;
+ }
+ T rem = floor(x);
+ if(itrunc(rem, pol) & 1)
+ invert = !invert;
+ rem = x - rem;
+ if(rem > 0.5f)
+ {
+ rem = 1 - rem;
+ invert = !invert;
+ }
+ if(rem == 0.5f)
+ return 0;
+
+ rem = cos(constants::pi<T>() * rem);
+ return invert ? T(-rem) : rem;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type cos_pi(T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ return boost::math::detail::cos_pi_imp<result_type>(x, pol);
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type cos_pi(T x)
+{
+ return boost::math::cos_pi(x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+#endif
+
diff --git a/boost/math/special_functions/detail/bessel_i0.hpp b/boost/math/special_functions/detail/bessel_i0.hpp
new file mode 100644
index 0000000000..2c129facc7
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_i0.hpp
@@ -0,0 +1,102 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_I0_HPP
+#define BOOST_MATH_BESSEL_I0_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/tools/big_constant.hpp>
+#include <boost/assert.hpp>
+
+// Modified Bessel function of the first kind of order zero
+// minimax rational approximations on intervals, see
+// Blair and Edwards, Chalk River Report AECL-4928, 1974
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T>
+T bessel_i0(T x)
+{
+ static const T P1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2335582639474375249e+15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.5050369673018427753e+14)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.2940087627407749166e+13)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.4925101247114157499e+11)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.1912746104985237192e+10)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0313066708737980747e+08)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.9545626019847898221e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.4125195876041896775e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -7.0935347449210549190e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.5453977791786851041e-02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.5172644670688975051e-05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.0517226450451067446e-08)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.6843448573468483278e-11)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.5982226675653184646e-14)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.2487866627945699800e-18)),
+ };
+ static const T Q1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2335582639474375245e+15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.8858692566751002988e+12)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.2207067397808979846e+10)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0377081058062166144e+07)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.8527560179962773045e+03)),
+ 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.2210262233306573296e-04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3067392038106924055e-02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.4700805721174453923e-01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.5674518371240761397e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.3517945679239481621e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.1611322818701131207e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -9.6090021968656180000e+00)),
+ };
+ static const T Q2[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.5194330231005480228e-04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.2547697594819615062e-02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.1151759188741312645e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3982595353892851542e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.0228002066743340583e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.5539563258012929600e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.1446690275135491500e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
+ };
+ T value, factor, r;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ if (x < 0)
+ {
+ x = -x; // even function
+ }
+ if (x == 0)
+ {
+ return static_cast<T>(1);
+ }
+ if (x <= 15) // x in (0, 15]
+ {
+ T y = x * x;
+ value = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ }
+ else // x in (15, \infty)
+ {
+ T y = 1 / x - T(1) / 15;
+ r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = exp(x) / sqrt(x);
+ value = factor * r;
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_I0_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_i1.hpp b/boost/math/special_functions/detail/bessel_i1.hpp
new file mode 100644
index 0000000000..aa4596cfd4
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_i1.hpp
@@ -0,0 +1,105 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_I1_HPP
+#define BOOST_MATH_BESSEL_I1_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/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(T x)
+{
+ static const T P1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4577180278143463643e+15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.7732037840791591320e+14)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.9876779648010090070e+12)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.3357437682275493024e+11)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4828267606612366099e+09)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.0588550724769347106e+07)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.1894091982308017540e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.8225946631657315931e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.7207090827310162436e-01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -9.1746443287817501309e-04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.3466829827635152875e-06)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4831904935994647675e-09)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.1928788903603238754e-12)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.5245515583151902910e-16)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.9705291802535139930e-19)),
+ };
+ static const T Q1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.9154360556286927285e+15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.7887501377547640438e+12)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4386907088588283434e+10)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1594225856856884006e+07)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.1326864679904189920e+03)),
+ 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.4582087408985668208e-05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.9359825138577646443e-04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.9204895411257790122e-02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.4198728018058047439e-01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3960118277609544334e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.9746376087200685843e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.5591872901933459000e-01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -6.0437159056137599999e-02)),
+ };
+ static const T Q2[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.7510433111922824643e-05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2835624489492512649e-03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.4212010813186530069e-02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -8.5017476463217924408e-01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.2593714889036996297e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.8806586721556593450e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0)),
+ };
+ T value, factor, r, w;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ w = abs(x);
+ if (x == 0)
+ {
+ return static_cast<T>(0);
+ }
+ if (w <= 15) // w in (0, 15]
+ {
+ T y = x * x;
+ r = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ factor = w;
+ value = factor * r;
+ }
+ else // w in (15, \infty)
+ {
+ T y = 1 / w - T(1) / 15;
+ r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = exp(w) / sqrt(w);
+ value = factor * r;
+ }
+
+ if (x < 0)
+ {
+ value *= -value; // odd function
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_I1_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_ik.hpp b/boost/math/special_functions/detail/bessel_ik.hpp
new file mode 100644
index 0000000000..a589673ffb
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_ik.hpp
@@ -0,0 +1,428 @@
+// 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;
+
+ // S converges slower than f
+ BOOST_MATH_INSTRUMENT_VARIABLE(Q * delta);
+ BOOST_MATH_INSTRUMENT_VARIABLE(abs(S) * tolerance);
+ if (abs(Q * delta) < abs(S) * tolerance)
+ {
+ break;
+ }
+ }
+ policies::check_series_iterations<T>("boost::math::bessel_ik<%1%>(%1%,%1%) in CF2_ik", k, pol);
+
+ *Kv = sqrt(pi<T>() / (2 * x)) * exp(-x) / S;
+ *Kv1 = *Kv * (0.5f + v + x + (v * v - 0.25f) * f) / x;
+ BOOST_MATH_INSTRUMENT_VARIABLE(*Kv);
+ BOOST_MATH_INSTRUMENT_VARIABLE(*Kv1);
+
+ return 0;
+}
+
+enum{
+ need_i = 1,
+ need_k = 2
+};
+
+// Compute I(v, x) and K(v, x) simultaneously by Temme's method, see
+// Temme, Journal of Computational Physics, vol 19, 324 (1975)
+template <typename T, typename Policy>
+int bessel_ik(T v, T x, T* I, T* K, int kind, const Policy& pol)
+{
+ // Kv1 = K_(v+1), fv = I_(v+1) / I_v
+ // Ku1 = K_(u+1), fu = I_(u+1) / I_u
+ T u, Iv, Kv, Kv1, Ku, Ku1, fv;
+ T W, current, prev, next;
+ bool reflect = false;
+ unsigned n, k;
+ int org_kind = kind;
+ BOOST_MATH_INSTRUMENT_VARIABLE(v);
+ BOOST_MATH_INSTRUMENT_VARIABLE(x);
+ BOOST_MATH_INSTRUMENT_VARIABLE(kind);
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ static const char* function = "boost::math::bessel_ik<%1%>(%1%,%1%)";
+
+ if (v < 0)
+ {
+ reflect = true;
+ v = -v; // v is non-negative from here
+ kind |= need_k;
+ }
+ n = iround(v, pol);
+ u = v - n; // -1/2 <= u < 1/2
+ BOOST_MATH_INSTRUMENT_VARIABLE(n);
+ BOOST_MATH_INSTRUMENT_VARIABLE(u);
+
+ if (x < 0)
+ {
+ *I = *K = policies::raise_domain_error<T>(function,
+ "Got x = %1% but real argument x must be non-negative, complex number result not supported.", x, pol);
+ return 1;
+ }
+ if (x == 0)
+ {
+ Iv = (v == 0) ? static_cast<T>(1) : static_cast<T>(0);
+ if(kind & need_k)
+ {
+ Kv = policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else
+ {
+ Kv = std::numeric_limits<T>::quiet_NaN(); // any value will do
+ }
+
+ if(reflect && (kind & need_i))
+ {
+ T z = (u + n % 2);
+ Iv = boost::math::sin_pi(z, pol) == 0 ?
+ Iv :
+ policies::raise_overflow_error<T>(function, 0, pol); // reflection formula
+ }
+
+ *I = Iv;
+ *K = Kv;
+ return 0;
+ }
+
+ // x is positive until reflection
+ W = 1 / x; // Wronskian
+ if (x <= 2) // x in (0, 2]
+ {
+ temme_ik(u, x, &Ku, &Ku1, pol); // Temme series
+ }
+ else // x in (2, \infty)
+ {
+ CF2_ik(u, x, &Ku, &Ku1, pol); // continued fraction CF2_ik
+ }
+ BOOST_MATH_INSTRUMENT_VARIABLE(Ku);
+ BOOST_MATH_INSTRUMENT_VARIABLE(Ku1);
+ prev = Ku;
+ current = Ku1;
+ T scale = 1;
+ for (k = 1; k <= n; k++) // forward recurrence for K
+ {
+ T fact = 2 * (u + k) / x;
+ if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
+ {
+ prev /= current;
+ scale /= current;
+ current = 1;
+ }
+ next = fact * current + prev;
+ prev = current;
+ current = next;
+ }
+ Kv = prev;
+ Kv1 = current;
+ 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) * sign(scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
+ else
+ *I = Iv + fact / scale; // reflection formula
+ }
+ else
+ {
+ *I = Iv;
+ }
+ if(tools::max_value<T>() * scale < Kv)
+ *K = (org_kind & need_k) ? T(sign(Kv) * sign(scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
+ else
+ *K = Kv / scale;
+ BOOST_MATH_INSTRUMENT_VARIABLE(*I);
+ BOOST_MATH_INSTRUMENT_VARIABLE(*K);
+ return 0;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_IK_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_j0.hpp b/boost/math/special_functions/detail/bessel_j0.hpp
new file mode 100644
index 0000000000..ee25d46f61
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_j0.hpp
@@ -0,0 +1,153 @@
+// 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)
+{
+ 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;
+ T z = x - 0.25f * pi<T>();
+ BOOST_ASSERT(sizeof(PC) == sizeof(QC));
+ BOOST_ASSERT(sizeof(PS) == sizeof(QS));
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (x * pi<T>()));
+ value = factor * (rc * cos(z) - y * rs * sin(z));
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_J0_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_j1.hpp b/boost/math/special_functions/detail/bessel_j1.hpp
new file mode 100644
index 0000000000..3db2503ff6
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_j1.hpp
@@ -0,0 +1,158 @@
+// 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)
+{
+ 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;
+ T z = w - 0.75f * pi<T>();
+ BOOST_ASSERT(sizeof(PC) == sizeof(QC));
+ BOOST_ASSERT(sizeof(PS) == sizeof(QS));
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (w * pi<T>()));
+ value = factor * (rc * cos(z) - y * rs * sin(z));
+ }
+
+ if (x < 0)
+ {
+ value *= -1; // odd function
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_J1_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_jn.hpp b/boost/math/special_functions/detail/bessel_jn.hpp
new file mode 100644
index 0000000000..2bf8d78b74
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_jn.hpp
@@ -0,0 +1,127 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_JN_HPP
+#define BOOST_MATH_BESSEL_JN_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/detail/bessel_j0.hpp>
+#include <boost/math/special_functions/detail/bessel_j1.hpp>
+#include <boost/math/special_functions/detail/bessel_jy.hpp>
+#include <boost/math/special_functions/detail/bessel_jy_asym.hpp>
+#include <boost/math/special_functions/detail/bessel_jy_series.hpp>
+
+// Bessel function of the first kind of integer order
+// J_n(z) is the minimal solution
+// n < abs(z), forward recurrence stable and usable
+// n >= abs(z), forward recurrence unstable, use Miller's algorithm
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_jn(int n, T x, const Policy& pol)
+{
+ T value(0), factor, current, prev, next;
+
+ BOOST_MATH_STD_USING
+
+ //
+ // Reflection has to come first:
+ //
+ if (n < 0)
+ {
+ factor = (n & 0x1) ? -1 : 1; // J_{-n}(z) = (-1)^n J_n(z)
+ n = -n;
+ }
+ else
+ {
+ factor = 1;
+ }
+ //
+ // Special cases:
+ //
+ if (n == 0)
+ {
+ return factor * bessel_j0(x);
+ }
+ if (n == 1)
+ {
+ return factor * bessel_j1(x);
+ }
+
+ if (x == 0) // n >= 2
+ {
+ return static_cast<T>(0);
+ }
+
+ typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
+ if(fabs(x) > asymptotic_bessel_j_limit<T>(n, tag_type()))
+ return factor * asymptotic_bessel_j_large_x_2<T>(n, x);
+
+ BOOST_ASSERT(n > 1);
+ T scale = 1;
+ if (n < abs(x)) // forward recurrence
+ {
+ prev = bessel_j0(x);
+ current = bessel_j1(x);
+ for (int k = 1; k < n; k++)
+ {
+ T fact = 2 * k / x;
+ //
+ // 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)
+ {
+ return factor * bessel_j_small_z_series(T(n), x, pol);
+ }
+ else // backward recurrence
+ {
+ T fn; int s; // fn = J_(n+1) / J_n
+ // |x| <= n, fast convergence for continued fraction CF1
+ boost::math::detail::CF1_jy(static_cast<T>(n), x, &fn, &s, pol);
+ prev = fn;
+ current = 1;
+ for (int k = n; k > 0; k--)
+ {
+ T fact = 2 * k / x;
+ if((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
+
diff --git a/boost/math/special_functions/detail/bessel_jy.hpp b/boost/math/special_functions/detail/bessel_jy.hpp
new file mode 100644
index 0000000000..19f951ab70
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_jy.hpp
@@ -0,0 +1,553 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_JY_HPP
+#define BOOST_MATH_BESSEL_JY_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/special_functions/gamma.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/math/special_functions/hypot.hpp>
+#include <boost/math/special_functions/sin_pi.hpp>
+#include <boost/math/special_functions/cos_pi.hpp>
+#include <boost/math/special_functions/detail/bessel_jy_asym.hpp>
+#include <boost/math/special_functions/detail/bessel_jy_series.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/type_traits/is_floating_point.hpp>
+#include <complex>
+
+// Bessel functions of the first and second kind of fractional order
+
+namespace boost { namespace math {
+
+namespace detail {
+
+//
+// Simultaneous calculation of A&S 9.2.9 and 9.2.10
+// for use in A&S 9.2.5 and 9.2.6.
+// This series is quick to evaluate, but divergent unless
+// x is very large, in fact it's pretty hard to figure out
+// with any degree of precision when this series actually
+// *will* converge!! Consequently, we may just have to
+// try it and see...
+//
+template <class T, class Policy>
+bool hankel_PQ(T v, T x, T* p, T* q, const Policy& )
+{
+ BOOST_MATH_STD_USING
+ T tolerance = 2 * policies::get_epsilon<T, Policy>();
+ *p = 1;
+ *q = 0;
+ T k = 1;
+ T z8 = 8 * x;
+ T sq = 1;
+ T mu = 4 * v * v;
+ T term = 1;
+ bool ok = true;
+ do
+ {
+ term *= (mu - sq * sq) / (k * z8);
+ *q += term;
+ k += 1;
+ sq += 2;
+ T mult = (sq * sq - mu) / (k * z8);
+ ok = fabs(mult) < 0.5f;
+ term *= mult;
+ *p += term;
+ k += 1;
+ sq += 2;
+ }
+ while((fabs(term) > tolerance * *p) && ok);
+ return ok;
+}
+
+// Calculate Y(v, x) and Y(v+1, x) by Temme's method, see
+// Temme, Journal of Computational Physics, vol 21, 343 (1976)
+template <typename T, typename Policy>
+int temme_jy(T v, T x, T* Y, T* Y1, const Policy& pol)
+{
+ T g, h, p, q, f, coef, sum, sum1, tolerance;
+ T a, d, e, sigma;
+ unsigned long k;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ BOOST_ASSERT(fabs(v) <= 0.5f); // precondition for using this routine
+
+ T gp = boost::math::tgamma1pm1(v, pol);
+ T gm = boost::math::tgamma1pm1(-v, pol);
+ T spv = boost::math::sin_pi(v, pol);
+ T spv2 = boost::math::sin_pi(v/2, pol);
+ T xp = pow(x/2, v);
+
+ a = log(x / 2);
+ sigma = -a * v;
+ d = abs(sigma) < tools::epsilon<T>() ?
+ T(1) : sinh(sigma) / sigma;
+ e = abs(v) < tools::epsilon<T>() ? T(v*pi<T>()*pi<T>() / 2)
+ : T(2 * spv2 * spv2 / v);
+
+ T g1 = (v == 0) ? T(-euler<T>()) : T((gp - gm) / ((1 + gp) * (1 + gm) * 2 * v));
+ T g2 = (2 + gp + gm) / ((1 + gp) * (1 + gm) * 2);
+ T vspv = (fabs(v) < tools::epsilon<T>()) ? T(1/constants::pi<T>()) : T(v / spv);
+ f = (g1 * cosh(sigma) - g2 * a * d) * 2 * vspv;
+
+ p = vspv / (xp * (1 + gm));
+ q = vspv * xp / (1 + gp);
+
+ g = f + e * q;
+ h = p;
+ coef = 1;
+ sum = coef * g;
+ sum1 = coef * h;
+
+ T v2 = v * v;
+ T coef_mult = -x * x / 4;
+
+ // series summation
+ tolerance = policies::get_epsilon<T, Policy>();
+ for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
+ {
+ f = (k * f + p + q) / (k*k - v2);
+ p /= k - v;
+ q /= k + v;
+ g = f + e * q;
+ h = p - k * g;
+ coef *= coef_mult / k;
+ sum += coef * g;
+ sum1 += coef * h;
+ if (abs(coef * g) < abs(sum) * tolerance)
+ {
+ break;
+ }
+ }
+ policies::check_series_iterations<T>("boost::math::bessel_jy<%1%>(%1%,%1%) in temme_jy", k, pol);
+ *Y = -sum;
+ *Y1 = -2 * sum1 / x;
+
+ return 0;
+}
+
+// Evaluate continued fraction fv = J_(v+1) / J_v, see
+// Abramowitz and Stegun, Handbook of Mathematical Functions, 1972, 9.1.73
+template <typename T, typename Policy>
+int CF1_jy(T v, T x, T* fv, int* sign, const Policy& pol)
+{
+ T C, D, f, a, b, delta, tiny, tolerance;
+ unsigned long k;
+ int s = 1;
+
+ BOOST_MATH_STD_USING
+
+ // |x| <= |v|, CF1_jy converges rapidly
+ // |x| > |v|, CF1_jy needs O(|x|) iterations to converge
+
+ // modified Lentz's method, see
+ // Lentz, Applied Optics, vol 15, 668 (1976)
+ tolerance = 2 * policies::get_epsilon<T, Policy>();;
+ tiny = sqrt(tools::min_value<T>());
+ C = f = tiny; // b0 = 0, replace with tiny
+ D = 0;
+ for (k = 1; k < policies::get_max_series_iterations<Policy>() * 100; k++)
+ {
+ a = -1;
+ b = 2 * (v + k) / x;
+ C = b + a / C;
+ D = b + a * D;
+ if (C == 0) { C = tiny; }
+ if (D == 0) { D = tiny; }
+ D = 1 / D;
+ delta = C * D;
+ f *= delta;
+ if (D < 0) { s = -s; }
+ if (abs(delta - 1) < tolerance)
+ { break; }
+ }
+ policies::check_series_iterations<T>("boost::math::bessel_jy<%1%>(%1%,%1%) in CF1_jy", k / 100, pol);
+ *fv = -f;
+ *sign = s; // sign of denominator
+
+ return 0;
+}
+//
+// This algorithm was originally written by Xiaogang Zhang
+// using std::complex to perform the complex arithmetic.
+// However, that turns out to 10x or more slower than using
+// all real-valued arithmetic, so it's been rewritten using
+// real values only.
+//
+template <typename T, typename Policy>
+int CF2_jy(T v, T x, T* p, T* q, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ T Cr, Ci, Dr, Di, fr, fi, a, br, bi, delta_r, delta_i, temp;
+ T tiny;
+ unsigned long k;
+
+ // |x| >= |v|, CF2_jy converges rapidly
+ // |x| -> 0, CF2_jy fails to converge
+ BOOST_ASSERT(fabs(x) > 1);
+
+ // modified Lentz's method, complex numbers involved, see
+ // Lentz, Applied Optics, vol 15, 668 (1976)
+ T tolerance = 2 * policies::get_epsilon<T, Policy>();
+ tiny = sqrt(tools::min_value<T>());
+ Cr = fr = -0.5f / x;
+ Ci = fi = 1;
+ //Dr = Di = 0;
+ T v2 = v * v;
+ a = (0.25f - v2) / x; // Note complex this one time only!
+ br = 2 * x;
+ bi = 2;
+ temp = Cr * Cr + 1;
+ Ci = bi + a * Cr / temp;
+ Cr = br + a / temp;
+ Dr = br;
+ Di = bi;
+ //std::cout << "C = " << Cr << " " << Ci << std::endl;
+ //std::cout << "D = " << Dr << " " << Di << std::endl;
+ if (fabs(Cr) + fabs(Ci) < tiny) { Cr = tiny; }
+ if (fabs(Dr) + fabs(Di) < tiny) { Dr = tiny; }
+ temp = Dr * Dr + Di * Di;
+ Dr = Dr / temp;
+ Di = -Di / temp;
+ delta_r = Cr * Dr - Ci * Di;
+ delta_i = Ci * Dr + Cr * Di;
+ temp = fr;
+ fr = temp * delta_r - fi * delta_i;
+ fi = temp * delta_i + fi * delta_r;
+ //std::cout << fr << " " << fi << std::endl;
+ for (k = 2; k < policies::get_max_series_iterations<Policy>(); k++)
+ {
+ a = k - 0.5f;
+ a *= a;
+ a -= v2;
+ bi += 2;
+ temp = Cr * Cr + Ci * Ci;
+ Cr = br + a * Cr / temp;
+ Ci = bi - a * Ci / temp;
+ Dr = br + a * Dr;
+ Di = bi + a * Di;
+ //std::cout << "C = " << Cr << " " << Ci << std::endl;
+ //std::cout << "D = " << Dr << " " << Di << std::endl;
+ if (fabs(Cr) + fabs(Ci) < tiny) { Cr = tiny; }
+ if (fabs(Dr) + fabs(Di) < tiny) { Dr = tiny; }
+ temp = Dr * Dr + Di * Di;
+ Dr = Dr / temp;
+ Di = -Di / temp;
+ delta_r = Cr * Dr - Ci * Di;
+ delta_i = Ci * Dr + Cr * Di;
+ temp = fr;
+ fr = temp * delta_r - fi * delta_i;
+ fi = temp * delta_i + fi * delta_r;
+ if (fabs(delta_r - 1) + fabs(delta_i) < tolerance)
+ break;
+ //std::cout << fr << " " << fi << std::endl;
+ }
+ policies::check_series_iterations<T>("boost::math::bessel_jy<%1%>(%1%,%1%) in CF2_jy", k, pol);
+ *p = fr;
+ *q = fi;
+
+ return 0;
+}
+
+enum
+{
+ need_j = 1, need_y = 2
+};
+
+// Compute J(v, x) and Y(v, x) simultaneously by Steed's method, see
+// Barnett et al, Computer Physics Communications, vol 8, 377 (1974)
+template <typename T, typename Policy>
+int bessel_jy(T v, T x, T* J, T* Y, int kind, const Policy& pol)
+{
+ BOOST_ASSERT(x >= 0);
+
+ T u, Jv, Ju, Yv, Yv1, Yu, Yu1(0), fv, fu;
+ T W, p, q, gamma, current, prev, next;
+ bool reflect = false;
+ unsigned n, k;
+ int s;
+ int org_kind = kind;
+ T cp = 0;
+ T sp = 0;
+
+ static const char* function = "boost::math::bessel_jy<%1%>(%1%,%1%)";
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ if (v < 0)
+ {
+ reflect = true;
+ v = -v; // v is non-negative from here
+ kind = need_j|need_y; // need both for reflection formula
+ }
+ n = iround(v, pol);
+ u = v - n; // -1/2 <= u < 1/2
+
+ if(reflect)
+ {
+ T z = (u + n % 2);
+ cp = boost::math::cos_pi(z, pol);
+ sp = boost::math::sin_pi(z, pol);
+ }
+
+ if (x == 0)
+ {
+ *J = *Y = policies::raise_overflow_error<T>(
+ function, 0, pol);
+ return 1;
+ }
+
+ // x is positive until reflection
+ W = T(2) / (x * pi<T>()); // Wronskian
+ T Yv_scale = 1;
+ if((x > 8) && (x < 1000) && hankel_PQ(v, x, &p, &q, pol))
+ {
+ //
+ // Hankel approximation: note that this method works best when x
+ // is large, but in that case we end up calculating sines and cosines
+ // of large values, with horrendous resulting accuracy. It is fast though
+ // when it works....
+ //
+ T chi = x - fmod(T(v / 2 + 0.25f), T(2)) * boost::math::constants::pi<T>();
+ T sc = sin(chi);
+ T cc = cos(chi);
+ chi = sqrt(2 / (boost::math::constants::pi<T>() * x));
+ Yv = chi * (p * sc + q * cc);
+ Jv = chi * (p * cc - q * sc);
+ }
+ else if((x < 1) && (u != 0) && (log(policies::get_epsilon<T, Policy>() / 2) > v * log((x/2) * (x/2) / v)))
+ {
+ // Evaluate using series representations.
+ // This is particularly important for x << v as in this
+ // area temme_jy may be slow to converge, if it converges at all.
+ // Requires x is not an integer.
+ if(kind&need_j)
+ Jv = bessel_j_small_z_series(v, x, pol);
+ else
+ Jv = std::numeric_limits<T>::quiet_NaN();
+ if((org_kind&need_y && (!reflect || (cp != 0)))
+ || (org_kind & need_j && (reflect && (sp != 0))))
+ {
+ // Only calculate if we need it, and if the reflection formula will actually use it:
+ Yv = bessel_y_small_z_series(v, x, &Yv_scale, pol);
+ }
+ else
+ Yv = std::numeric_limits<T>::quiet_NaN();
+ }
+ else if((u == 0) && (x < policies::get_epsilon<T, Policy>()))
+ {
+ // Truncated series evaluation for small x and v an integer,
+ // much quicker in this area than temme_jy below.
+ if(kind&need_j)
+ Jv = bessel_j_small_z_series(v, x, pol);
+ else
+ Jv = std::numeric_limits<T>::quiet_NaN();
+ if((org_kind&need_y && (!reflect || (cp != 0)))
+ || (org_kind & need_j && (reflect && (sp != 0))))
+ {
+ // Only calculate if we need it, and if the reflection formula will actually use it:
+ Yv = bessel_yn_small_z(n, x, &Yv_scale, pol);
+ }
+ else
+ Yv = std::numeric_limits<T>::quiet_NaN();
+ }
+ else if (x <= 2) // x in (0, 2]
+ {
+ if(temme_jy(u, x, &Yu, &Yu1, pol)) // Temme series
+ {
+ // domain error:
+ *J = *Y = Yu;
+ return 1;
+ }
+ prev = Yu;
+ current = Yu1;
+ T scale = 1;
+ for (k = 1; k <= n; k++) // forward recurrence for Y
+ {
+ T fact = 2 * (u + k) / x;
+ if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
+ {
+ scale /= current;
+ prev /= current;
+ current = 1;
+ }
+ next = fact * current - prev;
+ prev = current;
+ current = next;
+ }
+ Yv = prev;
+ Yv1 = current;
+ if(kind&need_j)
+ {
+ CF1_jy(v, x, &fv, &s, pol); // continued fraction CF1_jy
+ Jv = scale * W / (Yv * fv - Yv1); // Wronskian relation
+ }
+ else
+ Jv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
+ Yv_scale = scale;
+ }
+ else // x in (2, \infty)
+ {
+ // Get Y(u, x):
+ // define tag type that will dispatch to right limits:
+ typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
+
+ T lim, ratio;
+ switch(kind)
+ {
+ case need_j:
+ lim = asymptotic_bessel_j_limit<T>(v, tag_type());
+ break;
+ case need_y:
+ lim = asymptotic_bessel_y_limit<T>(tag_type());
+ break;
+ default:
+ lim = (std::max)(
+ asymptotic_bessel_j_limit<T>(v, tag_type()),
+ asymptotic_bessel_y_limit<T>(tag_type()));
+ break;
+ }
+ if(x > lim)
+ {
+ if(kind&need_y)
+ {
+ Yu = asymptotic_bessel_y_large_x_2(u, x);
+ Yu1 = asymptotic_bessel_y_large_x_2(T(u + 1), x);
+ }
+ else
+ Yu = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
+ if(kind&need_j)
+ {
+ Jv = asymptotic_bessel_j_large_x_2(v, x);
+ }
+ else
+ Jv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
+ }
+ else
+ {
+ CF1_jy(v, x, &fv, &s, pol);
+ // tiny initial value to prevent overflow
+ T init = sqrt(tools::min_value<T>());
+ prev = fv * s * init;
+ current = s * init;
+ if(v < max_factorial<T>::value)
+ {
+ for (k = n; k > 0; k--) // backward recurrence for J
+ {
+ next = 2 * (u + k) * current / x - prev;
+ prev = current;
+ current = next;
+ }
+ ratio = (s * init) / current; // scaling ratio
+ // can also call CF1_jy() to get fu, not much difference in precision
+ fu = prev / current;
+ }
+ else
+ {
+ //
+ // When v is large we may get overflow in this calculation
+ // leading to NaN's and other nasty surprises:
+ //
+ bool over = false;
+ for (k = n; k > 0; k--) // backward recurrence for J
+ {
+ T t = 2 * (u + k) / x;
+ if(tools::max_value<T>() / t < current)
+ {
+ over = true;
+ break;
+ }
+ next = t * current - prev;
+ prev = current;
+ current = next;
+ }
+ if(!over)
+ {
+ ratio = (s * init) / current; // scaling ratio
+ // can also call CF1_jy() to get fu, not much difference in precision
+ fu = prev / current;
+ }
+ else
+ {
+ ratio = 0;
+ fu = 1;
+ }
+ }
+ CF2_jy(u, x, &p, &q, pol); // continued fraction CF2_jy
+ T t = u / x - fu; // t = J'/J
+ gamma = (p - t) / q;
+ Ju = sign(current) * sqrt(W / (q + gamma * (p - t)));
+
+ Jv = Ju * ratio; // normalization
+
+ Yu = gamma * Ju;
+ Yu1 = Yu * (u/x - p - q/gamma);
+ }
+ if(kind&need_y)
+ {
+ // compute Y:
+ prev = Yu;
+ current = Yu1;
+ for (k = 1; k <= n; k++) // forward recurrence for Y
+ {
+ T fact = 2 * (u + k) / x;
+ if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
+ {
+ prev /= current;
+ Yv_scale /= current;
+ current = 1;
+ }
+ next = fact * current - prev;
+ prev = current;
+ current = next;
+ }
+ Yv = prev;
+ }
+ else
+ Yv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
+ }
+
+ if (reflect)
+ {
+ if((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 * Jv + (cp == 0 ? T(0) : T((cp * Yv) / Yv_scale));
+ }
+ else
+ {
+ *J = Jv;
+ if(tools::max_value<T>() * fabs(Yv_scale) < fabs(Yv))
+ *Y = org_kind & need_y ? T(sign(Yv) * sign(Yv_scale) * policies::raise_overflow_error<T>(function, 0, pol)) : T(0);
+ else
+ *Y = Yv / Yv_scale;
+ }
+
+ return 0;
+}
+
+} // namespace detail
+
+}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_JY_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_jy_asym.hpp b/boost/math/special_functions/detail/bessel_jy_asym.hpp
new file mode 100644
index 0000000000..0021f8c86a
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_jy_asym.hpp
@@ -0,0 +1,315 @@
+// Copyright (c) 2007 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//
+// This is a partial header, do not include on it's own!!!
+//
+// Contains asymptotic expansions for Bessel J(v,x) and Y(v,x)
+// functions, as x -> INF.
+//
+#ifndef BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
+#define BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/factorials.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+template <class T>
+inline T asymptotic_bessel_j_large_x_P(T v, T x)
+{
+ // A&S 9.2.9
+ T s = 1;
+ T mu = 4 * v * v;
+ T ez2 = 8 * x;
+ ez2 *= ez2;
+ s -= (mu-1) * (mu-9) / (2 * ez2);
+ s += (mu-1) * (mu-9) * (mu-25) * (mu - 49) / (24 * ez2 * ez2);
+ return s;
+}
+
+template <class T>
+inline T asymptotic_bessel_j_large_x_Q(T v, T x)
+{
+ // A&S 9.2.10
+ T s = 0;
+ T mu = 4 * v * v;
+ T ez = 8*x;
+ s += (mu-1) / ez;
+ s -= (mu-1) * (mu-9) * (mu-25) / (6 * ez*ez*ez);
+ return s;
+}
+
+template <class T>
+inline T asymptotic_bessel_j_large_x(T v, T x)
+{
+ //
+ // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
+ //
+ // Also A&S 9.2.5
+ //
+ BOOST_MATH_STD_USING // ADL of std names
+ T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
+ return sqrt(2 / (constants::pi<T>() * x))
+ * (asymptotic_bessel_j_large_x_P(v, x) * cos(chi)
+ - asymptotic_bessel_j_large_x_Q(v, x) * sin(chi));
+}
+
+template <class T>
+inline T asymptotic_bessel_y_large_x(T v, T x)
+{
+ //
+ // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
+ //
+ // Also A&S 9.2.5
+ //
+ BOOST_MATH_STD_USING // ADL of std names
+ T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
+ return sqrt(2 / (constants::pi<T>() * x))
+ * (asymptotic_bessel_j_large_x_P(v, x) * sin(chi)
+ - asymptotic_bessel_j_large_x_Q(v, x) * cos(chi));
+}
+
+template <class T>
+inline T asymptotic_bessel_amplitude(T v, T x)
+{
+ // Calculate the amplitude of J(v, x) and Y(v, x) for large
+ // x: see A&S 9.2.28.
+ BOOST_MATH_STD_USING
+ T s = 1;
+ T mu = 4 * v * v;
+ T txq = 2 * x;
+ txq *= txq;
+
+ s += (mu - 1) / (2 * txq);
+ s += 3 * (mu - 1) * (mu - 9) / (txq * txq * 8);
+ s += 15 * (mu - 1) * (mu - 9) * (mu - 25) / (txq * txq * txq * 8 * 6);
+
+ return sqrt(s * 2 / (constants::pi<T>() * x));
+}
+
+template <class T>
+T asymptotic_bessel_phase_mx(T v, T x)
+{
+ //
+ // Calculate the phase of J(v, x) and Y(v, x) for large x.
+ // See A&S 9.2.29.
+ // Note that the result returned is the phase less x.
+ //
+ T mu = 4 * v * v;
+ T denom = 4 * x;
+ T denom_mult = denom * denom;
+
+ T s = -constants::pi<T>() * (v / 2 + 0.25f);
+ s += (mu - 1) / (2 * denom);
+ denom *= denom_mult;
+ s += (mu - 1) * (mu - 25) / (6 * denom);
+ denom *= denom_mult;
+ s += (mu - 1) * (mu * mu - 114 * mu + 1073) / (5 * denom);
+ denom *= denom_mult;
+ s += (mu - 1) * (5 * mu * mu * mu - 1535 * mu * mu + 54703 * mu - 375733) / (14 * denom);
+ return s;
+}
+
+template <class T>
+inline T asymptotic_bessel_y_large_x_2(T v, T x)
+{
+ // See A&S 9.2.19.
+ BOOST_MATH_STD_USING
+ // Get the phase and amplitude:
+ T ampl = asymptotic_bessel_amplitude(v, x);
+ T phase = asymptotic_bessel_phase_mx(v, x);
+ BOOST_MATH_INSTRUMENT_VARIABLE(ampl);
+ BOOST_MATH_INSTRUMENT_VARIABLE(phase);
+ //
+ // Calculate the sine of the phase, using:
+ // sin(x+p) = sin(x)cos(p) + cos(x)sin(p)
+ //
+ T sin_phase = sin(phase) * cos(x) + cos(phase) * sin(x);
+ 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:
+ // cos(x+p) = cos(x)cos(p) - sin(x)sin(p)
+ //
+ 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 sin_phase = cos(phase) * cos(x) - sin(phase) * sin(x);
+ BOOST_MATH_INSTRUMENT_VARIABLE(sin_phase);
+ return sin_phase * ampl;
+}
+
+//
+// Various limits for the J and Y asymptotics
+// (the asympotic expansions are safe to use if
+// x is less than the limit given).
+// We assume that if we don't use these expansions then the
+// error will likely be >100eps, so the limits given are chosen
+// to lead to < 100eps truncation error.
+//
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<0>&)
+{
+ // default case:
+ BOOST_MATH_STD_USING
+ return 2.25 / pow(100 * tools::epsilon<T>() / T(0.001f), T(0.2f));
+}
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<53>&)
+{
+ // double case:
+ return 304 /*780*/;
+}
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<64>&)
+{
+ // 80-bit extended-double case:
+ return 1552 /*3500*/;
+}
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<113>&)
+{
+ // 128-bit long double case:
+ return 1245243 /*3128000*/;
+}
+
+template <class T, class Policy>
+struct bessel_asymptotic_tag
+{
+ typedef typename policies::precision<T, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::or_<
+ mpl::equal_to<precision_type, mpl::int_<0> >,
+ mpl::greater<precision_type, mpl::int_<113> > >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::greater<precision_type, mpl::int_<64> >,
+ mpl::int_<113>,
+ typename mpl::if_<
+ mpl::greater<precision_type, mpl::int_<53> >,
+ mpl::int_<64>,
+ mpl::int_<53>
+ >::type
+ >::type
+ >::type type;
+};
+
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<0>&)
+{
+ // default case:
+ BOOST_MATH_STD_USING
+ T v2 = (std::max)(T(3), T(v * v));
+ return v2 / pow(100 * tools::epsilon<T>() / T(2e-5f), T(0.17f));
+}
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<53>&)
+{
+ // double case:
+ T v2 = (std::max)(T(3), T(v * v));
+ return v2 * 33 /*73*/;
+}
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<64>&)
+{
+ // 80-bit extended-double case:
+ T v2 = (std::max)(T(3), T(v * v));
+ return v2 * 121 /*266*/;
+}
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<113>&)
+{
+ // 128-bit long double case:
+ T v2 = (std::max)(T(3), T(v * v));
+ return v2 * 39154 /*85700*/;
+}
+
+template <class T, class Policy>
+void temme_asyptotic_y_small_x(T v, T x, T* Y, T* Y1, const Policy& pol)
+{
+ T c = 1;
+ T p = (v / boost::math::sin_pi(v, pol)) * pow(x / 2, -v) / boost::math::tgamma(1 - v, pol);
+ T q = (v / boost::math::sin_pi(v, pol)) * pow(x / 2, v) / boost::math::tgamma(1 + v, pol);
+ T f = (p - q) / v;
+ T g_prefix = boost::math::sin_pi(v / 2, pol);
+ g_prefix *= g_prefix * 2 / v;
+ T g = f + g_prefix * q;
+ T h = p;
+ T c_mult = -x * x / 4;
+
+ T y(c * g), y1(c * h);
+
+ for(int k = 1; k < policies::get_max_series_iterations<Policy>(); ++k)
+ {
+ f = (k * f + p + q) / (k*k - v*v);
+ p /= k - v;
+ q /= k + v;
+ c *= c_mult / k;
+ T c1 = pow(-x * x / 4, k) / factorial<T>(k, pol);
+ g = f + g_prefix * q;
+ h = -k * g + p;
+ y += c * g;
+ y1 += c * h;
+ if(c * g / tools::epsilon<T>() < y)
+ break;
+ }
+
+ *Y = -y;
+ *Y1 = (-2 / x) * y1;
+}
+
+template <class T, class Policy>
+T asymptotic_bessel_i_large_x(T v, T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ T s = 1;
+ T mu = 4 * v * v;
+ T ex = 8 * x;
+ T num = mu - 1;
+ T denom = ex;
+
+ s -= num / denom;
+
+ num *= mu - 9;
+ denom *= ex * 2;
+ s += num / denom;
+
+ num *= mu - 25;
+ denom *= ex * 3;
+ s -= num / denom;
+
+ // Try and avoid overflow to the last minute:
+ T e = exp(x/2);
+
+ s = e * (e * s / sqrt(2 * x * constants::pi<T>()));
+
+ return (boost::math::isfinite)(s) ?
+ s : policies::raise_overflow_error<T>("boost::math::asymptotic_bessel_i_large_x<%1%>(%1%,%1%)", 0, pol);
+}
+
+}}} // namespaces
+
+#endif
+
diff --git a/boost/math/special_functions/detail/bessel_jy_series.hpp b/boost/math/special_functions/detail/bessel_jy_series.hpp
new file mode 100644
index 0000000000..b926366eb0
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_jy_series.hpp
@@ -0,0 +1,261 @@
+// Copyright (c) 2011 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_JN_SERIES_HPP
+#define BOOST_MATH_BESSEL_JN_SERIES_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+namespace boost { namespace math { namespace detail{
+
+template <class T, class Policy>
+struct bessel_j_small_z_series_term
+{
+ typedef T result_type;
+
+ bessel_j_small_z_series_term(T v_, T x)
+ : N(0), v(v_)
+ {
+ BOOST_MATH_STD_USING
+ mult = x / 2;
+ mult *= -mult;
+ term = 1;
+ }
+ T operator()()
+ {
+ T r = term;
+ ++N;
+ term *= mult / (N * (N + v));
+ return r;
+ }
+private:
+ unsigned N;
+ T v;
+ T mult;
+ T term;
+};
+//
+// Series evaluation for BesselJ(v, z) as z -> 0.
+// See http://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/06/01/04/01/01/0003/
+// Converges rapidly for all z << v.
+//
+template <class T, class Policy>
+inline T bessel_j_small_z_series(T v, T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T prefix;
+ if(v < max_factorial<T>::value)
+ {
+ prefix = pow(x / 2, v) / boost::math::tgamma(v+1, pol);
+ }
+ else
+ {
+ prefix = v * log(x / 2) - boost::math::lgamma(v+1, pol);
+ prefix = exp(prefix);
+ }
+ if(0 == prefix)
+ return prefix;
+
+ bessel_j_small_z_series_term<T, Policy> s(v, x);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ T zero = 0;
+ T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
+#else
+ T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
+#endif
+ policies::check_series_iterations<T>("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
+ return prefix * result;
+}
+
+template <class T, class Policy>
+struct bessel_y_small_z_series_term_a
+{
+ typedef T result_type;
+
+ bessel_y_small_z_series_term_a(T v_, T x)
+ : N(0), v(v_)
+ {
+ BOOST_MATH_STD_USING
+ mult = x / 2;
+ mult *= -mult;
+ term = 1;
+ }
+ T operator()()
+ {
+ BOOST_MATH_STD_USING
+ T r = term;
+ ++N;
+ term *= mult / (N * (N - v));
+ return r;
+ }
+private:
+ unsigned N;
+ T v;
+ T mult;
+ T term;
+};
+
+template <class T, class Policy>
+struct bessel_y_small_z_series_term_b
+{
+ typedef T result_type;
+
+ bessel_y_small_z_series_term_b(T v_, T x)
+ : N(0), v(v_)
+ {
+ BOOST_MATH_STD_USING
+ mult = x / 2;
+ mult *= -mult;
+ term = 1;
+ }
+ T operator()()
+ {
+ T r = term;
+ ++N;
+ term *= mult / (N * (N + v));
+ return r;
+ }
+private:
+ unsigned N;
+ T v;
+ T mult;
+ T term;
+};
+//
+// Series form for BesselY as z -> 0,
+// see: http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/01/0003/
+// This series is only useful when the second term is small compared to the first
+// otherwise we get catestrophic cancellation errors.
+//
+// Approximating tgamma(v) by v^v, and assuming |tgamma(-z)| < eps we end up requiring:
+// eps/2 * v^v(x/2)^-v > (x/2)^v or log(eps/2) > v log((x/2)^2/v)
+//
+template <class T, class Policy>
+inline T bessel_y_small_z_series(T v, T x, T* pscale, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ static const char* function = "bessel_y_small_z_series<%1%>(%1%,%1%)";
+ T prefix;
+ T gam;
+ T p = log(x / 2);
+ T scale = 1;
+ bool need_logs = (v >= max_factorial<T>::value) || (tools::log_max_value<T>() / v < fabs(p));
+ if(!need_logs)
+ {
+ gam = boost::math::tgamma(v, pol);
+ p = pow(x / 2, v);
+ if(tools::max_value<T>() * p < gam)
+ {
+ scale /= gam;
+ gam = 1;
+ if(tools::max_value<T>() * p < gam)
+ {
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ }
+ prefix = -gam / (constants::pi<T>() * p);
+ }
+ else
+ {
+ gam = boost::math::lgamma(v, pol);
+ p = v * p;
+ prefix = gam - log(constants::pi<T>()) - p;
+ if(tools::log_max_value<T>() < prefix)
+ {
+ prefix -= log(tools::max_value<T>() / 4);
+ scale /= (tools::max_value<T>() / 4);
+ if(tools::log_max_value<T>() < prefix)
+ {
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ }
+ prefix = -exp(prefix);
+ }
+ bessel_y_small_z_series_term_a<T, Policy> s(v, x);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+ *pscale = scale;
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ T zero = 0;
+ T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
+#else
+ T result = boost::math::tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
+#endif
+ policies::check_series_iterations<T>("boost::math::bessel_y_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
+ result *= prefix;
+
+ if(!need_logs)
+ {
+ prefix = boost::math::tgamma(-v, pol) * boost::math::cos_pi(v) * p / constants::pi<T>();
+ }
+ else
+ {
+ int s;
+ prefix = boost::math::lgamma(-v, &s, pol) + p;
+ prefix = exp(prefix) * s / constants::pi<T>();
+ }
+ bessel_y_small_z_series_term_b<T, Policy> s2(v, x);
+ max_iter = policies::get_max_series_iterations<Policy>();
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ T b = boost::math::tools::sum_series(s2, boost::math::policies::get_epsilon<T, Policy>(), max_iter, zero);
+#else
+ T b = boost::math::tools::sum_series(s2, boost::math::policies::get_epsilon<T, Policy>(), max_iter);
+#endif
+ result -= scale * prefix * b;
+ return result;
+}
+
+template <class T, class Policy>
+T bessel_yn_small_z(int n, T z, T* scale, const Policy& pol)
+{
+ //
+ // See http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/06/01/04/01/02/
+ //
+ // Note that when called we assume that x < epsilon and n is a positive integer.
+ //
+ BOOST_MATH_STD_USING
+ BOOST_ASSERT(n >= 0);
+ BOOST_ASSERT((z < policies::get_epsilon<T, Policy>()));
+
+ if(n == 0)
+ {
+ return (2 / constants::pi<T>()) * (log(z / 2) + constants::euler<T>());
+ }
+ else if(n == 1)
+ {
+ return (z / constants::pi<T>()) * log(z / 2)
+ - 2 / (constants::pi<T>() * z)
+ - (z / (2 * constants::pi<T>())) * (1 - 2 * constants::euler<T>());
+ }
+ else if(n == 2)
+ {
+ return (z * z) / (4 * constants::pi<T>()) * log(z / 2)
+ - (4 / (constants::pi<T>() * z * z))
+ - ((z * z) / (8 * constants::pi<T>())) * (3/2 - 2 * constants::euler<T>());
+ }
+ else
+ {
+ T p = pow(z / 2, n);
+ T result = -((boost::math::factorial<T>(n - 1) / constants::pi<T>()));
+ if(p * tools::max_value<T>() < result)
+ {
+ T div = tools::max_value<T>() / 8;
+ result /= div;
+ *scale /= div;
+ if(p * tools::max_value<T>() < result)
+ {
+ return -policies::raise_overflow_error<T>("bessel_yn_small_z<%1%>(%1%,%1%)", 0, pol);
+ }
+ }
+ return result / p;
+ }
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_JN_SERIES_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_k0.hpp b/boost/math/special_functions/detail/bessel_k0.hpp
new file mode 100644
index 0000000000..81407dab10
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_k0.hpp
@@ -0,0 +1,122 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_K0_HPP
+#define BOOST_MATH_BESSEL_K0_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/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
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_k0(T x, const Policy& pol)
+{
+ BOOST_MATH_INSTRUMENT_CODE(x);
+
+ static const T P1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.4708152720399552679e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.9169059852270512312e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.6850901201934832188e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1999463724910714109e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3166052564989571850e-01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.8599221412826100000e-04))
+ };
+ static const T Q1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1312714303849120380e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.4994418972832303646e+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.6128136304458193998e+06)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.7333769444840079748e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.7984434409411765813e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.9501657892958843865e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.6414452837299064100e+00))
+ };
+ static const T Q2[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.6128136304458193998e+06)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.9865713163054025489e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.5064972445877992730e+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, 1.1600249425076035558e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.3444738764199315021e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8321525870183537725e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.1557062783764037541e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.5097646353289914539e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7398867902565686251e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0577068948034021957e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.1075408980684392399e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.6832589957340267940e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.1394980557384778174e+02))
+ };
+ static const T Q3[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.2556599177304839811e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.8821890840982713696e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.4847228371802360957e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5.8824616785857027752e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.2689839587977598727e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.5144644673520157801e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.7418829762268075784e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.1474655750295278825e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.4329628889746408858e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.0013443064949242491e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
+ };
+ T value, factor, r, r1, r2;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::bessel_k0<%1%>(%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got x = %1%, but argument x must be non-negative, complex number result not supported", x, pol);
+ }
+ if (x == 0)
+ {
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ if (x <= 1) // x in (0, 1]
+ {
+ T y = x * x;
+ r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = log(x);
+ value = r1 - factor * r2;
+ }
+ else // x in (1, \infty)
+ {
+ T y = 1 / x;
+ r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
+ factor = exp(-x) / sqrt(x);
+ value = factor * r;
+ BOOST_MATH_INSTRUMENT_CODE("y = " << y);
+ BOOST_MATH_INSTRUMENT_CODE("r = " << r);
+ BOOST_MATH_INSTRUMENT_CODE("factor = " << factor);
+ BOOST_MATH_INSTRUMENT_CODE("value = " << value);
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_K0_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_k1.hpp b/boost/math/special_functions/detail/bessel_k1.hpp
new file mode 100644
index 0000000000..225209f7ba
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_k1.hpp
@@ -0,0 +1,118 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_K1_HPP
+#define BOOST_MATH_BESSEL_K1_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/tools/big_constant.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/assert.hpp>
+
+// Modified Bessel function of the second kind of order one
+// minimax rational approximations on intervals, see
+// Russon and Blair, Chalk River Report AECL-3461, 1969
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_k1(T x, const Policy& pol)
+{
+ static const T P1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2149374878243304548e+06)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.1938920065420586101e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7733324035147015630e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.1885382604084798576e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.9991373567429309922e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.8127070456878442310e-01))
+ };
+ static const T Q1[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2149374878243304548e+06)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.7264298672067697862e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.8143915754538725829e+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, 0.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.3531161492785421328e+06)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -1.4758069205414222471e+05)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -4.5051623763436087023e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -5.3103913335180275253e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.2795590826955002390e-01))
+ };
+ static const T Q2[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.7062322985570842656e+06)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.3117653211351080007e+04)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -3.0507151578787595807e+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, 2.2196792496874548962e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.4137176114230414036e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.4122953486801312910e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3319486433183221990e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.8590657697910288226e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.4540675585544584407e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.3123742209168871550e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 8.1094256146537402173e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.3182609918569941308e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 7.5584584631176030810e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6.4257745859173138767e-02))
+ };
+ static const T Q3[] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.7710478032601086579e+00)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.4552228452758912848e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.5951223655579051357e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.6929165726802648634e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.9448440788918006154e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.1181000487171943810e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.2082692316002348638e+03)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.3031020088765390854e+02)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3.6001069306861518855e+01)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.0))
+ };
+ T value, factor, r, r1, r2;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::bessel_k1<%1%>(%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol);
+ }
+ if (x == 0)
+ {
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ if (x <= 1) // x in (0, 1]
+ {
+ T y = x * x;
+ r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = log(x);
+ value = (r1 + factor * r2) / x;
+ }
+ else // x in (1, \infty)
+ {
+ T y = 1 / x;
+ r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
+ factor = exp(-x) / sqrt(x);
+ value = factor * r;
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_K1_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_kn.hpp b/boost/math/special_functions/detail/bessel_kn.hpp
new file mode 100644
index 0000000000..5f01460995
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_kn.hpp
@@ -0,0 +1,85 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_KN_HPP
+#define BOOST_MATH_BESSEL_KN_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/detail/bessel_k0.hpp>
+#include <boost/math/special_functions/detail/bessel_k1.hpp>
+#include <boost/math/policies/error_handling.hpp>
+
+// Modified Bessel function of the second kind of integer order
+// K_n(z) is the dominant solution, forward recurrence always OK (though unstable)
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_kn(int n, T x, const Policy& pol)
+{
+ T value, current, prev;
+
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::bessel_kn<%1%>(%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol);
+ }
+ if (x == 0)
+ {
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+
+ if (n < 0)
+ {
+ n = -n; // K_{-n}(z) = K_n(z)
+ }
+ if (n == 0)
+ {
+ value = bessel_k0(x, pol);
+ }
+ else if (n == 1)
+ {
+ value = bessel_k1(x, pol);
+ }
+ else
+ {
+ prev = bessel_k0(x, pol);
+ current = bessel_k1(x, pol);
+ int k = 1;
+ BOOST_ASSERT(k < n);
+ T scale = 1;
+ do
+ {
+ T fact = 2 * k / x;
+ if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
+ {
+ scale /= current;
+ prev /= current;
+ current = 1;
+ }
+ value = fact * current + prev;
+ prev = current;
+ current = value;
+ ++k;
+ }
+ while(k < n);
+ if(tools::max_value<T>() * scale < fabs(value))
+ return sign(scale) * sign(value) * policies::raise_overflow_error<T>(function, 0, pol);
+ value /= scale;
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_KN_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_y0.hpp b/boost/math/special_functions/detail/bessel_y0.hpp
new file mode 100644
index 0000000000..e23f861bf0
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_y0.hpp
@@ -0,0 +1,183 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_Y0_HPP
+#define BOOST_MATH_BESSEL_Y0_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/detail/bessel_j0.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/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& pol)
+{
+ 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;
+ T z = x - 0.25f * pi<T>();
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (x * pi<T>()));
+ value = factor * (rc * sin(z) + y * rs * cos(z));
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_Y0_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_y1.hpp b/boost/math/special_functions/detail/bessel_y1.hpp
new file mode 100644
index 0000000000..b85e7011ea
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_y1.hpp
@@ -0,0 +1,156 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_Y1_HPP
+#define BOOST_MATH_BESSEL_Y1_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/detail/bessel_j1.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/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& pol)
+{
+ 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;
+ T z = x - 0.75f * pi<T>();
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (x * pi<T>()));
+ value = factor * (rc * sin(z) + y * rs * cos(z));
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_Y1_HPP
+
diff --git a/boost/math/special_functions/detail/bessel_yn.hpp b/boost/math/special_functions/detail/bessel_yn.hpp
new file mode 100644
index 0000000000..b4f9855a2f
--- /dev/null
+++ b/boost/math/special_functions/detail/bessel_yn.hpp
@@ -0,0 +1,103 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_YN_HPP
+#define BOOST_MATH_BESSEL_YN_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/detail/bessel_y0.hpp>
+#include <boost/math/special_functions/detail/bessel_y1.hpp>
+#include <boost/math/special_functions/detail/bessel_jy_series.hpp>
+#include <boost/math/policies/error_handling.hpp>
+
+// Bessel function of the second kind of integer order
+// Y_n(z) is the dominant solution, forward recurrence always OK (though unstable)
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_yn(int n, T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T value, factor, current, prev;
+
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::bessel_yn<%1%>(%1%,%1%)";
+
+ if ((x == 0) && (n == 0))
+ {
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ if (x <= 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got x = %1%, but x must be > 0, complex result not supported.", x, pol);
+ }
+
+ //
+ // Reflection comes first:
+ //
+ if (n < 0)
+ {
+ factor = (n & 0x1) ? -1 : 1; // Y_{-n}(z) = (-1)^n Y_n(z)
+ n = -n;
+ }
+ else
+ {
+ factor = 1;
+ }
+
+ if(x < policies::get_epsilon<T, Policy>())
+ {
+ T scale = 1;
+ value = bessel_yn_small_z(n, x, &scale, pol);
+ if(tools::max_value<T>() * fabs(scale) < fabs(value))
+ return boost::math::sign(scale) * boost::math::sign(value) * policies::raise_overflow_error<T>(function, 0, pol);
+ value /= scale;
+ }
+ else if (n == 0)
+ {
+ value = bessel_y0(x, pol);
+ }
+ else if (n == 1)
+ {
+ value = factor * bessel_y1(x, pol);
+ }
+ else
+ {
+ prev = bessel_y0(x, pol);
+ current = bessel_y1(x, pol);
+ int k = 1;
+ BOOST_ASSERT(k < n);
+ do
+ {
+ T fact = 2 * k / x;
+ if((tools::max_value<T>() - fabs(prev)) / fact < fabs(current))
+ {
+ prev /= current;
+ factor /= current;
+ current = 1;
+ }
+ value = fact * current - prev;
+ prev = current;
+ current = value;
+ ++k;
+ }
+ while(k < n);
+ if(fabs(tools::max_value<T>() * factor) < fabs(value))
+ return sign(value) * sign(value) * policies::raise_overflow_error<T>(function, 0, pol);
+ value /= factor;
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_YN_HPP
+
diff --git a/boost/math/special_functions/detail/erf_inv.hpp b/boost/math/special_functions/detail/erf_inv.hpp
new file mode 100644
index 0000000000..f2f625f991
--- /dev/null
+++ b/boost/math/special_functions/detail/erf_inv.hpp
@@ -0,0 +1,471 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SF_ERF_INV_HPP
+#define BOOST_MATH_SF_ERF_INV_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+namespace boost{ namespace math{
+
+namespace detail{
+//
+// The inverse erf and erfc functions share a common implementation,
+// this version is for 80-bit long double's and smaller:
+//
+template <class T, class Policy>
+T erf_inv_imp(const T& p, const T& q, const Policy&, const boost::mpl::int_<64>*)
+{
+ BOOST_MATH_STD_USING // for ADL of std names.
+
+ T result = 0;
+
+ if(p <= 0.5)
+ {
+ //
+ // Evaluate inverse erf using the rational approximation:
+ //
+ // x = p(p+10)(Y+R(p))
+ //
+ // Where Y is a constant, and R(p) is optimised for a low
+ // absolute error compared to |Y|.
+ //
+ // double: Max error found: 2.001849e-18
+ // long double: Max error found: 1.017064e-20
+ // Maximum Deviation Found (actual error term at infinite precision) 8.030e-21
+ //
+ static const float Y = 0.0891314744949340820313f;
+ static const T P[] = {
+ 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[] = {
+ 1,
+ 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),
+ 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.25;
+ T r = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = g / (Y + r);
+ }
+ else
+ {
+ //
+ // For q < 0.25 we have a series of rational approximations all
+ // of the general form:
+ //
+ // let: x = sqrt(-log(q))
+ //
+ // Then the result is given by:
+ //
+ // x(Y+R(x-B))
+ //
+ // where Y is a constant, B is the lowest value of x for which
+ // the approximation is valid, and R(x-B) is optimised for a low
+ // absolute error compared to Y.
+ //
+ // Note that almost all code will really go through the first
+ // or maybe second approximation. After than we're dealing with very
+ // small input values indeed: 80 and 128 bit long double's go all the
+ // way down to ~ 1e-5000 so the "tail" is rather long...
+ //
+ T x = sqrt(-log(q));
+ if(x < 3)
+ {
+ // Max error found: 1.089051e-20
+ static const float Y = 0.807220458984375f;
+ static const T P[] = {
+ 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[] = {
+ 1,
+ 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.125;
+ T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = Y * x + R * x;
+ }
+ else if(x < 6)
+ {
+ // Max error found: 8.389174e-21
+ static const float Y = 0.93995571136474609375f;
+ static const T P[] = {
+ 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),
+ 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),
+ 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),
+ 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),
+ 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) ? boost::math::erf(guess, Policy()) : boost::math::erfc(guess, Policy())) - target, derivative, derivative2);
+ }
+ erf_roots(T z, int s) : target(z), sign(s) {}
+private:
+ T target;
+ int sign;
+};
+
+template <class T, class Policy>
+T erf_inv_imp(const T& p, const T& q, const Policy& pol, const boost::mpl::int_<0>*)
+{
+ //
+ // Generic version, get a guess that's accurate to 64-bits (10^-19)
+ //
+ T guess = erf_inv_imp(p, q, pol, static_cast<mpl::int_<64> const*>(0));
+ T result;
+ //
+ // If T has more bit's than 64 in it's mantissa then we need to iterate,
+ // otherwise we can just return the result:
+ //
+ if(policies::digits<T, Policy>() > 64)
+ {
+ boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ if(p <= 0.5)
+ {
+ result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(p, 1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3, max_iter);
+ }
+ else
+ {
+ result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(q, -1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3, max_iter);
+ }
+ policies::check_root_iterations<T>("boost::math::erf_inv<%1%>", max_iter, pol);
+ }
+ else
+ {
+ result = guess;
+ }
+ return result;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+typename tools::promote_args<T>::type erfc_inv(T z, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ //
+ // Begin by testing for domain errors, and other special cases:
+ //
+ static const char* function = "boost::math::erfc_inv<%1%>(%1%, %1%)";
+ if((z < 0) || (z > 2))
+ policies::raise_domain_error<result_type>(function, "Argument outside range [0,2] in inverse erfc function (got p=%1%).", z, pol);
+ if(z == 0)
+ return policies::raise_overflow_error<result_type>(function, 0, pol);
+ if(z == 2)
+ return -policies::raise_overflow_error<result_type>(function, 0, pol);
+ //
+ // Normalise the input, so it's in the range [0,1], we will
+ // negate the result if z is outside that range. This is a simple
+ // application of the erfc reflection formula: erfc(-z) = 2 - erfc(z)
+ //
+ result_type p, q, s;
+ if(z > 1)
+ {
+ q = 2 - z;
+ p = 1 - q;
+ s = -1;
+ }
+ else
+ {
+ p = 1 - z;
+ q = z;
+ s = 1;
+ }
+ //
+ // A bit of meta-programming to figure out which implementation
+ // to use, based on the number of bits in the mantissa of T:
+ //
+ typedef typename policies::precision<result_type, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >,
+ mpl::int_<0>,
+ mpl::int_<64>
+ >::type tag_type;
+ //
+ // Likewise use internal promotion, so we evaluate at a higher
+ // precision internally if it's appropriate:
+ //
+ typedef typename policies::evaluation<result_type, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ //
+ // And get the result, negating where required:
+ //
+ return s * policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function);
+}
+
+template <class T, class Policy>
+typename tools::promote_args<T>::type erf_inv(T z, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ //
+ // Begin by testing for domain errors, and other special cases:
+ //
+ static const char* function = "boost::math::erf_inv<%1%>(%1%, %1%)";
+ if((z < -1) || (z > 1))
+ policies::raise_domain_error<result_type>(function, "Argument outside range [-1, 1] in inverse erf function (got p=%1%).", z, pol);
+ if(z == 1)
+ return policies::raise_overflow_error<result_type>(function, 0, pol);
+ if(z == -1)
+ return -policies::raise_overflow_error<result_type>(function, 0, pol);
+ if(z == 0)
+ return 0;
+ //
+ // Normalise the input, so it's in the range [0,1], we will
+ // negate the result if z is outside that range. This is a simple
+ // application of the erf reflection formula: erf(-z) = -erf(z)
+ //
+ result_type p, q, s;
+ if(z < 0)
+ {
+ p = -z;
+ q = 1 - p;
+ s = -1;
+ }
+ else
+ {
+ p = z;
+ q = 1 - z;
+ s = 1;
+ }
+ //
+ // A bit of meta-programming to figure out which implementation
+ // to use, based on the number of bits in the mantissa of T:
+ //
+ typedef typename policies::precision<result_type, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >,
+ mpl::int_<0>,
+ mpl::int_<64>
+ >::type tag_type;
+ //
+ // Likewise use internal promotion, so we evaluate at a higher
+ // precision internally if it's appropriate:
+ //
+ typedef typename policies::evaluation<result_type, Policy>::type eval_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ //
+ // Likewise use internal promotion, so we evaluate at a higher
+ // precision internally if it's appropriate:
+ //
+ typedef typename policies::evaluation<result_type, Policy>::type eval_type;
+ //
+ // And get the result, negating where required:
+ //
+ return s * policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function);
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type erfc_inv(T z)
+{
+ return erfc_inv(z, policies::policy<>());
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type erf_inv(T z)
+{
+ return erf_inv(z, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SF_ERF_INV_HPP
+
diff --git a/boost/math/special_functions/detail/fp_traits.hpp b/boost/math/special_functions/detail/fp_traits.hpp
new file mode 100644
index 0000000000..50c034d303
--- /dev/null
+++ b/boost/math/special_functions/detail/fp_traits.hpp
@@ -0,0 +1,570 @@
+// fp_traits.hpp
+
+#ifndef BOOST_MATH_FP_TRAITS_HPP
+#define BOOST_MATH_FP_TRAITS_HPP
+
+// Copyright (c) 2006 Johan Rade
+
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+/*
+To support old compilers, care has been taken to avoid partial template
+specialization and meta function forwarding.
+With these techniques, the code could be simplified.
+*/
+
+#if defined(__vms) && defined(__DECCXX) && !__IEEE_FLOAT
+// The VAX floating point formats are used (for float and double)
+# define BOOST_FPCLASSIFY_VAX_FORMAT
+#endif
+
+#include <cstring>
+
+#include <boost/assert.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/detail/endian.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits/is_floating_point.hpp>
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+ namespace std{ using ::memcpy; }
+#endif
+
+#ifndef FP_NORMAL
+
+#define FP_ZERO 0
+#define FP_NORMAL 1
+#define FP_INFINITE 2
+#define FP_NAN 3
+#define FP_SUBNORMAL 4
+
+#else
+
+#define BOOST_HAS_FPCLASSIFY
+
+#ifndef fpclassify
+# if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) \
+ && defined(_GLIBCXX_USE_C99_MATH) \
+ && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) \
+ && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))
+# ifdef _STLP_VENDOR_CSTD
+# if _STLPORT_VERSION >= 0x520
+# define BOOST_FPCLASSIFY_PREFIX ::__std_alias::
+# else
+# define BOOST_FPCLASSIFY_PREFIX ::_STLP_VENDOR_CSTD::
+# endif
+# else
+# define BOOST_FPCLASSIFY_PREFIX ::std::
+# endif
+# else
+# undef BOOST_HAS_FPCLASSIFY
+# define BOOST_FPCLASSIFY_PREFIX
+# endif
+#elif (defined(__HP_aCC) && !defined(__hppa))
+// aCC 6 appears to do "#define fpclassify fpclassify" which messes us up a bit!
+# define BOOST_FPCLASSIFY_PREFIX ::
+#else
+# define BOOST_FPCLASSIFY_PREFIX
+#endif
+
+#ifdef __MINGW32__
+# undef BOOST_HAS_FPCLASSIFY
+#endif
+
+#endif
+
+
+//------------------------------------------------------------------------------
+
+namespace boost {
+namespace math {
+namespace detail {
+
+//------------------------------------------------------------------------------
+
+/*
+The following classes are used to tag the different methods that are used
+for floating point classification
+*/
+
+struct native_tag {};
+template <bool has_limits>
+struct generic_tag {};
+struct ieee_tag {};
+struct ieee_copy_all_bits_tag : public ieee_tag {};
+struct ieee_copy_leading_bits_tag : public ieee_tag {};
+
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+//
+// These helper functions are used only when numeric_limits<>
+// members are not compile time constants:
+//
+inline bool is_generic_tag_false(const generic_tag<false>*)
+{
+ return true;
+}
+inline bool is_generic_tag_false(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 defined(BOOST_BIG_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 0);
+#elif defined(BOOST_LITTLE_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 4);
+#else
+ BOOST_STATIC_ASSERT(false);
+#endif
+};
+
+//..............................................................................
+
+#else
+
+template<> struct fp_traits_non_native<double, double_precision>
+{
+ typedef ieee_copy_all_bits_tag method;
+
+ static const uint64_t sign = ((uint64_t)0x80000000u) << 32;
+ static const uint64_t exponent = ((uint64_t)0x7ff00000) << 32;
+ static const uint64_t flag = 0;
+ static const uint64_t significand
+ = (((uint64_t)0x000fffff) << 32) + ((uint64_t)0xffffffffu);
+
+ typedef uint64_t bits;
+ static void get_bits(double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
+ static void set_bits(double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
+};
+
+#endif
+
+#endif // #ifndef BOOST_FPCLASSIFY_VAX_FORMAT
+
+// long double (64 bits) -------------------------------------------------------
+
+#if defined(BOOST_NO_INT64_T) || defined(BOOST_NO_INCLASS_MEMBER_INITIALIZATION)\
+ || defined(__BORLANDC__) || defined(__CODEGEAR__)
+
+template<> struct fp_traits_non_native<long double, double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
+ }
+
+private:
+
+#if defined(BOOST_BIG_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 0);
+#elif defined(BOOST_LITTLE_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 4);
+#else
+ BOOST_STATIC_ASSERT(false);
+#endif
+};
+
+//..............................................................................
+
+#else
+
+template<> struct fp_traits_non_native<long double, double_precision>
+{
+ typedef ieee_copy_all_bits_tag method;
+
+ static const uint64_t sign = (uint64_t)0x80000000u << 32;
+ static const uint64_t exponent = (uint64_t)0x7ff00000 << 32;
+ static const uint64_t flag = 0;
+ static const uint64_t significand
+ = ((uint64_t)0x000fffff << 32) + (uint64_t)0xffffffffu;
+
+ typedef uint64_t bits;
+ static void get_bits(long double x, uint64_t& a) { std::memcpy(&a, &x, 8); }
+ static void set_bits(long double& x, uint64_t a) { std::memcpy(&x, &a, 8); }
+};
+
+#endif
+
+
+// long double (>64 bits), x86 and x64 -----------------------------------------
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
+ || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) \
+ || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
+
+// Intel extended double precision format (80 bits)
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + 6, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::memcpy(reinterpret_cast<unsigned char*>(&x) + 6, &a, 4);
+ }
+};
+
+
+// long double (>64 bits), Itanium ---------------------------------------------
+
+#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+
+// The floating point format is unknown at compile time
+// No template specialization is provided.
+// The generic_tag definition is used.
+
+// The Itanium supports both
+// the Intel extended double precision format (80 bits) and
+// the IEEE extended double precision format with 15 exponent bits (128 bits).
+
+
+// long double (>64 bits), PowerPC ---------------------------------------------
+
+#elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) \
+ || defined(__ppc) || defined(__ppc__) || defined(__PPC__)
+
+// PowerPC extended double precision format (128 bits)
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7ff00000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x000fffff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
+ }
+
+private:
+
+#if defined(BOOST_BIG_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 0);
+#elif defined(BOOST_LITTLE_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 12);
+#else
+ BOOST_STATIC_ASSERT(false);
+#endif
+};
+
+
+// long double (>64 bits), Motorola 68K ----------------------------------------
+
+#elif defined(__m68k) || defined(__m68k__) \
+ || defined(__mc68000) || defined(__mc68000__) \
+
+// Motorola extended double precision format (96 bits)
+
+// It is the same format as the Intel extended double precision format,
+// except that 1) it is big-endian, 2) the 3rd and 4th byte are padding, and
+// 3) the flag bit is not set for infinity
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00008000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x00007fff);
+
+ // copy 1st, 2nd, 5th and 6th byte. 3rd and 4th byte are padding.
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, &x, 2);
+ std::memcpy(reinterpret_cast<unsigned char*>(&a) + 2,
+ reinterpret_cast<const unsigned char*>(&x) + 4, 2);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::memcpy(&x, &a, 2);
+ std::memcpy(reinterpret_cast<unsigned char*>(&x) + 4,
+ reinterpret_cast<const unsigned char*>(&a) + 2, 2);
+ }
+};
+
+
+// long double (>64 bits), All other processors --------------------------------
+
+#else
+
+// IEEE extended double precision format with 15 exponent bits (128 bits)
+
+template<>
+struct fp_traits_non_native<long double, extended_double_precision>
+{
+ typedef ieee_copy_leading_bits_tag method;
+
+ BOOST_STATIC_CONSTANT(uint32_t, sign = 0x80000000u);
+ BOOST_STATIC_CONSTANT(uint32_t, exponent = 0x7fff0000);
+ BOOST_STATIC_CONSTANT(uint32_t, flag = 0x00000000);
+ BOOST_STATIC_CONSTANT(uint32_t, significand = 0x0000ffff);
+
+ typedef uint32_t bits;
+
+ static void get_bits(long double x, uint32_t& a)
+ {
+ std::memcpy(&a, reinterpret_cast<const unsigned char*>(&x) + offset_, 4);
+ }
+
+ static void set_bits(long double& x, uint32_t a)
+ {
+ std::memcpy(reinterpret_cast<unsigned char*>(&x) + offset_, &a, 4);
+ }
+
+private:
+
+#if defined(BOOST_BIG_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 0);
+#elif defined(BOOST_LITTLE_ENDIAN)
+ BOOST_STATIC_CONSTANT(int, offset_ = 12);
+#else
+ BOOST_STATIC_ASSERT(false);
+#endif
+};
+
+#endif
+
+//------------------------------------------------------------------------------
+
+// size_to_precision is a type switch for converting a C++ floating point type
+// to the corresponding precision type.
+
+template<int n, bool fp> struct size_to_precision
+{
+ typedef unknown_precision type;
+};
+
+template<> struct size_to_precision<4, true>
+{
+ typedef single_precision type;
+};
+
+template<> struct size_to_precision<8, true>
+{
+ typedef double_precision type;
+};
+
+template<> struct size_to_precision<10, true>
+{
+ typedef extended_double_precision type;
+};
+
+template<> struct size_to_precision<12, true>
+{
+ typedef extended_double_precision type;
+};
+
+template<> struct size_to_precision<16, true>
+{
+ typedef extended_double_precision type;
+};
+
+//------------------------------------------------------------------------------
+//
+// Figure out whether to use native classification functions based on
+// whether T is a built in floating point type or not:
+//
+template <class T>
+struct select_native
+{
+ typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
+ typedef fp_traits_non_native<T, precision> type;
+};
+template<>
+struct select_native<float>
+{
+ typedef fp_traits_native<float> type;
+};
+template<>
+struct select_native<double>
+{
+ typedef fp_traits_native<double> type;
+};
+template<>
+struct select_native<long double>
+{
+ typedef fp_traits_native<long double> type;
+};
+
+//------------------------------------------------------------------------------
+
+// fp_traits is a type switch that selects the right fp_traits_non_native
+
+#if (defined(BOOST_MATH_USE_C99) && !(defined(__GNUC__) && (__GNUC__ < 4))) \
+ && !defined(__hpux) \
+ && !defined(__DECCXX)\
+ && !defined(__osf__) \
+ && !defined(__SGI_STL_PORT) && !defined(_STLPORT_VERSION)\
+ && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
+# define BOOST_MATH_USE_STD_FPCLASSIFY
+#endif
+
+template<class T> struct fp_traits
+{
+ typedef BOOST_DEDUCED_TYPENAME size_to_precision<sizeof(T), ::boost::is_floating_point<T>::value>::type precision;
+#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
+ typedef typename select_native<T>::type type;
+#else
+ typedef fp_traits_non_native<T, precision> type;
+#endif
+ typedef fp_traits_non_native<T, precision> sign_change_type;
+};
+
+//------------------------------------------------------------------------------
+
+} // namespace detail
+} // namespace math
+} // namespace boost
+
+#endif
diff --git a/boost/math/special_functions/detail/gamma_inva.hpp b/boost/math/special_functions/detail/gamma_inva.hpp
new file mode 100644
index 0000000000..549bc3d552
--- /dev/null
+++ b/boost/math/special_functions/detail/gamma_inva.hpp
@@ -0,0 +1,233 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//
+// This is not a complete header file, it is included by gamma.hpp
+// after it has defined it's definitions. This inverts the incomplete
+// gamma functions P and Q on the first parameter "a" using a generic
+// root finding algorithm (TOMS Algorithm 748).
+//
+
+#ifndef BOOST_MATH_SP_DETAIL_GAMMA_INVA
+#define BOOST_MATH_SP_DETAIL_GAMMA_INVA
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/toms748_solve.hpp>
+#include <boost/cstdint.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+template <class T, class Policy>
+struct gamma_inva_t
+{
+ gamma_inva_t(T z_, T p_, bool invert_) : z(z_), p(p_), invert(invert_) {}
+ T operator()(T a)
+ {
+ return invert ? p - boost::math::gamma_q(a, z, Policy()) : boost::math::gamma_p(a, z, Policy()) - p;
+ }
+private:
+ T z, p;
+ bool invert;
+};
+
+template <class T, class Policy>
+T inverse_poisson_cornish_fisher(T lambda, T p, T q, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ // mean:
+ T m = lambda;
+ // standard deviation:
+ T sigma = sqrt(lambda);
+ // skewness
+ T sk = 1 / sigma;
+ // kurtosis:
+ // T k = 1/lambda;
+ // Get the inverse of a std normal distribution:
+ T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
+ // Set the sign:
+ if(p < 0.5)
+ x = -x;
+ T x2 = x * x;
+ // w is correction term due to skewness
+ T w = x + sk * (x2 - 1) / 6;
+ /*
+ // Add on correction due to kurtosis.
+ // Disabled for now, seems to make things worse?
+ //
+ if(lambda >= 10)
+ w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
+ */
+ w = m + sigma * w;
+ return w > tools::min_value<T>() ? w : tools::min_value<T>();
+}
+
+template <class T, class Policy>
+T gamma_inva_imp(const T& z, const T& p, const T& q, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // for ADL of std lib math functions
+ //
+ // Special cases first:
+ //
+ if(p == 0)
+ {
+ return tools::max_value<T>();
+ }
+ if(q == 0)
+ {
+ return tools::min_value<T>();
+ }
+ //
+ // Function object, this is the functor whose root
+ // we have to solve:
+ //
+ gamma_inva_t<T, Policy> f(z, (p < q) ? p : q, (p < q) ? false : true);
+ //
+ // Tolerance: full precision.
+ //
+ tools::eps_tolerance<T> tol(policies::digits<T, Policy>());
+ //
+ // Now figure out a starting guess for what a may be,
+ // we'll start out with a value that'll put p or q
+ // right bang in the middle of their range, the functions
+ // are quite sensitive so we should need too many steps
+ // to bracket the root from there:
+ //
+ T guess;
+ T factor = 8;
+ if(z >= 1)
+ {
+ //
+ // We can use the relationship between the incomplete
+ // gamma function and the poisson distribution to
+ // calculate an approximate inverse, for large z
+ // this is actually pretty accurate, but it fails badly
+ // when z is very small. Also set our step-factor according
+ // to how accurate we think the result is likely to be:
+ //
+ guess = 1 + inverse_poisson_cornish_fisher(z, q, p, pol);
+ if(z > 5)
+ {
+ if(z > 1000)
+ factor = 1.01f;
+ else if(z > 50)
+ factor = 1.1f;
+ else if(guess > 10)
+ factor = 1.25f;
+ else
+ factor = 2;
+ if(guess < 1.1)
+ factor = 8;
+ }
+ }
+ else if(z > 0.5)
+ {
+ guess = z * 1.2f;
+ }
+ else
+ {
+ guess = -0.4f / log(z);
+ }
+ //
+ // Max iterations permitted:
+ //
+ boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ //
+ // Use our generic derivative-free root finding procedure.
+ // We could use Newton steps here, taking the PDF of the
+ // Poisson distribution as our derivative, but that's
+ // even worse performance-wise than the generic method :-(
+ //
+ std::pair<T, T> r = bracket_and_solve_root(f, guess, factor, false, tol, max_iter, pol);
+ if(max_iter >= policies::get_max_root_iterations<Policy>())
+ policies::raise_evaluation_error<T>("boost::math::gamma_p_inva<%1%>(%1%, %1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol);
+ return (r.first + r.second) / 2;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p_inva(T1 x, T2 p, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(p == 0)
+ {
+ return tools::max_value<result_type>();
+ }
+ if(p == 1)
+ {
+ return tools::min_value<result_type>();
+ }
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::gamma_inva_imp(
+ static_cast<value_type>(x),
+ static_cast<value_type>(p),
+ static_cast<value_type>(1 - static_cast<value_type>(p)),
+ pol), "boost::math::gamma_p_inva<%1%>(%1%, %1%)");
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_q_inva(T1 x, T2 q, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(q == 1)
+ {
+ return tools::max_value<result_type>();
+ }
+ if(q == 0)
+ {
+ return tools::min_value<result_type>();
+ }
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::gamma_inva_imp(
+ static_cast<value_type>(x),
+ static_cast<value_type>(1 - static_cast<value_type>(q)),
+ static_cast<value_type>(q),
+ pol), "boost::math::gamma_q_inva<%1%>(%1%, %1%)");
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p_inva(T1 x, T2 p)
+{
+ return boost::math::gamma_p_inva(x, p, policies::policy<>());
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_q_inva(T1 x, T2 q)
+{
+ return boost::math::gamma_q_inva(x, q, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SP_DETAIL_GAMMA_INVA
+
+
+
diff --git a/boost/math/special_functions/detail/ibeta_inv_ab.hpp b/boost/math/special_functions/detail/ibeta_inv_ab.hpp
new file mode 100644
index 0000000000..8318a28454
--- /dev/null
+++ b/boost/math/special_functions/detail/ibeta_inv_ab.hpp
@@ -0,0 +1,324 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+//
+// This is not a complete header file, it is included by beta.hpp
+// after it has defined it's definitions. This inverts the incomplete
+// beta functions ibeta and ibetac on the first parameters "a"
+// and "b" using a generic root finding algorithm (TOMS Algorithm 748).
+//
+
+#ifndef BOOST_MATH_SP_DETAIL_BETA_INV_AB
+#define BOOST_MATH_SP_DETAIL_BETA_INV_AB
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/toms748_solve.hpp>
+#include <boost/cstdint.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+template <class T, class Policy>
+struct beta_inv_ab_t
+{
+ beta_inv_ab_t(T b_, T z_, T p_, bool invert_, bool swap_ab_) : b(b_), z(z_), p(p_), invert(invert_), swap_ab(swap_ab_) {}
+ T operator()(T a)
+ {
+ return invert ?
+ p - boost::math::ibetac(swap_ab ? b : a, swap_ab ? a : b, z, Policy())
+ : boost::math::ibeta(swap_ab ? b : a, swap_ab ? a : b, z, Policy()) - p;
+ }
+private:
+ T b, z, p;
+ bool invert, swap_ab;
+};
+
+template <class T, class Policy>
+T inverse_negative_binomial_cornish_fisher(T n, T sf, T sfc, T p, T q, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ // mean:
+ T m = n * (sfc) / sf;
+ T t = sqrt(n * (sfc));
+ // standard deviation:
+ T sigma = t / sf;
+ // skewness
+ T sk = (1 + sfc) / t;
+ // kurtosis:
+ T k = (6 - sf * (5+sfc)) / (n * (sfc));
+ // Get the inverse of a std normal distribution:
+ T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
+ // Set the sign:
+ if(p < 0.5)
+ x = -x;
+ T x2 = x * x;
+ // w is correction term due to skewness
+ T w = x + sk * (x2 - 1) / 6;
+ //
+ // Add on correction due to kurtosis.
+ //
+ if(n >= 10)
+ w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
+
+ w = m + sigma * w;
+ if(w < tools::min_value<T>())
+ return tools::min_value<T>();
+ return w;
+}
+
+template <class T, class Policy>
+T ibeta_inv_ab_imp(const T& b, const T& z, const T& p, const T& q, bool swap_ab, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // for ADL of std lib math functions
+ //
+ // Special cases first:
+ //
+ BOOST_MATH_INSTRUMENT_CODE("b = " << b << " z = " << z << " p = " << p << " q = " << " swap = " << swap_ab);
+ if(p == 0)
+ {
+ return swap_ab ? tools::min_value<T>() : tools::max_value<T>();
+ }
+ if(q == 0)
+ {
+ return swap_ab ? tools::max_value<T>() : tools::min_value<T>();
+ }
+ //
+ // Function object, this is the functor whose root
+ // we have to solve:
+ //
+ beta_inv_ab_t<T, Policy> f(b, z, (p < q) ? p : q, (p < q) ? false : true, swap_ab);
+ //
+ // Tolerance: full precision.
+ //
+ tools::eps_tolerance<T> tol(policies::digits<T, Policy>());
+ //
+ // Now figure out a starting guess for what a may be,
+ // we'll start out with a value that'll put p or q
+ // right bang in the middle of their range, the functions
+ // are quite sensitive so we should need too many steps
+ // to bracket the root from there:
+ //
+ T guess = 0;
+ T factor = 5;
+ //
+ // Convert variables to parameters of a negative binomial distribution:
+ //
+ T n = b;
+ T sf = swap_ab ? z : 1-z;
+ T sfc = swap_ab ? 1-z : z;
+ T u = swap_ab ? p : q;
+ T v = swap_ab ? q : p;
+ if(u <= pow(sf, n))
+ {
+ //
+ // Result is less than 1, negative binomial approximation
+ // is useless....
+ //
+ if((p < q) != swap_ab)
+ {
+ guess = (std::min)(T(b * 2), T(1));
+ }
+ else
+ {
+ guess = (std::min)(T(b / 2), T(1));
+ }
+ }
+ if(n * n * n * u * sf > 0.005)
+ guess = 1 + inverse_negative_binomial_cornish_fisher(n, sf, sfc, u, v, pol);
+
+ if(guess < 10)
+ {
+ //
+ // Negative binomial approximation not accurate in this area:
+ //
+ if((p < q) != swap_ab)
+ {
+ guess = (std::min)(T(b * 2), T(10));
+ }
+ else
+ {
+ guess = (std::min)(T(b / 2), T(10));
+ }
+ }
+ else
+ factor = (v < sqrt(tools::epsilon<T>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
+ BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
+ //
+ // Max iterations permitted:
+ //
+ boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ std::pair<T, T> r = bracket_and_solve_root(f, guess, factor, swap_ab ? true : false, tol, max_iter, pol);
+ if(max_iter >= policies::get_max_root_iterations<Policy>())
+ policies::raise_evaluation_error<T>("boost::math::ibeta_invab_imp<%1%>(%1%,%1%,%1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol);
+ return (r.first + r.second) / 2;
+}
+
+} // namespace detail
+
+template <class RT1, class RT2, class RT3, class Policy>
+typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_inva(RT1 b, RT2 x, RT3 p, const Policy& pol)
+{
+ typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(p == 0)
+ {
+ return tools::max_value<result_type>();
+ }
+ if(p == 1)
+ {
+ return tools::min_value<result_type>();
+ }
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::ibeta_inv_ab_imp(
+ static_cast<value_type>(b),
+ static_cast<value_type>(x),
+ static_cast<value_type>(p),
+ static_cast<value_type>(1 - static_cast<value_type>(p)),
+ false, pol),
+ "boost::math::ibeta_inva<%1%>(%1%,%1%,%1%)");
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inva(RT1 b, RT2 x, RT3 q, const Policy& pol)
+{
+ typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(q == 1)
+ {
+ return tools::max_value<result_type>();
+ }
+ if(q == 0)
+ {
+ return tools::min_value<result_type>();
+ }
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::ibeta_inv_ab_imp(
+ static_cast<value_type>(b),
+ static_cast<value_type>(x),
+ static_cast<value_type>(1 - static_cast<value_type>(q)),
+ static_cast<value_type>(q),
+ false, pol),
+ "boost::math::ibetac_inva<%1%>(%1%,%1%,%1%)");
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_invb(RT1 a, RT2 x, RT3 p, const Policy& pol)
+{
+ typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(p == 0)
+ {
+ return tools::min_value<result_type>();
+ }
+ if(p == 1)
+ {
+ return tools::max_value<result_type>();
+ }
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::ibeta_inv_ab_imp(
+ static_cast<value_type>(a),
+ static_cast<value_type>(x),
+ static_cast<value_type>(p),
+ static_cast<value_type>(1 - static_cast<value_type>(p)),
+ true, pol),
+ "boost::math::ibeta_invb<%1%>(%1%,%1%,%1%)");
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_invb(RT1 a, RT2 x, RT3 q, const Policy& pol)
+{
+ typedef typename tools::promote_args<RT1, RT2, RT3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(q == 1)
+ {
+ return tools::min_value<result_type>();
+ }
+ if(q == 0)
+ {
+ return tools::max_value<result_type>();
+ }
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::ibeta_inv_ab_imp(
+ static_cast<value_type>(a),
+ static_cast<value_type>(x),
+ static_cast<value_type>(1 - static_cast<value_type>(q)),
+ static_cast<value_type>(q),
+ true, pol),
+ "boost::math::ibetac_invb<%1%>(%1%,%1%,%1%)");
+}
+
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_inva(RT1 b, RT2 x, RT3 p)
+{
+ return boost::math::ibeta_inva(b, x, p, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inva(RT1 b, RT2 x, RT3 q)
+{
+ return boost::math::ibetac_inva(b, x, q, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_invb(RT1 a, RT2 x, RT3 p)
+{
+ return boost::math::ibeta_invb(a, x, p, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_invb(RT1 a, RT2 x, RT3 q)
+{
+ return boost::math::ibetac_invb(a, x, q, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SP_DETAIL_BETA_INV_AB
+
+
+
diff --git a/boost/math/special_functions/detail/ibeta_inverse.hpp b/boost/math/special_functions/detail/ibeta_inverse.hpp
new file mode 100644
index 0000000000..ccfa9197d9
--- /dev/null
+++ b/boost/math/special_functions/detail/ibeta_inverse.hpp
@@ -0,0 +1,944 @@
+// Copyright John Maddock 2006.
+// Copyright Paul A. Bristow 2007
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
+#define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/beta.hpp>
+#include <boost/math/special_functions/erf.hpp>
+#include <boost/math/tools/roots.hpp>
+#include <boost/math/special_functions/detail/t_distribution_inv.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+//
+// Helper object used by root finding
+// code to convert eta to x.
+//
+template <class T>
+struct temme_root_finder
+{
+ temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {}
+
+ boost::math::tuple<T, T> operator()(T x)
+ {
+ BOOST_MATH_STD_USING // ADL of std names
+
+ T y = 1 - x;
+ if(y == 0)
+ {
+ T big = tools::max_value<T>() / 4;
+ return boost::math::make_tuple(-big, -big);
+ }
+ if(x == 0)
+ {
+ T big = tools::max_value<T>() / 4;
+ return boost::math::make_tuple(-big, big);
+ }
+ T f = log(x) + a * log(y) + t;
+ T f1 = (1 / x) - (a / (y));
+ return boost::math::make_tuple(f, f1);
+ }
+private:
+ T t, a;
+};
+//
+// See:
+// "Asymptotic Inversion of the Incomplete Beta Function"
+// N.M. Temme
+// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
+// Section 2.
+//
+template <class T, class Policy>
+T temme_method_1_ibeta_inverse(T a, T b, T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+
+ const T r2 = sqrt(T(2));
+ //
+ // get the first approximation for eta from the inverse
+ // error function (Eq: 2.9 and 2.10).
+ //
+ T eta0 = boost::math::erfc_inv(2 * z, pol);
+ eta0 /= -sqrt(a / 2);
+
+ T terms[4] = { eta0 };
+ T workspace[7];
+ //
+ // calculate powers:
+ //
+ T B = b - a;
+ T B_2 = B * B;
+ T B_3 = B_2 * B;
+ //
+ // Calculate correction terms:
+ //
+
+ // See eq following 2.15:
+ workspace[0] = -B * r2 / 2;
+ workspace[1] = (1 - 2 * B) / 8;
+ workspace[2] = -(B * r2 / 48);
+ workspace[3] = T(-1) / 192;
+ workspace[4] = -B * r2 / 3840;
+ terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
+ // Eq Following 2.17:
+ workspace[0] = B * r2 * (3 * B - 2) / 12;
+ workspace[1] = (20 * B_2 - 12 * B + 1) / 128;
+ workspace[2] = B * r2 * (20 * B - 1) / 960;
+ workspace[3] = (16 * B_2 + 30 * B - 15) / 4608;
+ workspace[4] = B * r2 * (21 * B + 32) / 53760;
+ workspace[5] = (-32 * B_2 + 63) / 368640;
+ workspace[6] = -B * r2 * (120 * B + 17) / 25804480;
+ terms[2] = tools::evaluate_polynomial(workspace, eta0, 7);
+ // Eq Following 2.17:
+ workspace[0] = B * r2 * (-75 * B_2 + 80 * B - 16) / 480;
+ workspace[1] = (-1080 * B_3 + 868 * B_2 - 90 * B - 45) / 9216;
+ workspace[2] = B * r2 * (-1190 * B_2 + 84 * B + 373) / 53760;
+ workspace[3] = (-2240 * B_3 - 2508 * B_2 + 2100 * B - 165) / 368640;
+ terms[3] = tools::evaluate_polynomial(workspace, eta0, 4);
+ //
+ // Bring them together to get a final estimate for eta:
+ //
+ T eta = tools::evaluate_polynomial(terms, T(1/a), 4);
+ //
+ // now we need to convert eta to x, by solving the appropriate
+ // quadratic equation:
+ //
+ T eta_2 = eta * eta;
+ T c = -exp(-eta_2 / 2);
+ T x;
+ if(eta_2 == 0)
+ x = 0.5;
+ else
+ x = (1 + eta * sqrt((1 + c) / eta_2)) / 2;
+
+ BOOST_ASSERT(x >= 0);
+ BOOST_ASSERT(x <= 1);
+ BOOST_ASSERT(eta * (x - 0.5) >= 0);
+#ifdef BOOST_INSTRUMENT
+ std::cout << "Estimating x with Temme method 1: " << x << std::endl;
+#endif
+ return x;
+}
+//
+// See:
+// "Asymptotic Inversion of the Incomplete Beta Function"
+// N.M. Temme
+// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
+// Section 3.
+//
+template <class T, class Policy>
+T temme_method_2_ibeta_inverse(T /*a*/, T /*b*/, T z, T r, T theta, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+
+ //
+ // Get first estimate for eta, see Eq 3.9 and 3.10,
+ // but note there is a typo in Eq 3.10:
+ //
+ T eta0 = boost::math::erfc_inv(2 * z, pol);
+ eta0 /= -sqrt(r / 2);
+
+ T s = sin(theta);
+ T c = cos(theta);
+ //
+ // Now we need to purturb eta0 to get eta, which we do by
+ // evaluating the polynomial in 1/r at the bottom of page 151,
+ // to do this we first need the error terms e1, e2 e3
+ // which we'll fill into the array "terms". Since these
+ // terms are themselves polynomials, we'll need another
+ // array "workspace" to calculate those...
+ //
+ T terms[4] = { eta0 };
+ T workspace[6];
+ //
+ // some powers of sin(theta)cos(theta) that we'll need later:
+ //
+ T sc = s * c;
+ T sc_2 = sc * sc;
+ T sc_3 = sc_2 * sc;
+ T sc_4 = sc_2 * sc_2;
+ T sc_5 = sc_2 * sc_3;
+ T sc_6 = sc_3 * sc_3;
+ T sc_7 = sc_4 * sc_3;
+ //
+ // Calculate e1 and put it in terms[1], see the middle of page 151:
+ //
+ workspace[0] = (2 * s * s - 1) / (3 * s * c);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co1[] = { -1, -5, 5 };
+ workspace[1] = -tools::evaluate_even_polynomial(co1, s, 3) / (36 * sc_2);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co2[] = { 1, 21, -69, 46 };
+ workspace[2] = tools::evaluate_even_polynomial(co2, s, 4) / (1620 * sc_3);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 7, -2, 33, -62, 31 };
+ workspace[3] = -tools::evaluate_even_polynomial(co3, s, 5) / (6480 * sc_4);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 25, -52, -17, 88, -115, 46 };
+ workspace[4] = tools::evaluate_even_polynomial(co4, s, 6) / (90720 * sc_5);
+ terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
+ //
+ // Now evaluate e2 and put it in terms[2]:
+ //
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co5[] = { 7, 12, -78, 52 };
+ workspace[0] = -tools::evaluate_even_polynomial(co5, s, 4) / (405 * sc_3);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co6[] = { -7, 2, 183, -370, 185 };
+ workspace[1] = tools::evaluate_even_polynomial(co6, s, 5) / (2592 * sc_4);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co7[] = { -533, 776, -1835, 10240, -13525, 5410 };
+ workspace[2] = -tools::evaluate_even_polynomial(co7, s, 6) / (204120 * sc_5);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co8[] = { -1579, 3747, -3372, -15821, 45588, -45213, 15071 };
+ workspace[3] = -tools::evaluate_even_polynomial(co8, s, 7) / (2099520 * sc_6);
+ terms[2] = tools::evaluate_polynomial(workspace, eta0, 4);
+ //
+ // And e3, and put it in terms[3]:
+ //
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co9[] = {449, -1259, -769, 6686, -9260, 3704 };
+ workspace[0] = tools::evaluate_even_polynomial(co9, s, 6) / (102060 * sc_5);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co10[] = { 63149, -151557, 140052, -727469, 2239932, -2251437, 750479 };
+ workspace[1] = -tools::evaluate_even_polynomial(co10, s, 7) / (20995200 * sc_6);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co11[] = { 29233, -78755, 105222, 146879, -1602610, 3195183, -2554139, 729754 };
+ workspace[2] = tools::evaluate_even_polynomial(co11, s, 8) / (36741600 * sc_7);
+ terms[3] = tools::evaluate_polynomial(workspace, eta0, 3);
+ //
+ // Bring the correction terms together to evaluate eta,
+ // this is the last equation on page 151:
+ //
+ T eta = tools::evaluate_polynomial(terms, T(1/r), 4);
+ //
+ // Now that we have eta we need to back solve for x,
+ // we seek the value of x that gives eta in Eq 3.2.
+ // The two methods used are described in section 5.
+ //
+ // Begin by defining a few variables we'll need later:
+ //
+ T x;
+ T s_2 = s * s;
+ T c_2 = c * c;
+ T alpha = c / s;
+ alpha *= alpha;
+ T lu = (-(eta * eta) / (2 * s_2) + log(s_2) + c_2 * log(c_2) / s_2);
+ //
+ // Temme doesn't specify what value to switch on here,
+ // but this seems to work pretty well:
+ //
+ if(fabs(eta) < 0.7)
+ {
+ //
+ // Small eta use the expansion Temme gives in the second equation
+ // of section 5, it's a polynomial in eta:
+ //
+ workspace[0] = s * s;
+ workspace[1] = s * c;
+ workspace[2] = (1 - 2 * workspace[0]) / 3;
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co12[] = { 1, -13, 13 };
+ workspace[3] = tools::evaluate_polynomial(co12, workspace[0], 3) / (36 * s * c);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co13[] = { 1, 21, -69, 46 };
+ workspace[4] = tools::evaluate_polynomial(co13, workspace[0], 4) / (270 * workspace[0] * c * c);
+ x = tools::evaluate_polynomial(workspace, eta, 5);
+#ifdef BOOST_INSTRUMENT
+ std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl;
+#endif
+ }
+ else
+ {
+ //
+ // If eta is large we need to solve Eq 3.2 more directly,
+ // begin by getting an initial approximation for x from
+ // the last equation on page 155, this is a polynomial in u:
+ //
+ T u = exp(lu);
+ workspace[0] = u;
+ workspace[1] = alpha;
+ workspace[2] = 0;
+ workspace[3] = 3 * alpha * (3 * alpha + 1) / 6;
+ workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24;
+ workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120;
+ x = tools::evaluate_polynomial(workspace, u, 6);
+ //
+ // At this point we may or may not have the right answer, Eq-3.2 has
+ // two solutions for x for any given eta, however the mapping in 3.2
+ // is 1:1 with the sign of eta and x-sin^2(theta) being the same.
+ // So we can check if we have the right root of 3.2, and if not
+ // switch x for 1-x. This transformation is motivated by the fact
+ // that the distribution is *almost* symetric so 1-x will be in the right
+ // ball park for the solution:
+ //
+ if((x - s_2) * eta < 0)
+ x = 1 - x;
+#ifdef BOOST_INSTRUMENT
+ std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl;
+#endif
+ }
+ //
+ // The final step is a few Newton-Raphson iterations to
+ // clean up our approximation for x, this is pretty cheap
+ // in general, and very cheap compared to an incomplete beta
+ // evaluation. The limits set on x come from the observation
+ // that the sign of eta and x-sin^2(theta) are the same.
+ //
+ T lower, upper;
+ if(eta < 0)
+ {
+ lower = 0;
+ upper = s_2;
+ }
+ else
+ {
+ lower = s_2;
+ upper = 1;
+ }
+ //
+ // If our initial approximation is out of bounds then bisect:
+ //
+ if((x < lower) || (x > upper))
+ x = (lower+upper) / 2;
+ //
+ // And iterate:
+ //
+ x = tools::newton_raphson_iterate(
+ temme_root_finder<T>(-lu, alpha), x, lower, upper, policies::digits<T, Policy>() / 2);
+
+ return x;
+}
+//
+// See:
+// "Asymptotic Inversion of the Incomplete Beta Function"
+// N.M. Temme
+// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
+// Section 4.
+//
+template <class T, class Policy>
+T temme_method_3_ibeta_inverse(T a, T b, T p, T q, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+
+ //
+ // Begin by getting an initial approximation for the quantity
+ // eta from the dominant part of the incomplete beta:
+ //
+ T eta0;
+ if(p < q)
+ eta0 = boost::math::gamma_q_inv(b, p, pol);
+ else
+ eta0 = boost::math::gamma_p_inv(b, q, pol);
+ eta0 /= a;
+ //
+ // Define the variables and powers we'll need later on:
+ //
+ T mu = b / a;
+ T w = sqrt(1 + mu);
+ T w_2 = w * w;
+ T w_3 = w_2 * w;
+ T w_4 = w_2 * w_2;
+ T w_5 = w_3 * w_2;
+ T w_6 = w_3 * w_3;
+ T w_7 = w_4 * w_3;
+ T w_8 = w_4 * w_4;
+ T w_9 = w_5 * w_4;
+ T w_10 = w_5 * w_5;
+ T d = eta0 - mu;
+ T d_2 = d * d;
+ T d_3 = d_2 * d;
+ T d_4 = d_2 * d_2;
+ T w1 = w + 1;
+ T w1_2 = w1 * w1;
+ T w1_3 = w1 * w1_2;
+ T w1_4 = w1_2 * w1_2;
+ //
+ // Now we need to compute the purturbation error terms that
+ // convert eta0 to eta, these are all polynomials of polynomials.
+ // Probably these should be re-written to use tabulated data
+ // (see examples above), but it's less of a win in this case as we
+ // need to calculate the individual powers for the denominator terms
+ // anyway, so we might as well use them for the numerator-polynomials
+ // as well....
+ //
+ // Refer to p154-p155 for the details of these expansions:
+ //
+ T e1 = (w + 2) * (w - 1) / (3 * w);
+ e1 += (w_3 + 9 * w_2 + 21 * w + 5) * d / (36 * w_2 * w1);
+ e1 -= (w_4 - 13 * w_3 + 69 * w_2 + 167 * w + 46) * d_2 / (1620 * w1_2 * w_3);
+ e1 -= (7 * w_5 + 21 * w_4 + 70 * w_3 + 26 * w_2 - 93 * w - 31) * d_3 / (6480 * w1_3 * w_4);
+ e1 -= (75 * w_6 + 202 * w_5 + 188 * w_4 - 888 * w_3 - 1345 * w_2 + 118 * w + 138) * d_4 / (272160 * w1_4 * w_5);
+
+ T e2 = (28 * w_4 + 131 * w_3 + 402 * w_2 + 581 * w + 208) * (w - 1) / (1620 * w1 * w_3);
+ e2 -= (35 * w_6 - 154 * w_5 - 623 * w_4 - 1636 * w_3 - 3983 * w_2 - 3514 * w - 925) * d / (12960 * w1_2 * w_4);
+ e2 -= (2132 * w_7 + 7915 * w_6 + 16821 * w_5 + 35066 * w_4 + 87490 * w_3 + 141183 * w_2 + 95993 * w + 21640) * d_2 / (816480 * w_5 * w1_3);
+ e2 -= (11053 * w_8 + 53308 * w_7 + 117010 * w_6 + 163924 * w_5 + 116188 * w_4 - 258428 * w_3 - 677042 * w_2 - 481940 * w - 105497) * d_3 / (14696640 * w1_4 * w_6);
+
+ T e3 = -((3592 * w_7 + 8375 * w_6 - 1323 * w_5 - 29198 * w_4 - 89578 * w_3 - 154413 * w_2 - 116063 * w - 29632) * (w - 1)) / (816480 * w_5 * w1_2);
+ e3 -= (442043 * w_9 + 2054169 * w_8 + 3803094 * w_7 + 3470754 * w_6 + 2141568 * w_5 - 2393568 * w_4 - 19904934 * w_3 - 34714674 * w_2 - 23128299 * w - 5253353) * d / (146966400 * w_6 * w1_3);
+ e3 -= (116932 * w_10 + 819281 * w_9 + 2378172 * w_8 + 4341330 * w_7 + 6806004 * w_6 + 10622748 * w_5 + 18739500 * w_4 + 30651894 * w_3 + 30869976 * w_2 + 15431867 * w + 2919016) * d_2 / (146966400 * w1_4 * w_7);
+ //
+ // Combine eta0 and the error terms to compute eta (Second eqaution p155):
+ //
+ T eta = eta0 + e1 / a + e2 / (a * a) + e3 / (a * a * a);
+ //
+ // Now we need to solve Eq 4.2 to obtain x. For any given value of
+ // eta there are two solutions to this equation, and since the distribtion
+ // may be very skewed, these are not related by x ~ 1-x we used when
+ // implementing section 3 above. However we know that:
+ //
+ // cross < x <= 1 ; iff eta < mu
+ // x == cross ; iff eta == mu
+ // 0 <= x < cross ; iff eta > mu
+ //
+ // Where cross == 1 / (1 + mu)
+ // Many thanks to Prof Temme for clarifying this point.
+ //
+ // Therefore we'll just jump straight into Newton iterations
+ // to solve Eq 4.2 using these bounds, and simple bisection
+ // as the first guess, in practice this converges pretty quickly
+ // and we only need a few digits correct anyway:
+ //
+ if(eta <= 0)
+ eta = tools::min_value<T>();
+ T u = eta - mu * log(eta) + (1 + mu) * log(1 + mu) - mu;
+ T cross = 1 / (1 + mu);
+ T lower = eta < mu ? cross : 0;
+ T upper = eta < mu ? 1 : cross;
+ T x = (lower + upper) / 2;
+ x = tools::newton_raphson_iterate(
+ temme_root_finder<T>(u, mu), x, lower, upper, policies::digits<T, Policy>() / 2);
+#ifdef BOOST_INSTRUMENT
+ std::cout << "Estimating x with Temme method 3: " << x << std::endl;
+#endif
+ return x;
+}
+
+template <class T, class Policy>
+struct ibeta_roots
+{
+ ibeta_roots(T _a, T _b, T t, bool inv = false)
+ : a(_a), b(_b), target(t), invert(inv) {}
+
+ boost::math::tuple<T, T, T> operator()(T x)
+ {
+ BOOST_MATH_STD_USING // ADL of std names
+
+ BOOST_FPU_EXCEPTION_GUARD
+
+ T f1;
+ T y = 1 - x;
+ T f = ibeta_imp(a, b, x, Policy(), invert, true, &f1) - target;
+ if(invert)
+ f1 = -f1;
+ if(y == 0)
+ y = tools::min_value<T>() * 64;
+ if(x == 0)
+ x = tools::min_value<T>() * 64;
+
+ T f2 = f1 * (-y * a + (b - 2) * x + 1);
+ if(fabs(f2) < y * x * tools::max_value<T>())
+ f2 /= (y * x);
+ if(invert)
+ f2 = -f2;
+
+ // make sure we don't have a zero derivative:
+ if(f1 == 0)
+ f1 = (invert ? -1 : 1) * tools::min_value<T>() * 64;
+
+ return boost::math::make_tuple(f, f1, f2);
+ }
+private:
+ T a, b, target;
+ bool invert;
+};
+
+template <class T, class Policy>
+T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
+{
+ BOOST_MATH_STD_USING // For ADL of math functions.
+
+ //
+ // Handle trivial cases first:
+ //
+ if(q == 0)
+ {
+ if(py) *py = 0;
+ return 1;
+ }
+ else if(p == 0)
+ {
+ if(py) *py = 1;
+ return 0;
+ }
+ else if((a == 1) && (b == 1))
+ {
+ if(py) *py = 1 - p;
+ return p;
+ }
+ //
+ // The flag invert is set to true if we swap a for b and p for q,
+ // in which case the result has to be subtracted from 1:
+ //
+ bool invert = false;
+ //
+ // Depending upon which approximation method we use, we may end up
+ // calculating either x or y initially (where y = 1-x):
+ //
+ T x = 0; // Set to a safe zero to avoid a
+ // MSVC 2005 warning C4701: potentially uninitialized local variable 'x' used
+ // But code inspection appears to ensure that x IS assigned whatever the code path.
+ T y;
+
+ // For some of the methods we can put tighter bounds
+ // on the result than simply [0,1]:
+ //
+ T lower = 0;
+ T upper = 1;
+ //
+ // Student's T with b = 0.5 gets handled as a special case, swap
+ // around if the arguments are in the "wrong" order:
+ //
+ if((a == 0.5f) && (b >= 0.5f))
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ invert = !invert;
+ }
+ //
+ // Select calculation method for the initial estimate:
+ //
+ if((b == 0.5f) && (a >= 0.5f))
+ {
+ //
+ // We have a Student's T distribution:
+ x = find_ibeta_inv_from_t_dist(a, p, q, &y, pol);
+ }
+ else if(a + b > 5)
+ {
+ //
+ // When a+b is large then we can use one of Prof Temme's
+ // asymptotic expansions, begin by swapping things around
+ // so that p < 0.5, we do this to avoid cancellations errors
+ // when p is large.
+ //
+ if(p > 0.5)
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ invert = !invert;
+ }
+ T minv = (std::min)(a, b);
+ T maxv = (std::max)(a, b);
+ if((sqrt(minv) > (maxv - minv)) && (minv > 5))
+ {
+ //
+ // When a and b differ by a small amount
+ // the curve is quite symmetrical and we can use an error
+ // function to approximate the inverse. This is the cheapest
+ // of the three Temme expantions, and the calculated value
+ // for x will never be much larger than p, so we don't have
+ // to worry about cancellation as long as p is small.
+ //
+ x = temme_method_1_ibeta_inverse(a, b, p, pol);
+ y = 1 - x;
+ }
+ else
+ {
+ T r = a + b;
+ T theta = asin(sqrt(a / r));
+ T lambda = minv / r;
+ if((lambda >= 0.2) && (lambda <= 0.8) && (r >= 10))
+ {
+ //
+ // The second error function case is the next cheapest
+ // to use, it brakes down when the result is likely to be
+ // very small, if a+b is also small, but we can use a
+ // cheaper expansion there in any case. As before x won't
+ // be much larger than p, so as long as p is small we should
+ // be free of cancellation error.
+ //
+ T ppa = pow(p, 1/a);
+ if((ppa < 0.0025) && (a + b < 200))
+ {
+ x = ppa * pow(a * boost::math::beta(a, b, pol), 1/a);
+ }
+ else
+ x = temme_method_2_ibeta_inverse(a, b, p, r, theta, pol);
+ y = 1 - x;
+ }
+ else
+ {
+ //
+ // If we get here then a and b are very different in magnitude
+ // and we need to use the third of Temme's methods which
+ // involves inverting the incomplete gamma. This is much more
+ // expensive than the other methods. We also can only use this
+ // method when a > b, which can lead to cancellation errors
+ // if we really want y (as we will when x is close to 1), so
+ // a different expansion is used in that case.
+ //
+ if(a < b)
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ invert = !invert;
+ }
+ //
+ // Try and compute the easy way first:
+ //
+ T bet = 0;
+ if(b < 2)
+ bet = boost::math::beta(a, b, pol);
+ if(bet != 0)
+ {
+ y = pow(b * q * bet, 1/b);
+ x = 1 - y;
+ }
+ else
+ y = 1;
+ if(y > 1e-5)
+ {
+ x = temme_method_3_ibeta_inverse(a, b, p, q, pol);
+ y = 1 - x;
+ }
+ }
+ }
+ }
+ else if((a < 1) && (b < 1))
+ {
+ //
+ // Both a and b less than 1,
+ // there is a point of inflection at xs:
+ //
+ T xs = (1 - a) / (2 - a - b);
+ //
+ // Now we need to ensure that we start our iteration from the
+ // right side of the inflection point:
+ //
+ T fs = boost::math::ibeta(a, b, xs, pol) - p;
+ if(fabs(fs) / p < tools::epsilon<T>() * 3)
+ {
+ // The result is at the point of inflection, best just return it:
+ *py = invert ? xs : 1 - xs;
+ return invert ? 1-xs : xs;
+ }
+ if(fs < 0)
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ invert = !invert;
+ xs = 1 - xs;
+ }
+ T xg = pow(a * p * boost::math::beta(a, b, pol), 1/a);
+ x = xg / (1 + xg);
+ y = 1 / (1 + xg);
+ //
+ // And finally we know that our result is below the inflection
+ // point, so set an upper limit on our search:
+ //
+ if(x > xs)
+ x = xs;
+ upper = xs;
+ }
+ else if((a > 1) && (b > 1))
+ {
+ //
+ // Small a and b, both greater than 1,
+ // there is a point of inflection at xs,
+ // and it's complement is xs2, we must always
+ // start our iteration from the right side of the
+ // point of inflection.
+ //
+ T xs = (a - 1) / (a + b - 2);
+ T xs2 = (b - 1) / (a + b - 2);
+ T ps = boost::math::ibeta(a, b, xs, pol) - p;
+
+ if(ps < 0)
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ std::swap(xs, xs2);
+ invert = !invert;
+ }
+ //
+ // Estimate x and y, using expm1 to get a good estimate
+ // for y when it's very small:
+ //
+ T lx = log(p * a * boost::math::beta(a, b, pol)) / a;
+ x = exp(lx);
+ y = x < 0.9 ? T(1 - x) : (T)(-boost::math::expm1(lx, pol));
+
+ if((b < a) && (x < 0.2))
+ {
+ //
+ // Under a limited range of circumstances we can improve
+ // our estimate for x, frankly it's clear if this has much effect!
+ //
+ T ap1 = a - 1;
+ T bm1 = b - 1;
+ T a_2 = a * a;
+ T a_3 = a * a_2;
+ T b_2 = b * b;
+ T terms[5] = { 0, 1 };
+ terms[2] = bm1 / ap1;
+ ap1 *= ap1;
+ terms[3] = bm1 * (3 * a * b + 5 * b + a_2 - a - 4) / (2 * (a + 2) * ap1);
+ ap1 *= (a + 1);
+ terms[4] = bm1 * (33 * a * b_2 + 31 * b_2 + 8 * a_2 * b_2 - 30 * a * b - 47 * b + 11 * a_2 * b + 6 * a_3 * b + 18 + 4 * a - a_3 + a_2 * a_2 - 10 * a_2)
+ / (3 * (a + 3) * (a + 2) * ap1);
+ x = tools::evaluate_polynomial(terms, x, 5);
+ }
+ //
+ // And finally we know that our result is below the inflection
+ // point, so set an upper limit on our search:
+ //
+ if(x > xs)
+ x = xs;
+ upper = xs;
+ }
+ else /*if((a <= 1) != (b <= 1))*/
+ {
+ //
+ // If all else fails we get here, only one of a and b
+ // is above 1, and a+b is small. Start by swapping
+ // things around so that we have a concave curve with b > a
+ // and no points of inflection in [0,1]. As long as we expect
+ // x to be small then we can use the simple (and cheap) power
+ // term to estimate x, but when we expect x to be large then
+ // this greatly underestimates x and leaves us trying to
+ // iterate "round the corner" which may take almost forever...
+ //
+ // We could use Temme's inverse gamma function case in that case,
+ // this works really rather well (albeit expensively) even though
+ // strictly speaking we're outside it's defined range.
+ //
+ // However it's expensive to compute, and an alternative approach
+ // which models the curve as a distorted quarter circle is much
+ // cheaper to compute, and still keeps the number of iterations
+ // required down to a reasonable level. With thanks to Prof Temme
+ // for this suggestion.
+ //
+ if(b < a)
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ invert = !invert;
+ }
+ if(pow(p, 1/a) < 0.5)
+ {
+ x = pow(p * a * boost::math::beta(a, b, pol), 1 / a);
+ if(x == 0)
+ x = boost::math::tools::min_value<T>();
+ y = 1 - x;
+ }
+ else /*if(pow(q, 1/b) < 0.1)*/
+ {
+ // model a distorted quarter circle:
+ y = pow(1 - pow(p, b * boost::math::beta(a, b, pol)), 1/b);
+ if(y == 0)
+ y = boost::math::tools::min_value<T>();
+ x = 1 - y;
+ }
+ }
+
+ //
+ // Now we have a guess for x (and for y) we can set things up for
+ // iteration. If x > 0.5 it pays to swap things round:
+ //
+ if(x > 0.5)
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ std::swap(x, y);
+ invert = !invert;
+ T l = 1 - upper;
+ T u = 1 - lower;
+ lower = l;
+ upper = u;
+ }
+ //
+ // lower bound for our search:
+ //
+ // We're not interested in denormalised answers as these tend to
+ // these tend to take up lots of iterations, given that we can't get
+ // accurate derivatives in this area (they tend to be infinite).
+ //
+ if(lower == 0)
+ {
+ if(invert && (py == 0))
+ {
+ //
+ // We're not interested in answers smaller than machine epsilon:
+ //
+ lower = boost::math::tools::epsilon<T>();
+ if(x < lower)
+ x = lower;
+ }
+ else
+ lower = boost::math::tools::min_value<T>();
+ if(x < lower)
+ x = lower;
+ }
+ //
+ // Figure out how many digits to iterate towards:
+ //
+ int digits = boost::math::policies::digits<T, Policy>() / 2;
+ if((x < 1e-50) && ((a < 1) || (b < 1)))
+ {
+ //
+ // If we're in a region where the first derivative is very
+ // large, then we have to take care that the root-finder
+ // doesn't terminate prematurely. We'll bump the precision
+ // up to avoid this, but we have to take care not to set the
+ // precision too high or the last few iterations will just
+ // thrash around and convergence may be slow in this case.
+ // Try 3/4 of machine epsilon:
+ //
+ digits *= 3;
+ digits /= 2;
+ }
+ //
+ // Now iterate, we can use either p or q as the target here
+ // depending on which is smaller:
+ //
+ boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ x = boost::math::tools::halley_iterate(
+ boost::math::detail::ibeta_roots<T, Policy>(a, b, (p < q ? p : q), (p < q ? false : true)), x, lower, upper, digits, max_iter);
+ policies::check_root_iterations<T>("boost::math::ibeta<%1%>(%1%, %1%, %1%)", max_iter, pol);
+ //
+ // We don't really want these asserts here, but they are useful for sanity
+ // checking that we have the limits right, uncomment if you suspect bugs *only*.
+ //
+ //BOOST_ASSERT(x != upper);
+ //BOOST_ASSERT((x != lower) || (x == boost::math::tools::min_value<T>()) || (x == boost::math::tools::epsilon<T>()));
+ //
+ // Tidy up, if we "lower" was too high then zero is the best answer we have:
+ //
+ if(x == lower)
+ x = 0;
+ if(py)
+ *py = invert ? x : 1 - x;
+ return invert ? 1-x : x;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class T3, class T4, class Policy>
+inline typename tools::promote_args<T1, T2, T3, T4>::type
+ ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol)
+{
+ static const char* function = "boost::math::ibeta_inv<%1%>(%1%,%1%,%1%)";
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(a <= 0)
+ return policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
+ if(b <= 0)
+ return policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
+ if((p < 0) || (p > 1))
+ return policies::raise_domain_error<result_type>(function, "Argument p outside the range [0,1] in the incomplete beta function inverse (got p=%1%).", p, pol);
+
+ value_type rx, ry;
+
+ rx = detail::ibeta_inv_imp(
+ static_cast<value_type>(a),
+ static_cast<value_type>(b),
+ static_cast<value_type>(p),
+ static_cast<value_type>(1 - p),
+ forwarding_policy(), &ry);
+
+ if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
+}
+
+template <class T1, class T2, class T3, class T4>
+inline typename tools::promote_args<T1, T2, T3, T4>::type
+ ibeta_inv(T1 a, T2 b, T3 p, T4* py)
+{
+ return ibeta_inv(a, b, p, py, policies::policy<>());
+}
+
+template <class T1, class T2, class T3>
+inline typename tools::promote_args<T1, T2, T3>::type
+ ibeta_inv(T1 a, T2 b, T3 p)
+{
+ return ibeta_inv(a, b, p, static_cast<T1*>(0), policies::policy<>());
+}
+
+template <class T1, class T2, class T3, class Policy>
+inline typename tools::promote_args<T1, T2, T3>::type
+ ibeta_inv(T1 a, T2 b, T3 p, const Policy& pol)
+{
+ return ibeta_inv(a, b, p, static_cast<T1*>(0), pol);
+}
+
+template <class T1, class T2, class T3, class T4, class Policy>
+inline typename tools::promote_args<T1, T2, T3, T4>::type
+ ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol)
+{
+ static const char* function = "boost::math::ibetac_inv<%1%>(%1%,%1%,%1%)";
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ if(a <= 0)
+ policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
+ if(b <= 0)
+ policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
+ if((q < 0) || (q > 1))
+ policies::raise_domain_error<result_type>(function, "Argument q outside the range [0,1] in the incomplete beta function inverse (got q=%1%).", q, pol);
+
+ value_type rx, ry;
+
+ rx = detail::ibeta_inv_imp(
+ static_cast<value_type>(a),
+ static_cast<value_type>(b),
+ static_cast<value_type>(1 - q),
+ static_cast<value_type>(q),
+ forwarding_policy(), &ry);
+
+ if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
+}
+
+template <class T1, class T2, class T3, class T4>
+inline typename tools::promote_args<T1, T2, T3, T4>::type
+ ibetac_inv(T1 a, T2 b, T3 q, T4* py)
+{
+ return ibetac_inv(a, b, q, py, policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inv(RT1 a, RT2 b, RT3 q)
+{
+ typedef typename remove_cv<RT1>::type dummy;
+ return ibetac_inv(a, b, q, static_cast<dummy*>(0), policies::policy<>());
+}
+
+template <class RT1, class RT2, class RT3, class Policy>
+inline typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy& pol)
+{
+ typedef typename remove_cv<RT1>::type dummy;
+ return ibetac_inv(a, b, q, static_cast<dummy*>(0), pol);
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
+
+
+
+
diff --git a/boost/math/special_functions/detail/iconv.hpp b/boost/math/special_functions/detail/iconv.hpp
new file mode 100644
index 0000000000..8916eaed1d
--- /dev/null
+++ b/boost/math/special_functions/detail/iconv.hpp
@@ -0,0 +1,42 @@
+// Copyright (c) 2009 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_ICONV_HPP
+#define BOOST_MATH_ICONV_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/round.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+
+namespace boost { namespace math { namespace detail{
+
+template <class T, class Policy>
+inline int iconv_imp(T v, Policy const&, mpl::true_ const&)
+{
+ return static_cast<int>(v);
+}
+
+template <class T, class Policy>
+inline int iconv_imp(T v, Policy const& pol, mpl::false_ const&)
+{
+ BOOST_MATH_STD_USING
+ return iround(v);
+}
+
+template <class T, class Policy>
+inline int iconv(T v, Policy const& pol)
+{
+ typedef typename boost::is_convertible<T, int>::type tag_type;
+ return iconv_imp(v, pol, tag_type());
+}
+
+
+}}} // namespaces
+
+#endif // BOOST_MATH_ICONV_HPP
+
diff --git a/boost/math/special_functions/detail/igamma_inverse.hpp b/boost/math/special_functions/detail/igamma_inverse.hpp
new file mode 100644
index 0000000000..53875ff83e
--- /dev/null
+++ b/boost/math/special_functions/detail/igamma_inverse.hpp
@@ -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));
+ z = exp((v + z - s) / a);
+ s = boost::math::log1p(z / ap1 * (1 + z / ap2));
+ z = exp((v + z - s) / a);
+ s = boost::math::log1p(z / ap1 * (1 + z / ap2 * (1 + z / (a + 3))));
+ z = exp((v + z - s) / a);
+ BOOST_MATH_INSTRUMENT_VARIABLE(z);
+ }
+
+ if((z <= 0.01 * ap1) || (z > 0.7 * ap1))
+ {
+ result = z;
+ if(z <= 0.002 * ap1)
+ *p_has_10_digits = true;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ // DiDonato and Morris Eq 36:
+ T ls = log(didonato_SN(a, z, 100, T(1e-4)));
+ T v = log(p) + boost::math::lgamma(ap1, pol);
+ z = exp((v + z - ls) / a);
+ result = z * (1 - (a * log(z) - z - v + ls) / (a - z));
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ }
+ }
+ return result;
+}
+
+template <class T, class Policy>
+struct gamma_p_inverse_func
+{
+ gamma_p_inverse_func(T a_, T p_, bool inv) : a(a_), p(p_), invert(inv)
+ {
+ //
+ // If p is too near 1 then P(x) - p suffers from cancellation
+ // errors causing our root-finding algorithms to "thrash", better
+ // to invert in this case and calculate Q(x) - (1-p) instead.
+ //
+ // Of course if p is *very* close to 1, then the answer we get will
+ // be inaccurate anyway (because there's not enough information in p)
+ // but at least we will converge on the (inaccurate) answer quickly.
+ //
+ if(p > 0.9)
+ {
+ p = 1 - p;
+ invert = !invert;
+ }
+ }
+
+ boost::math::tuple<T, T, T> operator()(const T& x)const
+ {
+ BOOST_FPU_EXCEPTION_GUARD
+ //
+ // Calculate P(x) - p and the first two derivates, or if the invert
+ // flag is set, then Q(x) - q and it's derivatives.
+ //
+ typedef typename policies::evaluation<T, Policy>::type value_type;
+ typedef typename lanczos::lanczos<T, Policy>::type evaluation_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ BOOST_MATH_STD_USING // For ADL of std functions.
+
+ T f, f1;
+ value_type ft;
+ f = static_cast<T>(boost::math::detail::gamma_incomplete_imp(
+ static_cast<value_type>(a),
+ static_cast<value_type>(x),
+ true, invert,
+ forwarding_policy(), &ft));
+ f1 = static_cast<T>(ft);
+ T f2;
+ T div = (a - x - 1) / x;
+ f2 = f1;
+ if((fabs(div) > 1) && (tools::max_value<T>() / fabs(div) < f2))
+ {
+ // overflow:
+ f2 = -tools::max_value<T>() / 2;
+ }
+ else
+ {
+ f2 *= div;
+ }
+
+ if(invert)
+ {
+ f1 = -f1;
+ f2 = -f2;
+ }
+
+ return boost::math::make_tuple(f - p, f1, f2);
+ }
+private:
+ T a, p;
+ bool invert;
+};
+
+template <class T, class Policy>
+T gamma_p_inv_imp(T a, T p, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+
+ static const char* function = "boost::math::gamma_p_inv<%1%>(%1%, %1%)";
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(a);
+ BOOST_MATH_INSTRUMENT_VARIABLE(p);
+
+ if(a <= 0)
+ policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
+ if((p < 0) || (p > 1))
+ policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got p=%1%).", p, pol);
+ if(p == 1)
+ return tools::max_value<T>();
+ if(p == 0)
+ return 0;
+ bool has_10_digits;
+ T guess = detail::find_inverse_gamma<T>(a, p, 1 - p, pol, &has_10_digits);
+ if((policies::digits<T, Policy>() <= 36) && has_10_digits)
+ return guess;
+ T lower = tools::min_value<T>();
+ if(guess <= lower)
+ guess = tools::min_value<T>();
+ BOOST_MATH_INSTRUMENT_VARIABLE(guess);
+ //
+ // Work out how many digits to converge to, normally this is
+ // 2/3 of the digits in T, but if the first derivative is very
+ // large convergence is slow, so we'll bump it up to full
+ // precision to prevent premature termination of the root-finding routine.
+ //
+ unsigned digits = policies::digits<T, Policy>();
+ if(digits < 30)
+ {
+ digits *= 2;
+ digits /= 3;
+ }
+ else
+ {
+ digits /= 2;
+ digits -= 1;
+ }
+ if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
+ digits = policies::digits<T, Policy>() - 2;
+ //
+ // Go ahead and iterate:
+ //
+ boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ guess = tools::halley_iterate(
+ detail::gamma_p_inverse_func<T, Policy>(a, p, false),
+ guess,
+ lower,
+ tools::max_value<T>(),
+ digits,
+ max_iter);
+ policies::check_root_iterations<T>(function, max_iter, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(guess);
+ if(guess == lower)
+ guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
+ return guess;
+}
+
+template <class T, class Policy>
+T gamma_q_inv_imp(T a, T q, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+
+ static const char* function = "boost::math::gamma_q_inv<%1%>(%1%, %1%)";
+
+ if(a <= 0)
+ policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
+ if((q < 0) || (q > 1))
+ policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got q=%1%).", q, pol);
+ if(q == 0)
+ return tools::max_value<T>();
+ if(q == 1)
+ return 0;
+ bool has_10_digits;
+ T guess = detail::find_inverse_gamma<T>(a, 1 - q, q, pol, &has_10_digits);
+ if((policies::digits<T, Policy>() <= 36) && has_10_digits)
+ return guess;
+ T lower = tools::min_value<T>();
+ if(guess <= lower)
+ guess = tools::min_value<T>();
+ //
+ // Work out how many digits to converge to, normally this is
+ // 2/3 of the digits in T, but if the first derivative is very
+ // large convergence is slow, so we'll bump it up to full
+ // precision to prevent premature termination of the root-finding routine.
+ //
+ unsigned digits = policies::digits<T, Policy>();
+ if(digits < 30)
+ {
+ digits *= 2;
+ digits /= 3;
+ }
+ else
+ {
+ digits /= 2;
+ digits -= 1;
+ }
+ if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
+ digits = policies::digits<T, Policy>();
+ //
+ // Go ahead and iterate:
+ //
+ boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
+ guess = tools::halley_iterate(
+ detail::gamma_p_inverse_func<T, Policy>(a, q, true),
+ guess,
+ lower,
+ tools::max_value<T>(),
+ digits,
+ max_iter);
+ policies::check_root_iterations<T>(function, max_iter, pol);
+ if(guess == lower)
+ guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
+ return guess;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p_inv(T1 a, T2 p, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ return detail::gamma_p_inv_imp(
+ static_cast<result_type>(a),
+ static_cast<result_type>(p), pol);
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_q_inv(T1 a, T2 p, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ return detail::gamma_q_inv_imp(
+ static_cast<result_type>(a),
+ static_cast<result_type>(p), pol);
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p_inv(T1 a, T2 p)
+{
+ return gamma_p_inv(a, p, policies::policy<>());
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_q_inv(T1 a, T2 p)
+{
+ return gamma_q_inv(a, p, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
+
+
+
diff --git a/boost/math/special_functions/detail/igamma_large.hpp b/boost/math/special_functions/detail/igamma_large.hpp
new file mode 100644
index 0000000000..f9a810c489
--- /dev/null
+++ b/boost/math/special_functions/detail/igamma_large.hpp
@@ -0,0 +1,769 @@
+// Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// This file implements the asymptotic expansions of the incomplete
+// gamma functions P(a, x) and Q(a, x), used when a is large and
+// x ~ a.
+//
+// The primary reference is:
+//
+// "The Asymptotic Expansion of the Incomplete Gamma Functions"
+// N. M. Temme.
+// Siam J. Math Anal. Vol 10 No 4, July 1979, p757.
+//
+// A different way of evaluating these expansions,
+// plus a lot of very useful background information is in:
+//
+// "A Set of Algorithms For the Incomplete Gamma Functions."
+// N. M. Temme.
+// Probability in the Engineering and Informational Sciences,
+// 8, 1994, 291.
+//
+// An alternative implementation is in:
+//
+// "Computation of the Incomplete Gamma Function Ratios and their Inverse."
+// A. R. Didonato and A. H. Morris.
+// ACM TOMS, Vol 12, No 4, Dec 1986, p377.
+//
+// There are various versions of the same code below, each accurate
+// to a different precision. To understand the code, refer to Didonato
+// and Morris, from Eq 17 and 18 onwards.
+//
+// The coefficients used here are not taken from Didonato and Morris:
+// the domain over which these expansions are used is slightly different
+// to theirs, and their constants are not quite accurate enough for
+// 128-bit long double's. Instead the coefficients were calculated
+// using the methods described by Temme p762 from Eq 3.8 onwards.
+// The values obtained agree with those obtained by Didonato and Morris
+// (at least to the first 30 digits that they provide).
+// At double precision the degrees of polynomial required for full
+// machine precision are close to those recomended to Didonato and Morris,
+// but of course many more terms are needed for larger types.
+//
+#ifndef BOOST_MATH_DETAIL_IGAMMA_LARGE
+#define BOOST_MATH_DETAIL_IGAMMA_LARGE
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+namespace boost{ namespace math{ namespace detail{
+
+// This version will never be called (at runtime), it's a stub used
+// when T is unsuitable to be passed to these routines:
+//
+template <class T, class Policy>
+inline T igamma_temme_large(T, T, const Policy& /* pol */, mpl::int_<0> const *)
+{
+ // stub function, should never actually be called
+ BOOST_ASSERT(0);
+ return 0;
+}
+//
+// This version is accurate for up to 64-bit mantissa's,
+// (80-bit long double, or 10^-20).
+//
+template <class T, class Policy>
+T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<64> const *)
+{
+ BOOST_MATH_STD_USING // ADL of std functions
+ T sigma = (x - a) / a;
+ T phi = -boost::math::log1pmx(sigma, pol);
+ T y = a * phi;
+ T z = sqrt(2 * phi);
+ if(x < a)
+ z = -z;
+
+ T workspace[13];
+
+ static const T C0[] = {
+ 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
+
diff --git a/boost/math/special_functions/detail/lanczos_sse2.hpp b/boost/math/special_functions/detail/lanczos_sse2.hpp
new file mode 100644
index 0000000000..6a3f3e5347
--- /dev/null
+++ b/boost/math/special_functions/detail/lanczos_sse2.hpp
@@ -0,0 +1,201 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS_SSE2
+#define BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS_SSE2
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <emmintrin.h>
+
+#if defined(__GNUC__) || defined(__PGI)
+#define ALIGN16 __attribute__((aligned(16)))
+#else
+#define ALIGN16 __declspec(align(16))
+#endif
+
+namespace boost{ namespace math{ namespace lanczos{
+
+template <>
+inline double lanczos13m53::lanczos_sum<double>(const double& x)
+{
+ static const ALIGN16 double coeff[26] = {
+ static_cast<double>(2.506628274631000270164908177133837338626L),
+ static_cast<double>(1u),
+ static_cast<double>(210.8242777515793458725097339207133627117L),
+ static_cast<double>(66u),
+ static_cast<double>(8071.672002365816210638002902272250613822L),
+ static_cast<double>(1925u),
+ static_cast<double>(186056.2653952234950402949897160456992822L),
+ static_cast<double>(32670u),
+ static_cast<double>(2876370.628935372441225409051620849613599L),
+ static_cast<double>(357423u),
+ static_cast<double>(31426415.58540019438061423162831820536287L),
+ static_cast<double>(2637558u),
+ static_cast<double>(248874557.8620541565114603864132294232163L),
+ static_cast<double>(13339535u),
+ static_cast<double>(1439720407.311721673663223072794912393972L),
+ static_cast<double>(45995730u),
+ static_cast<double>(6039542586.35202800506429164430729792107L),
+ static_cast<double>(105258076u),
+ static_cast<double>(17921034426.03720969991975575445893111267L),
+ static_cast<double>(150917976u),
+ static_cast<double>(35711959237.35566804944018545154716670596L),
+ static_cast<double>(120543840u),
+ static_cast<double>(42919803642.64909876895789904700198885093L),
+ static_cast<double>(39916800u),
+ static_cast<double>(23531376880.41075968857200767445163675473L),
+ static_cast<double>(0u)
+ };
+ register __m128d vx = _mm_load1_pd(&x);
+ register __m128d sum_even = _mm_load_pd(coeff);
+ register __m128d sum_odd = _mm_load_pd(coeff+2);
+ register __m128d nc_odd, nc_even;
+ register __m128d vx2 = _mm_mul_pd(vx, vx);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 4);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 6);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 8);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 10);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 12);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 14);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 16);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 18);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 20);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 22);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 24);
+ sum_odd = _mm_mul_pd(sum_odd, vx);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_even = _mm_add_pd(sum_even, sum_odd);
+
+
+ double ALIGN16 t[2];
+ _mm_store_pd(t, sum_even);
+
+ return t[0] / t[1];
+}
+
+template <>
+inline double lanczos13m53::lanczos_sum_expG_scaled<double>(const double& x)
+{
+ static const ALIGN16 double coeff[26] = {
+ static_cast<double>(0.006061842346248906525783753964555936883222L),
+ static_cast<double>(1u),
+ static_cast<double>(0.5098416655656676188125178644804694509993L),
+ static_cast<double>(66u),
+ static_cast<double>(19.51992788247617482847860966235652136208L),
+ static_cast<double>(1925u),
+ static_cast<double>(449.9445569063168119446858607650988409623L),
+ static_cast<double>(32670u),
+ static_cast<double>(6955.999602515376140356310115515198987526L),
+ static_cast<double>(357423u),
+ static_cast<double>(75999.29304014542649875303443598909137092L),
+ static_cast<double>(2637558u),
+ static_cast<double>(601859.6171681098786670226533699352302507L),
+ static_cast<double>(13339535u),
+ static_cast<double>(3481712.15498064590882071018964774556468L),
+ static_cast<double>(45995730u),
+ static_cast<double>(14605578.08768506808414169982791359218571L),
+ static_cast<double>(105258076u),
+ static_cast<double>(43338889.32467613834773723740590533316085L),
+ static_cast<double>(150917976u),
+ static_cast<double>(86363131.28813859145546927288977868422342L),
+ static_cast<double>(120543840u),
+ static_cast<double>(103794043.1163445451906271053616070238554L),
+ static_cast<double>(39916800u),
+ static_cast<double>(56906521.91347156388090791033559122686859L),
+ static_cast<double>(0u)
+ };
+ register __m128d vx = _mm_load1_pd(&x);
+ register __m128d sum_even = _mm_load_pd(coeff);
+ register __m128d sum_odd = _mm_load_pd(coeff+2);
+ register __m128d nc_odd, nc_even;
+ register __m128d vx2 = _mm_mul_pd(vx, vx);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 4);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 6);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 8);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 10);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 12);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 14);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 16);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 18);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 20);
+ sum_odd = _mm_mul_pd(sum_odd, vx2);
+ nc_odd = _mm_load_pd(coeff + 22);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_odd = _mm_add_pd(sum_odd, nc_odd);
+
+ sum_even = _mm_mul_pd(sum_even, vx2);
+ nc_even = _mm_load_pd(coeff + 24);
+ sum_odd = _mm_mul_pd(sum_odd, vx);
+ sum_even = _mm_add_pd(sum_even, nc_even);
+ sum_even = _mm_add_pd(sum_even, sum_odd);
+
+
+ double ALIGN16 t[2];
+ _mm_store_pd(t, sum_even);
+
+ return t[0] / t[1];
+}
+
+} // namespace lanczos
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS
+
+
+
+
diff --git a/boost/math/special_functions/detail/lgamma_small.hpp b/boost/math/special_functions/detail/lgamma_small.hpp
new file mode 100644
index 0000000000..526a573583
--- /dev/null
+++ b/boost/math/special_functions/detail/lgamma_small.hpp
@@ -0,0 +1,514 @@
+// (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{
+
+//
+// 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>(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>(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),
+ 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[] = {
+ 1,
+ 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[] = {
+ 1,
+ 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[] = {
+ 1,
+ 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
+
diff --git a/boost/math/special_functions/detail/round_fwd.hpp b/boost/math/special_functions/detail/round_fwd.hpp
new file mode 100644
index 0000000000..952259ae93
--- /dev/null
+++ b/boost/math/special_functions/detail/round_fwd.hpp
@@ -0,0 +1,80 @@
+// Copyright John Maddock 2008.
+
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SPECIAL_ROUND_FWD_HPP
+#define BOOST_MATH_SPECIAL_ROUND_FWD_HPP
+
+#include <boost/config.hpp>
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+namespace boost
+{
+ namespace math
+ {
+
+ template <class T, class Policy>
+ T trunc(const T& v, const Policy& pol);
+ template <class T>
+ T trunc(const T& v);
+ template <class T, class Policy>
+ int itrunc(const T& v, const Policy& pol);
+ template <class T>
+ int itrunc(const T& v);
+ template <class T, class Policy>
+ long ltrunc(const T& v, const Policy& pol);
+ template <class T>
+ long ltrunc(const T& v);
+#ifdef BOOST_HAS_LONG_LONG
+ template <class T, class Policy>
+ boost::long_long_type lltrunc(const T& v, const Policy& pol);
+ template <class T>
+ boost::long_long_type lltrunc(const T& v);
+#endif
+ template <class T, class Policy>
+ T round(const T& v, const Policy& pol);
+ template <class T>
+ T round(const T& v);
+ template <class T, class Policy>
+ int iround(const T& v, const Policy& pol);
+ template <class T>
+ int iround(const T& v);
+ template <class T, class Policy>
+ long lround(const T& v, const Policy& pol);
+ template <class T>
+ long lround(const T& v);
+#ifdef BOOST_HAS_LONG_LONG
+ template <class T, class Policy>
+ boost::long_long_type llround(const T& v, const Policy& pol);
+ template <class T>
+ boost::long_long_type llround(const T& v);
+#endif
+ template <class T, class Policy>
+ T modf(const T& v, T* ipart, const Policy& pol);
+ template <class T>
+ T modf(const T& v, T* ipart);
+ template <class T, class Policy>
+ T modf(const T& v, int* ipart, const Policy& pol);
+ template <class T>
+ T modf(const T& v, int* ipart);
+ template <class T, class Policy>
+ T modf(const T& v, long* ipart, const Policy& pol);
+ template <class T>
+ T modf(const T& v, long* ipart);
+#ifdef BOOST_HAS_LONG_LONG
+ template <class T, class Policy>
+ T modf(const T& v, boost::long_long_type* ipart, const Policy& pol);
+ template <class T>
+ T modf(const T& v, boost::long_long_type* ipart);
+#endif
+
+ }
+}
+#endif // BOOST_MATH_SPECIAL_ROUND_FWD_HPP
+
diff --git a/boost/math/special_functions/detail/t_distribution_inv.hpp b/boost/math/special_functions/detail/t_distribution_inv.hpp
new file mode 100644
index 0000000000..4e0d2d1b79
--- /dev/null
+++ b/boost/math/special_functions/detail/t_distribution_inv.hpp
@@ -0,0 +1,544 @@
+// Copyright John Maddock 2007.
+// Copyright Paul A. Bristow 2007
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SF_DETAIL_INV_T_HPP
+#define BOOST_MATH_SF_DETAIL_INV_T_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/cbrt.hpp>
+#include <boost/math/special_functions/round.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+//
+// The main method used is due to Hill:
+//
+// G. W. Hill, Algorithm 396, Student's t-Quantiles,
+// Communications of the ACM, 13(10): 619-620, Oct., 1970.
+//
+template <class T, class Policy>
+T inverse_students_t_hill(T ndf, T u, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ BOOST_ASSERT(u <= 0.5);
+
+ T a, b, c, d, q, x, y;
+
+ if (ndf > 1e20f)
+ return -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
+
+ a = 1 / (ndf - 0.5f);
+ b = 48 / (a * a);
+ c = ((20700 * a / b - 98) * a - 16) * a + 96.36f;
+ d = ((94.5f / (b + c) - 3) / b + 1) * sqrt(a * constants::pi<T>() / 2) * ndf;
+ y = pow(d * 2 * u, 2 / ndf);
+
+ if (y > (0.05f + a))
+ {
+ //
+ // Asymptotic inverse expansion about normal:
+ //
+ x = -boost::math::erfc_inv(2 * u, pol) * constants::root_two<T>();
+ y = x * x;
+
+ if (ndf < 5)
+ c += 0.3f * (ndf - 4.5f) * (x + 0.6f);
+ c += (((0.05f * d * x - 5) * x - 7) * x - 2) * x + b;
+ y = (((((0.4f * y + 6.3f) * y + 36) * y + 94.5f) / c - y - 3) / b + 1) * x;
+ y = boost::math::expm1(a * y * y, pol);
+ }
+ else
+ {
+ y = ((1 / (((ndf + 6) / (ndf * y) - 0.089f * d - 0.822f)
+ * (ndf + 2) * 3) + 0.5 / (ndf + 4)) * y - 1)
+ * (ndf + 1) / (ndf + 2) + 1 / y;
+ }
+ q = sqrt(ndf * y);
+
+ return -q;
+}
+//
+// Tail and body series are due to Shaw:
+//
+// www.mth.kcl.ac.uk/~shaww/web_page/papers/Tdistribution06.pdf
+//
+// Shaw, W.T., 2006, "Sampling Student's T distribution - use of
+// the inverse cumulative distribution function."
+// Journal of Computational Finance, Vol 9 Issue 4, pp 37-73, Summer 2006
+//
+template <class T, class Policy>
+T inverse_students_t_tail_series(T df, T v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ // Tail series expansion, see section 6 of Shaw's paper.
+ // w is calculated using Eq 60:
+ T w = boost::math::tgamma_delta_ratio(df / 2, constants::half<T>(), pol)
+ * sqrt(df * constants::pi<T>()) * v;
+ // define some variables:
+ T np2 = df + 2;
+ T np4 = df + 4;
+ T np6 = df + 6;
+ //
+ // Calculate the coefficients d(k), these depend only on the
+ // number of degrees of freedom df, so at least in theory
+ // we could tabulate these for fixed df, see p15 of Shaw:
+ //
+ T d[7] = { 1, };
+ d[1] = -(df + 1) / (2 * np2);
+ np2 *= (df + 2);
+ d[2] = -df * (df + 1) * (df + 3) / (8 * np2 * np4);
+ np2 *= df + 2;
+ d[3] = -df * (df + 1) * (df + 5) * (((3 * df) + 7) * df -2) / (48 * np2 * np4 * np6);
+ np2 *= (df + 2);
+ np4 *= (df + 4);
+ d[4] = -df * (df + 1) * (df + 7) *
+ ( (((((15 * df) + 154) * df + 465) * df + 286) * df - 336) * df + 64 )
+ / (384 * np2 * np4 * np6 * (df + 8));
+ np2 *= (df + 2);
+ d[5] = -df * (df + 1) * (df + 3) * (df + 9)
+ * (((((((35 * df + 452) * df + 1573) * df + 600) * df - 2020) * df) + 928) * df -128)
+ / (1280 * np2 * np4 * np6 * (df + 8) * (df + 10));
+ np2 *= (df + 2);
+ np4 *= (df + 4);
+ np6 *= (df + 6);
+ d[6] = -df * (df + 1) * (df + 11)
+ * ((((((((((((945 * df) + 31506) * df + 425858) * df + 2980236) * df + 11266745) * df + 20675018) * df + 7747124) * df - 22574632) * df - 8565600) * df + 18108416) * df - 7099392) * df + 884736)
+ / (46080 * np2 * np4 * np6 * (df + 8) * (df + 10) * (df +12));
+ //
+ // Now bring everthing together to provide the result,
+ // this is Eq 62 of Shaw:
+ //
+ T rn = sqrt(df);
+ T div = pow(rn * w, 1 / df);
+ T power = div * div;
+ T result = tools::evaluate_polynomial<7, T, T>(d, power);
+ result *= rn;
+ result /= div;
+ return -result;
+}
+
+template <class T, class Policy>
+T inverse_students_t_body_series(T df, T u, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ //
+ // Body series for small N:
+ //
+ // Start with Eq 56 of Shaw:
+ //
+ T v = boost::math::tgamma_delta_ratio(df / 2, constants::half<T>(), pol)
+ * sqrt(df * constants::pi<T>()) * (u - constants::half<T>());
+ //
+ // Workspace for the polynomial coefficients:
+ //
+ T c[11] = { 0, 1, };
+ //
+ // Figure out what the coefficients are, note these depend
+ // only on the degrees of freedom (Eq 57 of Shaw):
+ //
+ T in = 1 / df;
+ c[2] = 0.16666666666666666667 + 0.16666666666666666667 * in;
+ c[3] = (0.0083333333333333333333 * in
+ + 0.066666666666666666667) * in
+ + 0.058333333333333333333;
+ c[4] = ((0.00019841269841269841270 * in
+ + 0.0017857142857142857143) * in
+ + 0.026785714285714285714) * in
+ + 0.025198412698412698413;
+ c[5] = (((2.7557319223985890653e-6 * in
+ + 0.00037477954144620811287) * in
+ - 0.0011078042328042328042) * in
+ + 0.010559964726631393298) * in
+ + 0.012039792768959435626;
+ c[6] = ((((2.5052108385441718775e-8 * in
+ - 0.000062705427288760622094) * in
+ + 0.00059458674042007375341) * in
+ - 0.0016095979637646304313) * in
+ + 0.0061039211560044893378) * in
+ + 0.0038370059724226390893;
+ c[7] = (((((1.6059043836821614599e-10 * in
+ + 0.000015401265401265401265) * in
+ - 0.00016376804137220803887) * in
+ + 0.00069084207973096861986) * in
+ - 0.0012579159844784844785) * in
+ + 0.0010898206731540064873) * in
+ + 0.0032177478835464946576;
+ c[8] = ((((((7.6471637318198164759e-13 * in
+ - 3.9851014346715404916e-6) * in
+ + 0.000049255746366361445727) * in
+ - 0.00024947258047043099953) * in
+ + 0.00064513046951456342991) * in
+ - 0.00076245135440323932387) * in
+ + 0.000033530976880017885309) * in
+ + 0.0017438262298340009980;
+ c[9] = (((((((2.8114572543455207632e-15 * in
+ + 1.0914179173496789432e-6) * in
+ - 0.000015303004486655377567) * in
+ + 0.000090867107935219902229) * in
+ - 0.00029133414466938067350) * in
+ + 0.00051406605788341121363) * in
+ - 0.00036307660358786885787) * in
+ - 0.00031101086326318780412) * in
+ + 0.00096472747321388644237;
+ c[10] = ((((((((8.2206352466243297170e-18 * in
+ - 3.1239569599829868045e-7) * in
+ + 4.8903045291975346210e-6) * in
+ - 0.000033202652391372058698) * in
+ + 0.00012645437628698076975) * in
+ - 0.00028690924218514613987) * in
+ + 0.00035764655430568632777) * in
+ - 0.00010230378073700412687) * in
+ - 0.00036942667800009661203) * in
+ + 0.00054229262813129686486;
+ //
+ // The result is then a polynomial in v (see Eq 56 of Shaw):
+ //
+ return tools::evaluate_odd_polynomial<11, T, T>(c, v);
+}
+
+template <class T, class Policy>
+T inverse_students_t(T df, T u, T v, const Policy& pol, bool* pexact = 0)
+{
+ //
+ // df = number of degrees of freedom.
+ // u = probablity.
+ // v = 1 - u.
+ // l = lanczos type to use.
+ //
+ BOOST_MATH_STD_USING
+ bool invert = false;
+ T result = 0;
+ if(pexact)
+ *pexact = false;
+ if(u > v)
+ {
+ // function is symmetric, invert it:
+ std::swap(u, v);
+ invert = true;
+ }
+ if((floor(df) == df) && (df < 20))
+ {
+ //
+ // we have integer degrees of freedom, try for the special
+ // cases first:
+ //
+ T tolerance = ldexp(1.0f, (2 * policies::digits<T, Policy>()) / 3);
+
+ switch(itrunc(df, Policy()))
+ {
+ case 1:
+ {
+ //
+ // df = 1 is the same as the Cauchy distribution, see
+ // Shaw Eq 35:
+ //
+ if(u == 0.5)
+ result = 0;
+ else
+ result = -cos(constants::pi<T>() * u) / sin(constants::pi<T>() * u);
+ if(pexact)
+ *pexact = true;
+ break;
+ }
+ case 2:
+ {
+ //
+ // df = 2 has an exact result, see Shaw Eq 36:
+ //
+ result =(2 * u - 1) / sqrt(2 * u * v);
+ if(pexact)
+ *pexact = true;
+ break;
+ }
+ case 4:
+ {
+ //
+ // df = 4 has an exact result, see Shaw Eq 38 & 39:
+ //
+ T alpha = 4 * u * v;
+ T root_alpha = sqrt(alpha);
+ T r = 4 * cos(acos(root_alpha) / 3) / root_alpha;
+ T x = sqrt(r - 4);
+ result = u - 0.5f < 0 ? (T)-x : x;
+ if(pexact)
+ *pexact = true;
+ break;
+ }
+ case 6:
+ {
+ //
+ // We get numeric overflow in this area:
+ //
+ if(u < 1e-150)
+ return (invert ? -1 : 1) * inverse_students_t_hill(df, u, pol);
+ //
+ // Newton-Raphson iteration of a polynomial case,
+ // choice of seed value is taken from Shaw's online
+ // supplement:
+ //
+ T a = 4 * (u - u * u);//1 - 4 * (u - 0.5f) * (u - 0.5f);
+ T b = boost::math::cbrt(a);
+ static const T c = 0.85498797333834849467655443627193;
+ T p = 6 * (1 + c * (1 / b - 1));
+ T p0;
+ do{
+ T p2 = p * p;
+ T p4 = p2 * p2;
+ T p5 = p * p4;
+ p0 = p;
+ // next term is given by Eq 41:
+ p = 2 * (8 * a * p5 - 270 * p2 + 2187) / (5 * (4 * a * p4 - 216 * p - 243));
+ }while(fabs((p - p0) / p) > tolerance);
+ //
+ // Use Eq 45 to extract the result:
+ //
+ p = sqrt(p - df);
+ result = (u - 0.5f) < 0 ? (T)-p : p;
+ break;
+ }
+#if 0
+ //
+ // These are Shaw's "exact" but iterative solutions
+ // for even df, the numerical accuracy of these is
+ // rather less than Hill's method, so these are disabled
+ // for now, which is a shame because they are reasonably
+ // quick to evaluate...
+ //
+ case 8:
+ {
+ //
+ // Newton-Raphson iteration of a polynomial case,
+ // choice of seed value is taken from Shaw's online
+ // supplement:
+ //
+ static const T c8 = 0.85994765706259820318168359251872L;
+ T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
+ T b = pow(a, T(1) / 4);
+ T p = 8 * (1 + c8 * (1 / b - 1));
+ T p0 = p;
+ do{
+ T p5 = p * p;
+ p5 *= p5 * p;
+ p0 = p;
+ // Next term is given by Eq 42:
+ p = 2 * (3 * p + (640 * (160 + p * (24 + p * (p + 4)))) / (-5120 + p * (-2048 - 960 * p + a * p5))) / 7;
+ }while(fabs((p - p0) / p) > tolerance);
+ //
+ // Use Eq 45 to extract the result:
+ //
+ p = sqrt(p - df);
+ result = (u - 0.5f) < 0 ? -p : p;
+ break;
+ }
+ case 10:
+ {
+ //
+ // Newton-Raphson iteration of a polynomial case,
+ // choice of seed value is taken from Shaw's online
+ // supplement:
+ //
+ static const T c10 = 0.86781292867813396759105692122285L;
+ T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
+ T b = pow(a, T(1) / 5);
+ T p = 10 * (1 + c10 * (1 / b - 1));
+ T p0;
+ do{
+ T p6 = p * p;
+ p6 *= p6 * p6;
+ p0 = p;
+ // Next term given by Eq 43:
+ p = (8 * p) / 9 + (218750 * (21875 + 4 * p * (625 + p * (75 + 2 * p * (5 + p))))) /
+ (9 * (-68359375 + 8 * p * (-2343750 + p * (-546875 - 175000 * p + 8 * a * p6))));
+ }while(fabs((p - p0) / p) > tolerance);
+ //
+ // Use Eq 45 to extract the result:
+ //
+ p = sqrt(p - df);
+ result = (u - 0.5f) < 0 ? -p : p;
+ break;
+ }
+#endif
+ default:
+ goto calculate_real;
+ }
+ }
+ else
+ {
+calculate_real:
+ if(df < 3)
+ {
+ //
+ // Use a roughly linear scheme to choose between Shaw's
+ // tail series and body series:
+ //
+ T crossover = 0.2742f - df * 0.0242143f;
+ if(u > crossover)
+ {
+ result = boost::math::detail::inverse_students_t_body_series(df, u, pol);
+ }
+ else
+ {
+ result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
+ }
+ }
+ else
+ {
+ //
+ // Use Hill's method except in the exteme tails
+ // where we use Shaw's tail series.
+ // The crossover point is roughly exponential in -df:
+ //
+ T crossover = ldexp(1.0f, iround(T(df / -0.654f), pol));
+ if(u > crossover)
+ {
+ result = boost::math::detail::inverse_students_t_hill(df, u, pol);
+ }
+ else
+ {
+ result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
+ }
+ }
+ }
+ return invert ? (T)-result : result;
+}
+
+template <class T, class Policy>
+inline T find_ibeta_inv_from_t_dist(T a, T p, T q, T* py, const Policy& pol)
+{
+ T u = (p > q) ? T(0.5f - q) / T(2) : T(p / 2);
+ T v = 1 - u; // u < 0.5 so no cancellation error
+ T df = a * 2;
+ T t = boost::math::detail::inverse_students_t(df, u, v, pol);
+ T x = df / (df + t * t);
+ *py = t * t / (df + t * t);
+ return x;
+}
+
+template <class T, class Policy>
+inline T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::false_*)
+{
+ BOOST_MATH_STD_USING
+ //
+ // Need to use inverse incomplete beta to get
+ // required precision so not so fast:
+ //
+ T probability = (p > 0.5) ? 1 - p : p;
+ T t, x, y(0);
+ x = ibeta_inv(df / 2, T(0.5), 2 * probability, &y, pol);
+ if(df * y > tools::max_value<T>() * x)
+ t = policies::raise_overflow_error<T>("boost::math::students_t_quantile<%1%>(%1%,%1%)", 0, pol);
+ else
+ t = sqrt(df * y / x);
+ //
+ // Figure out sign based on the size of p:
+ //
+ if(p < 0.5)
+ t = -t;
+ return t;
+}
+
+template <class T, class Policy>
+T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::true_*)
+{
+ BOOST_MATH_STD_USING
+ bool invert = false;
+ if((df < 2) && (floor(df) != df))
+ return boost::math::detail::fast_students_t_quantile_imp(df, p, pol, static_cast<mpl::false_*>(0));
+ if(p > 0.5)
+ {
+ p = 1 - p;
+ invert = true;
+ }
+ //
+ // Get an estimate of the result:
+ //
+ bool exact;
+ T t = inverse_students_t(df, p, T(1-p), pol, &exact);
+ if((t == 0) || exact)
+ return invert ? -t : t; // can't do better!
+ //
+ // Change variables to inverse incomplete beta:
+ //
+ T t2 = t * t;
+ T xb = df / (df + t2);
+ T y = t2 / (df + t2);
+ T a = df / 2;
+ //
+ // t can be so large that x underflows,
+ // just return our estimate in that case:
+ //
+ if(xb == 0)
+ return t;
+ //
+ // Get incomplete beta and it's derivative:
+ //
+ T f1;
+ T f0 = xb < y ? ibeta_imp(a, constants::half<T>(), xb, pol, false, true, &f1)
+ : ibeta_imp(constants::half<T>(), a, y, pol, true, true, &f1);
+
+ // Get cdf from incomplete beta result:
+ T p0 = f0 / 2 - p;
+ // Get pdf from derivative:
+ T p1 = f1 * sqrt(y * xb * xb * xb / df);
+ //
+ // Second derivative divided by p1:
+ //
+ // yacas gives:
+ //
+ // In> PrettyForm(Simplify(D(t) (1 + t^2/v) ^ (-(v+1)/2)))
+ //
+ // | | v + 1 | |
+ // | -| ----- + 1 | |
+ // | | 2 | |
+ // -| | 2 | |
+ // | | t | |
+ // | | -- + 1 | |
+ // | ( v + 1 ) * | v | * t |
+ // ---------------------------------------------
+ // v
+ //
+ // Which after some manipulation is:
+ //
+ // -p1 * t * (df + 1) / (t^2 + df)
+ //
+ T p2 = t * (df + 1) / (t * t + df);
+ // Halley step:
+ t = fabs(t);
+ t += p0 / (p1 + p0 * p2 / 2);
+ return !invert ? -t : t;
+}
+
+template <class T, class Policy>
+inline T fast_students_t_quantile(T df, T p, const Policy& pol)
+{
+ typedef typename policies::evaluation<T, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ typedef mpl::bool_<
+ (std::numeric_limits<T>::digits <= 53)
+ &&
+ (std::numeric_limits<T>::is_specialized)
+ &&
+ (std::numeric_limits<T>::radix == 2)
+ > tag_type;
+ return policies::checked_narrowing_cast<T, forwarding_policy>(fast_students_t_quantile_imp(static_cast<value_type>(df), static_cast<value_type>(p), pol, static_cast<tag_type*>(0)), "boost::math::students_t_quantile<%1%>(%1%,%1%,%1%)");
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_SF_DETAIL_INV_T_HPP
+
+
+
diff --git a/boost/math/special_functions/detail/unchecked_factorial.hpp b/boost/math/special_functions/detail/unchecked_factorial.hpp
new file mode 100644
index 0000000000..eb8927a268
--- /dev/null
+++ b/boost/math/special_functions/detail/unchecked_factorial.hpp
@@ -0,0 +1,415 @@
+// Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SP_UC_FACTORIALS_HPP
+#define BOOST_MATH_SP_UC_FACTORIALS_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/array.hpp>
+#ifdef BOOST_MSVC
+#pragma warning(push) // Temporary until lexical cast fixed.
+#pragma warning(disable: 4127 4701)
+#endif
+#include <boost/lexical_cast.hpp>
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+
+namespace boost { namespace math
+{
+// Forward declarations:
+template <class T>
+struct max_factorial;
+
+// Definitions:
+template <>
+inline float unchecked_factorial<float>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(float))
+{
+ static const boost::array<float, 35> factorials = {{
+ 1.0F,
+ 1.0F,
+ 2.0F,
+ 6.0F,
+ 24.0F,
+ 120.0F,
+ 720.0F,
+ 5040.0F,
+ 40320.0F,
+ 362880.0F,
+ 3628800.0F,
+ 39916800.0F,
+ 479001600.0F,
+ 6227020800.0F,
+ 87178291200.0F,
+ 1307674368000.0F,
+ 20922789888000.0F,
+ 355687428096000.0F,
+ 6402373705728000.0F,
+ 121645100408832000.0F,
+ 0.243290200817664e19F,
+ 0.5109094217170944e20F,
+ 0.112400072777760768e22F,
+ 0.2585201673888497664e23F,
+ 0.62044840173323943936e24F,
+ 0.15511210043330985984e26F,
+ 0.403291461126605635584e27F,
+ 0.10888869450418352160768e29F,
+ 0.304888344611713860501504e30F,
+ 0.8841761993739701954543616e31F,
+ 0.26525285981219105863630848e33F,
+ 0.822283865417792281772556288e34F,
+ 0.26313083693369353016721801216e36F,
+ 0.868331761881188649551819440128e37F,
+ 0.29523279903960414084761860964352e39F,
+ }};
+
+ return factorials[i];
+}
+
+template <>
+struct max_factorial<float>
+{
+ BOOST_STATIC_CONSTANT(unsigned, value = 34);
+};
+
+
+template <>
+inline long double unchecked_factorial<long double>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(long double))
+{
+ static const boost::array<long double, 171> factorials = {{
+ 1L,
+ 1L,
+ 2L,
+ 6L,
+ 24L,
+ 120L,
+ 720L,
+ 5040L,
+ 40320L,
+ 362880.0L,
+ 3628800.0L,
+ 39916800.0L,
+ 479001600.0L,
+ 6227020800.0L,
+ 87178291200.0L,
+ 1307674368000.0L,
+ 20922789888000.0L,
+ 355687428096000.0L,
+ 6402373705728000.0L,
+ 121645100408832000.0L,
+ 0.243290200817664e19L,
+ 0.5109094217170944e20L,
+ 0.112400072777760768e22L,
+ 0.2585201673888497664e23L,
+ 0.62044840173323943936e24L,
+ 0.15511210043330985984e26L,
+ 0.403291461126605635584e27L,
+ 0.10888869450418352160768e29L,
+ 0.304888344611713860501504e30L,
+ 0.8841761993739701954543616e31L,
+ 0.26525285981219105863630848e33L,
+ 0.822283865417792281772556288e34L,
+ 0.26313083693369353016721801216e36L,
+ 0.868331761881188649551819440128e37L,
+ 0.29523279903960414084761860964352e39L,
+ 0.103331479663861449296666513375232e41L,
+ 0.3719933267899012174679994481508352e42L,
+ 0.137637530912263450463159795815809024e44L,
+ 0.5230226174666011117600072241000742912e45L,
+ 0.203978820811974433586402817399028973568e47L,
+ 0.815915283247897734345611269596115894272e48L,
+ 0.3345252661316380710817006205344075166515e50L,
+ 0.1405006117752879898543142606244511569936e52L,
+ 0.6041526306337383563735513206851399750726e53L,
+ 0.265827157478844876804362581101461589032e55L,
+ 0.1196222208654801945619631614956577150644e57L,
+ 0.5502622159812088949850305428800254892962e58L,
+ 0.2586232415111681806429643551536119799692e60L,
+ 0.1241391559253607267086228904737337503852e62L,
+ 0.6082818640342675608722521633212953768876e63L,
+ 0.3041409320171337804361260816606476884438e65L,
+ 0.1551118753287382280224243016469303211063e67L,
+ 0.8065817517094387857166063685640376697529e68L,
+ 0.427488328406002556429801375338939964969e70L,
+ 0.2308436973392413804720927426830275810833e72L,
+ 0.1269640335365827592596510084756651695958e74L,
+ 0.7109985878048634518540456474637249497365e75L,
+ 0.4052691950487721675568060190543232213498e77L,
+ 0.2350561331282878571829474910515074683829e79L,
+ 0.1386831185456898357379390197203894063459e81L,
+ 0.8320987112741390144276341183223364380754e82L,
+ 0.507580213877224798800856812176625227226e84L,
+ 0.3146997326038793752565312235495076408801e86L,
+ 0.1982608315404440064116146708361898137545e88L,
+ 0.1268869321858841641034333893351614808029e90L,
+ 0.8247650592082470666723170306785496252186e91L,
+ 0.5443449390774430640037292402478427526443e93L,
+ 0.3647111091818868528824985909660546442717e95L,
+ 0.2480035542436830599600990418569171581047e97L,
+ 0.1711224524281413113724683388812728390923e99L,
+ 0.1197857166996989179607278372168909873646e101L,
+ 0.8504785885678623175211676442399260102886e102L,
+ 0.6123445837688608686152407038527467274078e104L,
+ 0.4470115461512684340891257138125051110077e106L,
+ 0.3307885441519386412259530282212537821457e108L,
+ 0.2480914081139539809194647711659403366093e110L,
+ 0.188549470166605025498793226086114655823e112L,
+ 0.1451830920282858696340707840863082849837e114L,
+ 0.1132428117820629783145752115873204622873e116L,
+ 0.8946182130782975286851441715398316520698e117L,
+ 0.7156945704626380229481153372318653216558e119L,
+ 0.5797126020747367985879734231578109105412e121L,
+ 0.4753643337012841748421382069894049466438e123L,
+ 0.3945523969720658651189747118012061057144e125L,
+ 0.3314240134565353266999387579130131288001e127L,
+ 0.2817104114380550276949479442260611594801e129L,
+ 0.2422709538367273238176552320344125971528e131L,
+ 0.210775729837952771721360051869938959523e133L,
+ 0.1854826422573984391147968456455462843802e135L,
+ 0.1650795516090846108121691926245361930984e137L,
+ 0.1485715964481761497309522733620825737886e139L,
+ 0.1352001527678402962551665687594951421476e141L,
+ 0.1243841405464130725547532432587355307758e143L,
+ 0.1156772507081641574759205162306240436215e145L,
+ 0.1087366156656743080273652852567866010042e147L,
+ 0.103299784882390592625997020993947270954e149L,
+ 0.9916779348709496892095714015418938011582e150L,
+ 0.9619275968248211985332842594956369871234e152L,
+ 0.942689044888324774562618574305724247381e154L,
+ 0.9332621544394415268169923885626670049072e156L,
+ 0.9332621544394415268169923885626670049072e158L,
+ 0.9425947759838359420851623124482936749562e160L,
+ 0.9614466715035126609268655586972595484554e162L,
+ 0.990290071648618040754671525458177334909e164L,
+ 0.1029901674514562762384858386476504428305e167L,
+ 0.1081396758240290900504101305800329649721e169L,
+ 0.1146280563734708354534347384148349428704e171L,
+ 0.1226520203196137939351751701038733888713e173L,
+ 0.132464181945182897449989183712183259981e175L,
+ 0.1443859583202493582204882102462797533793e177L,
+ 0.1588245541522742940425370312709077287172e179L,
+ 0.1762952551090244663872161047107075788761e181L,
+ 0.1974506857221074023536820372759924883413e183L,
+ 0.2231192748659813646596607021218715118256e185L,
+ 0.2543559733472187557120132004189335234812e187L,
+ 0.2925093693493015690688151804817735520034e189L,
+ 0.339310868445189820119825609358857320324e191L,
+ 0.396993716080872089540195962949863064779e193L,
+ 0.4684525849754290656574312362808384164393e195L,
+ 0.5574585761207605881323431711741977155627e197L,
+ 0.6689502913449127057588118054090372586753e199L,
+ 0.8094298525273443739681622845449350829971e201L,
+ 0.9875044200833601362411579871448208012564e203L,
+ 0.1214630436702532967576624324188129585545e206L,
+ 0.1506141741511140879795014161993280686076e208L,
+ 0.1882677176888926099743767702491600857595e210L,
+ 0.237217324288004688567714730513941708057e212L,
+ 0.3012660018457659544809977077527059692324e214L,
+ 0.3856204823625804217356770659234636406175e216L,
+ 0.4974504222477287440390234150412680963966e218L,
+ 0.6466855489220473672507304395536485253155e220L,
+ 0.8471580690878820510984568758152795681634e222L,
+ 0.1118248651196004307449963076076169029976e225L,
+ 0.1487270706090685728908450891181304809868e227L,
+ 0.1992942746161518876737324194182948445223e229L,
+ 0.269047270731805048359538766214698040105e231L,
+ 0.3659042881952548657689727220519893345429e233L,
+ 0.5012888748274991661034926292112253883237e235L,
+ 0.6917786472619488492228198283114910358867e237L,
+ 0.9615723196941089004197195613529725398826e239L,
+ 0.1346201247571752460587607385894161555836e242L,
+ 0.1898143759076170969428526414110767793728e244L,
+ 0.2695364137888162776588507508037290267094e246L,
+ 0.3854370717180072770521565736493325081944e248L,
+ 0.5550293832739304789551054660550388118e250L,
+ 0.80479260574719919448490292577980627711e252L,
+ 0.1174997204390910823947958271638517164581e255L,
+ 0.1727245890454638911203498659308620231933e257L,
+ 0.2556323917872865588581178015776757943262e259L,
+ 0.380892263763056972698595524350736933546e261L,
+ 0.571338395644585459047893286526105400319e263L,
+ 0.8627209774233240431623188626544191544816e265L,
+ 0.1311335885683452545606724671234717114812e268L,
+ 0.2006343905095682394778288746989117185662e270L,
+ 0.308976961384735088795856467036324046592e272L,
+ 0.4789142901463393876335775239063022722176e274L,
+ 0.7471062926282894447083809372938315446595e276L,
+ 0.1172956879426414428192158071551315525115e279L,
+ 0.1853271869493734796543609753051078529682e281L,
+ 0.2946702272495038326504339507351214862195e283L,
+ 0.4714723635992061322406943211761943779512e285L,
+ 0.7590705053947218729075178570936729485014e287L,
+ 0.1229694218739449434110178928491750176572e290L,
+ 0.2004401576545302577599591653441552787813e292L,
+ 0.3287218585534296227263330311644146572013e294L,
+ 0.5423910666131588774984495014212841843822e296L,
+ 0.9003691705778437366474261723593317460744e298L,
+ 0.1503616514864999040201201707840084015944e301L,
+ 0.2526075744973198387538018869171341146786e303L,
+ 0.4269068009004705274939251888899566538069e305L,
+ 0.7257415615307998967396728211129263114717e307L,
+ }};
+
+ return factorials[i];
+}
+
+template <>
+struct max_factorial<long double>
+{
+ BOOST_STATIC_CONSTANT(unsigned, value = 170);
+};
+
+template <>
+inline double unchecked_factorial<double>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(double))
+{
+ return static_cast<double>(boost::math::unchecked_factorial<long double>(i));
+}
+
+template <>
+struct max_factorial<double>
+{
+ BOOST_STATIC_CONSTANT(unsigned,
+ value = ::boost::math::max_factorial<long double>::value);
+};
+
+template <class T>
+inline T unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(T))
+{
+ BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
+ // factorial<unsigned int>(n) is not implemented
+ // because it would overflow integral type T for too small n
+ // to be useful. Use instead a floating-point type,
+ // and convert to an unsigned type if essential, for example:
+ // unsigned int nfac = static_cast<unsigned int>(factorial<double>(n));
+ // See factorial documentation for more detail.
+
+ static const boost::array<T, 101> factorials = {{
+ boost::lexical_cast<T>("1"),
+ boost::lexical_cast<T>("1"),
+ boost::lexical_cast<T>("2"),
+ boost::lexical_cast<T>("6"),
+ boost::lexical_cast<T>("24"),
+ boost::lexical_cast<T>("120"),
+ boost::lexical_cast<T>("720"),
+ boost::lexical_cast<T>("5040"),
+ boost::lexical_cast<T>("40320"),
+ boost::lexical_cast<T>("362880"),
+ boost::lexical_cast<T>("3628800"),
+ boost::lexical_cast<T>("39916800"),
+ boost::lexical_cast<T>("479001600"),
+ boost::lexical_cast<T>("6227020800"),
+ boost::lexical_cast<T>("87178291200"),
+ boost::lexical_cast<T>("1307674368000"),
+ boost::lexical_cast<T>("20922789888000"),
+ boost::lexical_cast<T>("355687428096000"),
+ boost::lexical_cast<T>("6402373705728000"),
+ boost::lexical_cast<T>("121645100408832000"),
+ boost::lexical_cast<T>("2432902008176640000"),
+ boost::lexical_cast<T>("51090942171709440000"),
+ boost::lexical_cast<T>("1124000727777607680000"),
+ boost::lexical_cast<T>("25852016738884976640000"),
+ boost::lexical_cast<T>("620448401733239439360000"),
+ boost::lexical_cast<T>("15511210043330985984000000"),
+ boost::lexical_cast<T>("403291461126605635584000000"),
+ boost::lexical_cast<T>("10888869450418352160768000000"),
+ boost::lexical_cast<T>("304888344611713860501504000000"),
+ boost::lexical_cast<T>("8841761993739701954543616000000"),
+ boost::lexical_cast<T>("265252859812191058636308480000000"),
+ boost::lexical_cast<T>("8222838654177922817725562880000000"),
+ boost::lexical_cast<T>("263130836933693530167218012160000000"),
+ boost::lexical_cast<T>("8683317618811886495518194401280000000"),
+ boost::lexical_cast<T>("295232799039604140847618609643520000000"),
+ boost::lexical_cast<T>("10333147966386144929666651337523200000000"),
+ boost::lexical_cast<T>("371993326789901217467999448150835200000000"),
+ boost::lexical_cast<T>("13763753091226345046315979581580902400000000"),
+ boost::lexical_cast<T>("523022617466601111760007224100074291200000000"),
+ boost::lexical_cast<T>("20397882081197443358640281739902897356800000000"),
+ boost::lexical_cast<T>("815915283247897734345611269596115894272000000000"),
+ boost::lexical_cast<T>("33452526613163807108170062053440751665152000000000"),
+ boost::lexical_cast<T>("1405006117752879898543142606244511569936384000000000"),
+ boost::lexical_cast<T>("60415263063373835637355132068513997507264512000000000"),
+ boost::lexical_cast<T>("2658271574788448768043625811014615890319638528000000000"),
+ boost::lexical_cast<T>("119622220865480194561963161495657715064383733760000000000"),
+ boost::lexical_cast<T>("5502622159812088949850305428800254892961651752960000000000"),
+ boost::lexical_cast<T>("258623241511168180642964355153611979969197632389120000000000"),
+ boost::lexical_cast<T>("12413915592536072670862289047373375038521486354677760000000000"),
+ boost::lexical_cast<T>("608281864034267560872252163321295376887552831379210240000000000"),
+ boost::lexical_cast<T>("30414093201713378043612608166064768844377641568960512000000000000"),
+ boost::lexical_cast<T>("1551118753287382280224243016469303211063259720016986112000000000000"),
+ boost::lexical_cast<T>("80658175170943878571660636856403766975289505440883277824000000000000"),
+ boost::lexical_cast<T>("4274883284060025564298013753389399649690343788366813724672000000000000"),
+ boost::lexical_cast<T>("230843697339241380472092742683027581083278564571807941132288000000000000"),
+ boost::lexical_cast<T>("12696403353658275925965100847566516959580321051449436762275840000000000000"),
+ boost::lexical_cast<T>("710998587804863451854045647463724949736497978881168458687447040000000000000"),
+ boost::lexical_cast<T>("40526919504877216755680601905432322134980384796226602145184481280000000000000"),
+ boost::lexical_cast<T>("2350561331282878571829474910515074683828862318181142924420699914240000000000000"),
+ boost::lexical_cast<T>("138683118545689835737939019720389406345902876772687432540821294940160000000000000"),
+ boost::lexical_cast<T>("8320987112741390144276341183223364380754172606361245952449277696409600000000000000"),
+ boost::lexical_cast<T>("507580213877224798800856812176625227226004528988036003099405939480985600000000000000"),
+ boost::lexical_cast<T>("31469973260387937525653122354950764088012280797258232192163168247821107200000000000000"),
+ boost::lexical_cast<T>("1982608315404440064116146708361898137544773690227268628106279599612729753600000000000000"),
+ boost::lexical_cast<T>("126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000"),
+ boost::lexical_cast<T>("8247650592082470666723170306785496252186258551345437492922123134388955774976000000000000000"),
+ boost::lexical_cast<T>("544344939077443064003729240247842752644293064388798874532860126869671081148416000000000000000"),
+ boost::lexical_cast<T>("36471110918188685288249859096605464427167635314049524593701628500267962436943872000000000000000"),
+ boost::lexical_cast<T>("2480035542436830599600990418569171581047399201355367672371710738018221445712183296000000000000000"),
+ boost::lexical_cast<T>("171122452428141311372468338881272839092270544893520369393648040923257279754140647424000000000000000"),
+ boost::lexical_cast<T>("11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000"),
+ boost::lexical_cast<T>("850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000"),
+ boost::lexical_cast<T>("61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000"),
+ boost::lexical_cast<T>("4470115461512684340891257138125051110076800700282905015819080092370422104067183317016903680000000000000000"),
+ boost::lexical_cast<T>("330788544151938641225953028221253782145683251820934971170611926835411235700971565459250872320000000000000000"),
+ boost::lexical_cast<T>("24809140811395398091946477116594033660926243886570122837795894512655842677572867409443815424000000000000000000"),
+ boost::lexical_cast<T>("1885494701666050254987932260861146558230394535379329335672487982961844043495537923117729972224000000000000000000"),
+ boost::lexical_cast<T>("145183092028285869634070784086308284983740379224208358846781574688061991349156420080065207861248000000000000000000"),
+ boost::lexical_cast<T>("11324281178206297831457521158732046228731749579488251990048962825668835325234200766245086213177344000000000000000000"),
+ boost::lexical_cast<T>("894618213078297528685144171539831652069808216779571907213868063227837990693501860533361810841010176000000000000000000"),
+ boost::lexical_cast<T>("71569457046263802294811533723186532165584657342365752577109445058227039255480148842668944867280814080000000000000000000"),
+ boost::lexical_cast<T>("5797126020747367985879734231578109105412357244731625958745865049716390179693892056256184534249745940480000000000000000000"),
+ boost::lexical_cast<T>("475364333701284174842138206989404946643813294067993328617160934076743994734899148613007131808479167119360000000000000000000"),
+ boost::lexical_cast<T>("39455239697206586511897471180120610571436503407643446275224357528369751562996629334879591940103770870906880000000000000000000"),
+ boost::lexical_cast<T>("3314240134565353266999387579130131288000666286242049487118846032383059131291716864129885722968716753156177920000000000000000000"),
+ boost::lexical_cast<T>("281710411438055027694947944226061159480056634330574206405101912752560026159795933451040286452340924018275123200000000000000000000"),
+ boost::lexical_cast<T>("24227095383672732381765523203441259715284870552429381750838764496720162249742450276789464634901319465571660595200000000000000000000"),
+ boost::lexical_cast<T>("2107757298379527717213600518699389595229783738061356212322972511214654115727593174080683423236414793504734471782400000000000000000000"),
+ boost::lexical_cast<T>("185482642257398439114796845645546284380220968949399346684421580986889562184028199319100141244804501828416633516851200000000000000000000"),
+ boost::lexical_cast<T>("16507955160908461081216919262453619309839666236496541854913520707833171034378509739399912570787600662729080382999756800000000000000000000"),
+ boost::lexical_cast<T>("1485715964481761497309522733620825737885569961284688766942216863704985393094065876545992131370884059645617234469978112000000000000000000000"),
+ boost::lexical_cast<T>("135200152767840296255166568759495142147586866476906677791741734597153670771559994765685283954750449427751168336768008192000000000000000000000"),
+ boost::lexical_cast<T>("12438414054641307255475324325873553077577991715875414356840239582938137710983519518443046123837041347353107486982656753664000000000000000000000"),
+ boost::lexical_cast<T>("1156772507081641574759205162306240436214753229576413535186142281213246807121467315215203289516844845303838996289387078090752000000000000000000000"),
+ boost::lexical_cast<T>("108736615665674308027365285256786601004186803580182872307497374434045199869417927630229109214583415458560865651202385340530688000000000000000000000"),
+ boost::lexical_cast<T>("10329978488239059262599702099394727095397746340117372869212250571234293987594703124871765375385424468563282236864226607350415360000000000000000000000"),
+ boost::lexical_cast<T>("991677934870949689209571401541893801158183648651267795444376054838492222809091499987689476037000748982075094738965754305639874560000000000000000000000"),
+ boost::lexical_cast<T>("96192759682482119853328425949563698712343813919172976158104477319333745612481875498805879175589072651261284189679678167647067832320000000000000000000000"),
+ boost::lexical_cast<T>("9426890448883247745626185743057242473809693764078951663494238777294707070023223798882976159207729119823605850588608460429412647567360000000000000000000000"),
+ boost::lexical_cast<T>("933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000"),
+ boost::lexical_cast<T>("93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000"),
+ }};
+
+ return factorials[i];
+}
+
+template <class T>
+struct max_factorial
+{
+ BOOST_STATIC_CONSTANT(unsigned, value = 100);
+};
+
+#ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
+template <class T>
+const unsigned max_factorial<T>::value;
+#endif
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SP_UC_FACTORIALS_HPP
+
diff --git a/boost/math/special_functions/digamma.hpp b/boost/math/special_functions/digamma.hpp
new file mode 100644
index 0000000000..0dbddc77e2
--- /dev/null
+++ b/boost/math/special_functions/digamma.hpp
@@ -0,0 +1,451 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SF_DIGAMMA_HPP
+#define BOOST_MATH_SF_DIGAMMA_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/mpl/comparison.hpp>
+#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 void*)
+{ return 10; }
+//
+// Implementations of the asymptotic expansion come next,
+// the coefficients of the series have been evaluated
+// in advance at high precision, and the series truncated
+// at the first term that's too small to effect the result.
+// Note that the series becomes divergent after a while
+// so truncation is very important.
+//
+// This first one gives 34-digit precision for x >= 20:
+//
+template <class T>
+inline T digamma_imp_large(T x, const mpl::int_<0>*)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+ static const T P[] = {
+ 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;
+}
+//
+// Now follow rational approximations over the range [1,2].
+//
+// 35-digit precision:
+//
+template <class T>
+T digamma_imp_1_2(T x, const mpl::int_<0>*)
+{
+ //
+ // Now the approximation, we use the form:
+ //
+ // digamma(x) = (x - root) * (Y + R(x-1))
+ //
+ // Where root is the location of the positive root of digamma,
+ // Y is a constant, and R is optimised for low absolute error
+ // compared to Y.
+ //
+ // Max error found at 128-bit long double precision: 5.541e-35
+ // Maximum Deviation Found (approximation error): 1.965e-35
+ //
+ static const float Y = 0.99558162689208984375F;
+
+ static const T root1 = 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[] = {
+ 1,
+ 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[] = {
+ 1,
+ 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),
+ 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.25479851023250261e0,
+ -0.44981331915268368e0,
+ -0.43916936919946835e0,
+ -0.61041765350579073e-1
+ };
+ static const T Q[] = {
+ 0.1e1,
+ 0.15890202430554952e1,
+ 0.65341249856146947e0,
+ 0.63851690523355715e-1
+ };
+ T g = x - root;
+ g -= root_minor;
+ T r = tools::evaluate_polynomial(P, 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 < 0)
+ {
+ // Reflect:
+ x = 1 - x;
+ // Argument reduction for tan:
+ T remainder = x - floor(x);
+ // Shift to negative if > 0.5:
+ if(remainder > 0.5)
+ {
+ remainder -= 1;
+ }
+ //
+ // check for evaluation at a negative pole:
+ //
+ if(remainder == 0)
+ {
+ return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", 0, (1-x), pol);
+ }
+ result = constants::pi<T>() / tan(constants::pi<T>() * remainder);
+ }
+ //
+ // If we're above the lower-limit for the
+ // asymptotic expansion then use it:
+ //
+ if(x >= digamma_large_lim(t))
+ {
+ result += digamma_imp_large(x, t);
+ }
+ else
+ {
+ //
+ // If x > 2 reduce to the interval [1,2]:
+ //
+ while(x > 2)
+ {
+ x -= 1;
+ result += 1/x;
+ }
+ //
+ // If x < 1 use recurrance to shift to > 1:
+ //
+ if(x < 1)
+ {
+ result = -1/x;
+ x += 1;
+ }
+ result += digamma_imp_1_2(x, t);
+ }
+ return result;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ digamma(T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::precision<T, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::or_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::greater<precision_type, mpl::int_<64> >
+ >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less<precision_type, mpl::int_<25> >,
+ mpl::int_<24>,
+ typename mpl::if_<
+ mpl::less<precision_type, mpl::int_<54> >,
+ mpl::int_<53>,
+ mpl::int_<64>
+ >::type
+ >::type
+ >::type tag_type;
+
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::digamma_imp(
+ static_cast<value_type>(x),
+ static_cast<const tag_type*>(0), pol), "boost::math::digamma<%1%>(%1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ digamma(T x)
+{
+ return digamma(x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+#endif
+
diff --git a/boost/math/special_functions/ellint_1.hpp b/boost/math/special_functions/ellint_1.hpp
new file mode 100644
index 0000000000..469f4bd01a
--- /dev/null
+++ b/boost/math/special_functions/ellint_1.hpp
@@ -0,0 +1,187 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Copyright (c) 2006 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// History:
+// XZ wrote the original of this file as part of the Google
+// Summer of Code 2006. JM modified it to fit into the
+// Boost.Math conceptual framework better, and to ensure
+// that the code continues to work no matter how many digits
+// type T has.
+
+#ifndef BOOST_MATH_ELLINT_1_HPP
+#define BOOST_MATH_ELLINT_1_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/ellint_rf.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/tools/workaround.hpp>
+
+// Elliptic integrals (complete and incomplete) of the first kind
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math {
+
+template <class T1, class T2, class Policy>
+typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const Policy& pol);
+
+namespace detail{
+
+template <typename T, typename Policy>
+T ellint_k_imp(T k, const Policy& pol);
+
+// Elliptic integral (Legendre form) of the first kind
+template <typename T, typename Policy>
+T ellint_f_imp(T phi, T k, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ static const char* function = "boost::math::ellint_f<%1%>(%1%,%1%)";
+ BOOST_MATH_INSTRUMENT_VARIABLE(phi);
+ BOOST_MATH_INSTRUMENT_VARIABLE(k);
+ BOOST_MATH_INSTRUMENT_VARIABLE(function);
+
+ if (abs(k) > 1)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got k = %1%, function requires |k| <= 1", k, pol);
+ }
+
+ bool invert = false;
+ if(phi < 0)
+ {
+ BOOST_MATH_INSTRUMENT_VARIABLE(phi);
+ phi = fabs(phi);
+ invert = true;
+ }
+
+ T result;
+
+ if(phi >= tools::max_value<T>())
+ {
+ // Need to handle infinity as a special case:
+ result = policies::raise_overflow_error<T>(function, 0, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else if(phi > 1 / tools::epsilon<T>())
+ {
+ // Phi is so large that phi%pi is necessarily zero (or garbage),
+ // just return the second part of the duplication formula:
+ result = 2 * phi * ellint_k_imp(k, pol) / constants::pi<T>();
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ // Carlson's algorithm works only for |phi| <= pi/2,
+ // use the integrand's periodicity to normalize phi
+ //
+ // Xiaogang's original code used a cast to long long here
+ // but that fails if T has more digits than a long long,
+ // so rewritten to use fmod instead:
+ //
+ BOOST_MATH_INSTRUMENT_CODE("pi/2 = " << constants::pi<T>() / 2);
+ T rphi = boost::math::tools::fmod_workaround(phi, T(constants::pi<T>() / 2));
+ BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
+ T m = floor((2 * phi) / constants::pi<T>());
+ BOOST_MATH_INSTRUMENT_VARIABLE(m);
+ int s = 1;
+ if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
+ {
+ m += 1;
+ s = -1;
+ rphi = constants::pi<T>() / 2 - rphi;
+ BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
+ }
+ T sinp = sin(rphi);
+ T cosp = cos(rphi);
+ BOOST_MATH_INSTRUMENT_VARIABLE(sinp);
+ BOOST_MATH_INSTRUMENT_VARIABLE(cosp);
+ result = s * sinp * ellint_rf_imp(T(cosp * cosp), T(1 - k * k * sinp * sinp), T(1), pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ if(m != 0)
+ {
+ result += m * ellint_k_imp(k, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ }
+ return invert ? T(-result) : result;
+}
+
+// Complete elliptic integral (Legendre form) of the first kind
+template <typename T, typename Policy>
+T ellint_k_imp(T k, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::ellint_k<%1%>(%1%)";
+
+ if (abs(k) > 1)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got k = %1%, function requires |k| <= 1", k, pol);
+ }
+ if (abs(k) == 1)
+ {
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+
+ T x = 0;
+ T y = 1 - k * k;
+ T z = 1;
+ T value = ellint_rf_imp(x, y, z, pol);
+
+ return value;
+}
+
+template <typename T, typename Policy>
+inline typename tools::promote_args<T>::type ellint_1(T k, const Policy& pol, const mpl::true_&)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_k_imp(static_cast<value_type>(k), pol), "boost::math::ellint_1<%1%>(%1%)");
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const mpl::false_&)
+{
+ return boost::math::ellint_1(k, phi, policies::policy<>());
+}
+
+}
+
+// Complete elliptic integral (Legendre form) of the first kind
+template <typename T>
+inline typename tools::promote_args<T>::type ellint_1(T k)
+{
+ return ellint_1(k, policies::policy<>());
+}
+
+// Elliptic integral (Legendre form) of the first kind
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_f_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_1<%1%>(%1%,%1%)");
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi)
+{
+ typedef typename policies::is_policy<T2>::type tag_type;
+ return detail::ellint_1(k, phi, tag_type());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ELLINT_1_HPP
+
diff --git a/boost/math/special_functions/ellint_2.hpp b/boost/math/special_functions/ellint_2.hpp
new file mode 100644
index 0000000000..85eca6cde7
--- /dev/null
+++ b/boost/math/special_functions/ellint_2.hpp
@@ -0,0 +1,168 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Copyright (c) 2006 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// History:
+// XZ wrote the original of this file as part of the Google
+// Summer of Code 2006. JM modified it to fit into the
+// Boost.Math conceptual framework better, and to ensure
+// that the code continues to work no matter how many digits
+// type T has.
+
+#ifndef BOOST_MATH_ELLINT_2_HPP
+#define BOOST_MATH_ELLINT_2_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/ellint_rf.hpp>
+#include <boost/math/special_functions/ellint_rd.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/tools/workaround.hpp>
+
+// Elliptic integrals (complete and incomplete) of the second kind
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math {
+
+template <class T1, class T2, class Policy>
+typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol);
+
+namespace detail{
+
+template <typename T, typename Policy>
+T ellint_e_imp(T k, const Policy& pol);
+
+// Elliptic integral (Legendre form) of the second kind
+template <typename T, typename Policy>
+T ellint_e_imp(T phi, T k, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ bool invert = false;
+ if(phi < 0)
+ {
+ phi = fabs(phi);
+ invert = true;
+ }
+
+ T result;
+
+ if(phi >= tools::max_value<T>())
+ {
+ // Need to handle infinity as a special case:
+ result = policies::raise_overflow_error<T>("boost::math::ellint_e<%1%>(%1%,%1%)", 0, pol);
+ }
+ else if(phi > 1 / tools::epsilon<T>())
+ {
+ // Phi is so large that phi%pi is necessarily zero (or garbage),
+ // just return the second part of the duplication formula:
+ result = 2 * phi * ellint_e_imp(k, pol) / constants::pi<T>();
+ }
+ else
+ {
+ // Carlson's algorithm works only for |phi| <= pi/2,
+ // use the integrand's periodicity to normalize phi
+ //
+ // Xiaogang's original code used a cast to long long here
+ // but that fails if T has more digits than a long long,
+ // so rewritten to use fmod instead:
+ //
+ T rphi = boost::math::tools::fmod_workaround(phi, T(constants::pi<T>() / 2));
+ T m = floor((2 * phi) / constants::pi<T>());
+ int s = 1;
+ if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
+ {
+ m += 1;
+ s = -1;
+ rphi = constants::pi<T>() / 2 - rphi;
+ }
+ T sinp = sin(rphi);
+ T cosp = cos(rphi);
+ T x = cosp * cosp;
+ T t = k * k * sinp * sinp;
+ T y = 1 - t;
+ T z = 1;
+ result = s * sinp * (ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3);
+ if(m != 0)
+ result += m * ellint_e_imp(k, pol);
+ }
+ return invert ? T(-result) : result;
+}
+
+// Complete elliptic integral (Legendre form) of the second kind
+template <typename T, typename Policy>
+T ellint_e_imp(T k, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ if (abs(k) > 1)
+ {
+ return policies::raise_domain_error<T>("boost::math::ellint_e<%1%>(%1%)",
+ "Got k = %1%, function requires |k| <= 1", k, pol);
+ }
+ if (abs(k) == 1)
+ {
+ return static_cast<T>(1);
+ }
+
+ T x = 0;
+ T t = k * k;
+ T y = 1 - t;
+ T z = 1;
+ T value = ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3;
+
+ return value;
+}
+
+template <typename T, typename Policy>
+inline typename tools::promote_args<T>::type ellint_2(T k, const Policy& pol, const mpl::true_&)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%)");
+}
+
+// Elliptic integral (Legendre form) of the second kind
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const mpl::false_&)
+{
+ return boost::math::ellint_2(k, phi, policies::policy<>());
+}
+
+} // detail
+
+// Complete elliptic integral (Legendre form) of the second kind
+template <typename T>
+inline typename tools::promote_args<T>::type ellint_2(T k)
+{
+ return ellint_2(k, policies::policy<>());
+}
+
+// Elliptic integral (Legendre form) of the second kind
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi)
+{
+ typedef typename policies::is_policy<T2>::type tag_type;
+ return detail::ellint_2(k, phi, tag_type());
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%,%1%)");
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ELLINT_2_HPP
+
diff --git a/boost/math/special_functions/ellint_3.hpp b/boost/math/special_functions/ellint_3.hpp
new file mode 100644
index 0000000000..f63bb2d4b0
--- /dev/null
+++ b/boost/math/special_functions/ellint_3.hpp
@@ -0,0 +1,318 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Copyright (c) 2006 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// History:
+// XZ wrote the original of this file as part of the Google
+// Summer of Code 2006. JM modified it to fit into the
+// Boost.Math conceptual framework better, and to correctly
+// handle the various corner cases.
+//
+
+#ifndef BOOST_MATH_ELLINT_3_HPP
+#define BOOST_MATH_ELLINT_3_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/ellint_rf.hpp>
+#include <boost/math/special_functions/ellint_rj.hpp>
+#include <boost/math/special_functions/ellint_1.hpp>
+#include <boost/math/special_functions/ellint_2.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/tools/workaround.hpp>
+
+// Elliptic integrals (complete and incomplete) of the third kind
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math {
+
+namespace detail{
+
+template <typename T, typename Policy>
+T ellint_pi_imp(T v, T k, T vc, const Policy& pol);
+
+// Elliptic integral (Legendre form) of the third kind
+template <typename T, typename Policy>
+T ellint_pi_imp(T v, T phi, T k, T vc, const Policy& pol)
+{
+ // Note vc = 1-v presumably without cancellation error.
+ T value, x, y, z, p, t;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ static const char* function = "boost::math::ellint_3<%1%>(%1%,%1%,%1%)";
+
+ if (abs(k) > 1)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got k = %1%, function requires |k| <= 1", k, pol);
+ }
+
+ T sphi = sin(fabs(phi));
+
+ if(v > 1 / (sphi * sphi))
+ {
+ // Complex result is a domain error:
+ return policies::raise_domain_error<T>(function,
+ "Got v = %1%, but result is complex for v > 1 / sin^2(phi)", v, pol);
+ }
+
+ // Special cases first:
+ if(v == 0)
+ {
+ // A&S 17.7.18 & 19
+ return (k == 0) ? phi : ellint_f_imp(phi, k, pol);
+ }
+ if(phi == constants::pi<T>() / 2)
+ {
+ // Have to filter this case out before the next
+ // special case, otherwise we might get an infinity from
+ // tan(phi).
+ // Also note that since we can't represent PI/2 exactly
+ // in a T, this is a bit of a guess as to the users true
+ // intent...
+ //
+ return ellint_pi_imp(v, k, vc, pol);
+ }
+ if(k == 0)
+ {
+ // A&S 17.7.20:
+ if(v < 1)
+ {
+ T vcr = sqrt(vc);
+ return atan(vcr * tan(phi)) / vcr;
+ }
+ else if(v == 1)
+ {
+ return tan(phi);
+ }
+ else
+ {
+ // v > 1:
+ T vcr = sqrt(-vc);
+ T arg = vcr * tan(phi);
+ return (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * vcr);
+ }
+ }
+
+ if(v < 0)
+ {
+ //
+ // If we don't shift to 0 <= v <= 1 we get
+ // cancellation errors later on. Use
+ // A&S 17.7.15/16 to shift to v > 0:
+ //
+ T k2 = k * k;
+ T N = (k2 - v) / (1 - v);
+ T Nm1 = (1 - k2) / (1 - v);
+ T p2 = sqrt(-v * (k2 - v) / (1 - v));
+ T delta = sqrt(1 - k2 * sphi * sphi);
+ T result = ellint_pi_imp(N, phi, k, Nm1, pol);
+
+ result *= sqrt(Nm1 * (1 - k2 / N));
+ result += ellint_f_imp(phi, k, pol) * k2 / p2;
+ result += atan((p2/2) * sin(2 * phi) / delta);
+ result /= sqrt((1 - v) * (1 - k2 / v));
+ return result;
+ }
+#if 0 // disabled but retained for future reference: see below.
+ if(v > 1)
+ {
+ //
+ // If v > 1 we can use the identity in A&S 17.7.7/8
+ // to shift to 0 <= v <= 1. Unfortunately this
+ // identity appears only to function correctly when
+ // 0 <= phi <= pi/2, but it's when phi is outside that
+ // range that we really need it: That's when
+ // Carlson's formula fails, and what's more the periodicity
+ // reduction used below on phi doesn't work when v > 1.
+ //
+ // So we're stuck... the code is archived here in case
+ // some bright spart can figure out the fix.
+ //
+ T k2 = k * k;
+ T N = k2 / v;
+ T Nm1 = (v - k2) / v;
+ T p1 = sqrt((-vc) * (1 - k2 / v));
+ T delta = sqrt(1 - k2 * sphi * sphi);
+ //
+ // These next two terms have a large amount of cancellation
+ // so it's not clear if this relation is useable even if
+ // the issues with phi > pi/2 can be fixed:
+ //
+ T result = -ellint_pi_imp(N, phi, k, Nm1);
+ result += ellint_f_imp(phi, k);
+ //
+ // This log term gives the complex result when
+ // n > 1/sin^2(phi)
+ // However that case is dealt with as an error above,
+ // so we should always get a real result here:
+ //
+ result += log((delta + p1 * tan(phi)) / (delta - p1 * tan(phi))) / (2 * p1);
+ return result;
+ }
+#endif
+
+ // Carlson's algorithm works only for |phi| <= pi/2,
+ // use the integrand's periodicity to normalize phi
+ //
+ // Xiaogang's original code used a cast to long long here
+ // but that fails if T has more digits than a long long,
+ // so rewritten to use fmod instead:
+ //
+ if(fabs(phi) > 1 / tools::epsilon<T>())
+ {
+ if(v > 1)
+ return policies::raise_domain_error<T>(
+ function,
+ "Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol);
+ //
+ // Phi is so large that phi%pi is necessarily zero (or garbage),
+ // just return the second part of the duplication formula:
+ //
+ value = 2 * fabs(phi) * ellint_pi_imp(v, k, vc, pol) / constants::pi<T>();
+ }
+ else
+ {
+ T rphi = boost::math::tools::fmod_workaround(T(fabs(phi)), T(constants::pi<T>() / 2));
+ T m = floor((2 * fabs(phi)) / constants::pi<T>());
+ int sign = 1;
+ if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
+ {
+ m += 1;
+ sign = -1;
+ rphi = constants::pi<T>() / 2 - rphi;
+ }
+ T sinp = sin(rphi);
+ T cosp = cos(rphi);
+ x = cosp * cosp;
+ t = sinp * sinp;
+ y = 1 - k * k * t;
+ z = 1;
+ if(v * t < 0.5)
+ p = 1 - v * t;
+ else
+ p = x + vc * t;
+ value = sign * sinp * (ellint_rf_imp(x, y, z, pol) + v * t * ellint_rj_imp(x, y, z, p, pol) / 3);
+ if((m > 0) && (vc > 0))
+ value += m * ellint_pi_imp(v, k, vc, pol);
+ }
+
+ if (phi < 0)
+ {
+ value = -value; // odd function
+ }
+ return value;
+}
+
+// Complete elliptic integral (Legendre form) of the third kind
+template <typename T, typename Policy>
+T ellint_pi_imp(T v, T k, T vc, const Policy& pol)
+{
+ // Note arg vc = 1-v, possibly without cancellation errors
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::ellint_pi<%1%>(%1%,%1%)";
+
+ if (abs(k) >= 1)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got k = %1%, function requires |k| <= 1", k, pol);
+ }
+ if(vc <= 0)
+ {
+ // Result is complex:
+ return policies::raise_domain_error<T>(function,
+ "Got v = %1%, function requires v < 1", v, pol);
+ }
+
+ if(v == 0)
+ {
+ return (k == 0) ? boost::math::constants::pi<T>() / 2 : ellint_k_imp(k, pol);
+ }
+
+ if(v < 0)
+ {
+ T k2 = k * k;
+ T N = (k2 - v) / (1 - v);
+ T Nm1 = (1 - k2) / (1 - v);
+ T p2 = sqrt(-v * (k2 - v) / (1 - v));
+
+ T result = boost::math::detail::ellint_pi_imp(N, k, Nm1, pol);
+
+ result *= sqrt(Nm1 * (1 - k2 / N));
+ result += ellint_k_imp(k, pol) * k2 / p2;
+ result /= sqrt((1 - v) * (1 - k2 / v));
+ return result;
+ }
+
+ T x = 0;
+ T y = 1 - k * k;
+ T z = 1;
+ T p = vc;
+ T value = ellint_rf_imp(x, y, z, pol) + v * ellint_rj_imp(x, y, z, p, pol) / 3;
+
+ return value;
+}
+
+template <class T1, class T2, class T3>
+inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const mpl::false_&)
+{
+ return boost::math::ellint_3(k, v, phi, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v, const Policy& pol, const mpl::true_&)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(
+ detail::ellint_pi_imp(
+ static_cast<value_type>(v),
+ static_cast<value_type>(k),
+ static_cast<value_type>(1-v),
+ pol), "boost::math::ellint_3<%1%>(%1%,%1%)");
+}
+
+} // namespace detail
+
+template <class T1, class T2, class T3, class Policy>
+inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2, T3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(
+ detail::ellint_pi_imp(
+ static_cast<value_type>(v),
+ static_cast<value_type>(phi),
+ static_cast<value_type>(k),
+ static_cast<value_type>(1-v),
+ pol), "boost::math::ellint_3<%1%>(%1%,%1%,%1%)");
+}
+
+template <class T1, class T2, class T3>
+typename detail::ellint_3_result<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi)
+{
+ typedef typename policies::is_policy<T3>::type tag_type;
+ return detail::ellint_3(k, v, phi, tag_type());
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v)
+{
+ return ellint_3(k, v, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ELLINT_3_HPP
+
diff --git a/boost/math/special_functions/ellint_rc.hpp b/boost/math/special_functions/ellint_rc.hpp
new file mode 100644
index 0000000000..5f6d5c64bc
--- /dev/null
+++ b/boost/math/special_functions/ellint_rc.hpp
@@ -0,0 +1,115 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// History:
+// XZ wrote the original of this file as part of the Google
+// Summer of Code 2006. JM modified it to fit into the
+// Boost.Math conceptual framework better, and to correctly
+// handle the y < 0 case.
+//
+
+#ifndef BOOST_MATH_ELLINT_RC_HPP
+#define BOOST_MATH_ELLINT_RC_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+
+// Carlson's degenerate elliptic integral
+// R_C(x, y) = R_F(x, y, y) = 0.5 * \int_{0}^{\infty} (t+x)^{-1/2} (t+y)^{-1} dt
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T ellint_rc_imp(T x, T y, const Policy& pol)
+{
+ T value, S, u, lambda, tolerance, prefix;
+ unsigned long k;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::ellint_rc<%1%>(%1%,%1%)";
+
+ if(x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument x must be non-negative but got %1%", x, pol);
+ }
+ if(y == 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument y must not be zero but got %1%", y, pol);
+ }
+
+ // error scales as the 6th power of tolerance
+ tolerance = pow(4 * tools::epsilon<T>(), T(1) / 6);
+
+ // for y < 0, the integral is singular, return Cauchy principal value
+ if (y < 0)
+ {
+ prefix = sqrt(x / (x - y));
+ x = x - y;
+ y = -y;
+ }
+ else
+ prefix = 1;
+
+ // duplication:
+ k = 1;
+ do
+ {
+ u = (x + y + y) / 3;
+ S = y / u - 1; // 1 - x / u = 2 * S
+
+ if (2 * abs(S) < tolerance)
+ break;
+
+ T sx = sqrt(x);
+ T sy = sqrt(y);
+ lambda = 2 * sx * sy + y;
+ x = (x + lambda) / 4;
+ y = (y + lambda) / 4;
+ ++k;
+ }while(k < policies::get_max_series_iterations<Policy>());
+ // Check to see if we gave up too soon:
+ policies::check_series_iterations<T>(function, k, pol);
+
+ // Taylor series expansion to the 5th order
+ value = (1 + S * S * (T(3) / 10 + S * (T(1) / 7 + S * (T(3) / 8 + S * T(9) / 22)))) / sqrt(u);
+
+ return value * prefix;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ ellint_rc(T1 x, T2 y, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(
+ detail::ellint_rc_imp(
+ static_cast<value_type>(x),
+ static_cast<value_type>(y), pol), "boost::math::ellint_rc<%1%>(%1%,%1%)");
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ ellint_rc(T1 x, T2 y)
+{
+ return ellint_rc(x, y, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ELLINT_RC_HPP
+
diff --git a/boost/math/special_functions/ellint_rd.hpp b/boost/math/special_functions/ellint_rd.hpp
new file mode 100644
index 0000000000..61014d3866
--- /dev/null
+++ b/boost/math/special_functions/ellint_rd.hpp
@@ -0,0 +1,130 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// History:
+// XZ wrote the original of this file as part of the Google
+// Summer of Code 2006. JM modified it slightly to fit into the
+// Boost.Math conceptual framework better.
+
+#ifndef BOOST_MATH_ELLINT_RD_HPP
+#define BOOST_MATH_ELLINT_RD_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/policies/error_handling.hpp>
+
+// Carlson's elliptic integral of the second kind
+// R_D(x, y, z) = R_J(x, y, z, z) = 1.5 * \int_{0}^{\infty} [(t+x)(t+y)]^{-1/2} (t+z)^{-3/2} dt
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T ellint_rd_imp(T x, T y, T z, const Policy& pol)
+{
+ T value, u, lambda, sigma, factor, tolerance;
+ T X, Y, Z, EA, EB, EC, ED, EE, S1, S2;
+ unsigned long k;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument x must be >= 0, but got %1%", x, pol);
+ }
+ if (y < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument y must be >= 0, but got %1%", y, pol);
+ }
+ if (z <= 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument z must be > 0, but got %1%", z, pol);
+ }
+ if (x + y == 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "At most one argument can be zero, but got, x + y = %1%", x+y, pol);
+ }
+
+ // error scales as the 6th power of tolerance
+ tolerance = pow(tools::epsilon<T>() / 3, T(1)/6);
+
+ // duplication
+ sigma = 0;
+ factor = 1;
+ k = 1;
+ do
+ {
+ u = (x + y + z + z + z) / 5;
+ X = (u - x) / u;
+ Y = (u - y) / u;
+ Z = (u - z) / u;
+ if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
+ break;
+ T sx = sqrt(x);
+ T sy = sqrt(y);
+ T sz = sqrt(z);
+ lambda = sy * (sx + sz) + sz * sx; //sqrt(x * y) + sqrt(y * z) + sqrt(z * x);
+ sigma += factor / (sz * (z + lambda));
+ factor /= 4;
+ x = (x + lambda) / 4;
+ y = (y + lambda) / 4;
+ z = (z + lambda) / 4;
+ ++k;
+ }
+ while(k < policies::get_max_series_iterations<Policy>());
+
+ // Check to see if we gave up too soon:
+ policies::check_series_iterations<T>(function, k, pol);
+
+ // Taylor series expansion to the 5th order
+ EA = X * Y;
+ EB = Z * Z;
+ EC = EA - EB;
+ ED = EA - 6 * EB;
+ EE = ED + EC + EC;
+ S1 = ED * (ED * T(9) / 88 - Z * EE * T(9) / 52 - T(3) / 14);
+ S2 = Z * (EE / 6 + Z * (-EC * T(9) / 22 + Z * EA * T(3) / 26));
+ value = 3 * sigma + factor * (1 + S1 + S2) / (u * sqrt(u));
+
+ return value;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class T3, class Policy>
+inline typename tools::promote_args<T1, T2, T3>::type
+ ellint_rd(T1 x, T2 y, T3 z, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2, T3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(
+ detail::ellint_rd_imp(
+ static_cast<value_type>(x),
+ static_cast<value_type>(y),
+ static_cast<value_type>(z), pol), "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)");
+}
+
+template <class T1, class T2, class T3>
+inline typename tools::promote_args<T1, T2, T3>::type
+ ellint_rd(T1 x, T2 y, T3 z)
+{
+ return ellint_rd(x, y, z, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ELLINT_RD_HPP
+
diff --git a/boost/math/special_functions/ellint_rf.hpp b/boost/math/special_functions/ellint_rf.hpp
new file mode 100644
index 0000000000..ac5725783a
--- /dev/null
+++ b/boost/math/special_functions/ellint_rf.hpp
@@ -0,0 +1,132 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// History:
+// XZ wrote the original of this file as part of the Google
+// Summer of Code 2006. JM modified it to fit into the
+// Boost.Math conceptual framework better, and to handle
+// types longer than 80-bit reals.
+//
+#ifndef BOOST_MATH_ELLINT_RF_HPP
+#define BOOST_MATH_ELLINT_RF_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/tools/config.hpp>
+
+#include <boost/math/policies/error_handling.hpp>
+
+// Carlson's elliptic integral of the first kind
+// R_F(x, y, z) = 0.5 * \int_{0}^{\infty} [(t+x)(t+y)(t+z)]^{-1/2} dt
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T ellint_rf_imp(T x, T y, T z, const Policy& pol)
+{
+ T value, X, Y, Z, E2, E3, u, lambda, tolerance;
+ unsigned long k;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)";
+
+ if (x < 0 || y < 0 || z < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "domain error, all arguments must be non-negative, "
+ "only sensible result is %1%.",
+ std::numeric_limits<T>::quiet_NaN(), pol);
+ }
+ if (x + y == 0 || y + z == 0 || z + x == 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "domain error, at most one argument can be zero, "
+ "only sensible result is %1%.",
+ std::numeric_limits<T>::quiet_NaN(), pol);
+ }
+
+ // Carlson scales error as the 6th power of tolerance,
+ // but this seems not to work for types larger than
+ // 80-bit reals, this heuristic seems to work OK:
+ if(policies::digits<T, Policy>() > 64)
+ {
+ tolerance = pow(tools::epsilon<T>(), T(1)/4.25f);
+ BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
+ }
+ else
+ {
+ tolerance = pow(4*tools::epsilon<T>(), T(1)/6);
+ BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
+ }
+
+ // duplication
+ k = 1;
+ do
+ {
+ u = (x + y + z) / 3;
+ X = (u - x) / u;
+ Y = (u - y) / u;
+ Z = (u - z) / u;
+
+ // Termination condition:
+ if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
+ break;
+
+ T sx = sqrt(x);
+ T sy = sqrt(y);
+ T sz = sqrt(z);
+ lambda = sy * (sx + sz) + sz * sx;
+ x = (x + lambda) / 4;
+ y = (y + lambda) / 4;
+ z = (z + lambda) / 4;
+ ++k;
+ }
+ while(k < policies::get_max_series_iterations<Policy>());
+
+ // Check to see if we gave up too soon:
+ policies::check_series_iterations<T>(function, k, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(k);
+
+ // Taylor series expansion to the 5th order
+ E2 = X * Y - Z * Z;
+ E3 = X * Y * Z;
+ value = (1 + E2*(E2/24 - E3*T(3)/44 - T(0.1)) + E3/14) / sqrt(u);
+ BOOST_MATH_INSTRUMENT_VARIABLE(value);
+
+ return value;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class T3, class Policy>
+inline typename tools::promote_args<T1, T2, T3>::type
+ ellint_rf(T1 x, T2 y, T3 z, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2, T3>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(
+ detail::ellint_rf_imp(
+ static_cast<value_type>(x),
+ static_cast<value_type>(y),
+ static_cast<value_type>(z), pol), "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)");
+}
+
+template <class T1, class T2, class T3>
+inline typename tools::promote_args<T1, T2, T3>::type
+ ellint_rf(T1 x, T2 y, T3 z)
+{
+ return ellint_rf(x, y, z, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ELLINT_RF_HPP
+
diff --git a/boost/math/special_functions/ellint_rj.hpp b/boost/math/special_functions/ellint_rj.hpp
new file mode 100644
index 0000000000..1ecca753a4
--- /dev/null
+++ b/boost/math/special_functions/ellint_rj.hpp
@@ -0,0 +1,180 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// History:
+// XZ wrote the original of this file as part of the Google
+// Summer of Code 2006. JM modified it to fit into the
+// Boost.Math conceptual framework better, and to correctly
+// handle the p < 0 case.
+//
+
+#ifndef BOOST_MATH_ELLINT_RJ_HPP
+#define BOOST_MATH_ELLINT_RJ_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/ellint_rc.hpp>
+#include <boost/math/special_functions/ellint_rf.hpp>
+
+// Carlson's elliptic integral of the third kind
+// R_J(x, y, z, p) = 1.5 * \int_{0}^{\infty} (t+p)^{-1} [(t+x)(t+y)(t+z)]^{-1/2} dt
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
+{
+ T value, u, lambda, alpha, beta, sigma, factor, tolerance;
+ T X, Y, Z, P, EA, EB, EC, E2, E3, S1, S2, S3;
+ unsigned long k;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::ellint_rj<%1%>(%1%,%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument x must be non-negative, but got x = %1%", x, pol);
+ }
+ if(y < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument y must be non-negative, but got y = %1%", y, pol);
+ }
+ if(z < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument z must be non-negative, but got z = %1%", z, pol);
+ }
+ if(p == 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Argument p must not be zero, but got p = %1%", p, pol);
+ }
+ if (x + y == 0 || y + z == 0 || z + x == 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "At most one argument can be zero, "
+ "only possible result is %1%.", std::numeric_limits<T>::quiet_NaN(), pol);
+ }
+
+ // error scales as the 6th power of tolerance
+ tolerance = pow(T(1) * tools::epsilon<T>() / 3, T(1) / 6);
+
+ // for p < 0, the integral is singular, return Cauchy principal value
+ if (p < 0)
+ {
+ //
+ // We must ensure that (z - y) * (y - x) is positive.
+ // Since the integral is symmetrical in x, y and z
+ // we can just permute the values:
+ //
+ if(x > y)
+ std::swap(x, y);
+ if(y > z)
+ std::swap(y, z);
+ if(x > y)
+ std::swap(x, y);
+
+ T q = -p;
+ T pmy = (z - y) * (y - x) / (y + q); // p - y
+
+ BOOST_ASSERT(pmy >= 0);
+
+ T p = pmy + y;
+ value = boost::math::ellint_rj(x, y, z, p, pol);
+ value *= pmy;
+ value -= 3 * boost::math::ellint_rf(x, y, z, pol);
+ value += 3 * sqrt((x * y * z) / (x * z + p * q)) * boost::math::ellint_rc(x * z + p * q, p * q, pol);
+ value /= (y + q);
+ return value;
+ }
+
+ // duplication
+ sigma = 0;
+ factor = 1;
+ k = 1;
+ do
+ {
+ u = (x + y + z + p + p) / 5;
+ X = (u - x) / u;
+ Y = (u - y) / u;
+ Z = (u - z) / u;
+ P = (u - p) / u;
+
+ if ((tools::max)(abs(X), abs(Y), abs(Z), abs(P)) < tolerance)
+ break;
+
+ T sx = sqrt(x);
+ T sy = sqrt(y);
+ T sz = sqrt(z);
+
+ lambda = sy * (sx + sz) + sz * sx;
+ alpha = p * (sx + sy + sz) + sx * sy * sz;
+ alpha *= alpha;
+ beta = p * (p + lambda) * (p + lambda);
+ sigma += factor * boost::math::ellint_rc(alpha, beta, pol);
+ factor /= 4;
+ x = (x + lambda) / 4;
+ y = (y + lambda) / 4;
+ z = (z + lambda) / 4;
+ p = (p + lambda) / 4;
+ ++k;
+ }
+ while(k < policies::get_max_series_iterations<Policy>());
+
+ // Check to see if we gave up too soon:
+ policies::check_series_iterations<T>(function, k, pol);
+
+ // Taylor series expansion to the 5th order
+ EA = X * Y + Y * Z + Z * X;
+ EB = X * Y * Z;
+ EC = P * P;
+ E2 = EA - 3 * EC;
+ E3 = EB + 2 * P * (EA - EC);
+ S1 = 1 + E2 * (E2 * T(9) / 88 - E3 * T(9) / 52 - T(3) / 14);
+ S2 = EB * (T(1) / 6 + P * (T(-6) / 22 + P * T(3) / 26));
+ S3 = P * ((EA - EC) / 3 - P * EA * T(3) / 22);
+ value = 3 * sigma + factor * (S1 + S2 + S3) / (u * sqrt(u));
+
+ return value;
+}
+
+} // namespace detail
+
+template <class T1, class T2, class T3, class T4, class Policy>
+inline typename tools::promote_args<T1, T2, T3, T4>::type
+ ellint_rj(T1 x, T2 y, T3 z, T4 p, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(
+ detail::ellint_rj_imp(
+ static_cast<value_type>(x),
+ static_cast<value_type>(y),
+ static_cast<value_type>(z),
+ static_cast<value_type>(p),
+ pol), "boost::math::ellint_rj<%1%>(%1%,%1%,%1%,%1%)");
+}
+
+template <class T1, class T2, class T3, class T4>
+inline typename tools::promote_args<T1, T2, T3, T4>::type
+ ellint_rj(T1 x, T2 y, T3 z, T4 p)
+{
+ return ellint_rj(x, y, z, p, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ELLINT_RJ_HPP
+
diff --git a/boost/math/special_functions/erf.hpp b/boost/math/special_functions/erf.hpp
new file mode 100644
index 0000000000..1abb59177f
--- /dev/null
+++ b/boost/math/special_functions/erf.hpp
@@ -0,0 +1,1092 @@
+// (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_ERF_HPP
+#define BOOST_MATH_SPECIAL_ERF_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/gamma.hpp>
+#include <boost/math/tools/roots.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/tools/big_constant.hpp>
+
+namespace boost{ namespace math{
+
+namespace detail
+{
+
+//
+// Asymptotic series for large z:
+//
+template <class T>
+struct erf_asympt_series_t
+{
+ erf_asympt_series_t(T z) : xx(2 * -z * z), tk(1)
+ {
+ BOOST_MATH_STD_USING
+ result = -exp(-z * z) / sqrt(boost::math::constants::pi<T>());
+ result /= z;
+ }
+
+ typedef T result_type;
+
+ T operator()()
+ {
+ BOOST_MATH_STD_USING
+ T r = result;
+ result *= tk / xx;
+ tk += 2;
+ if( fabs(r) < fabs(result))
+ result = 0;
+ return r;
+ }
+private:
+ T result;
+ T xx;
+ int tk;
+};
+//
+// How large z has to be in order to ensure that the series converges:
+//
+template <class T>
+inline float erf_asymptotic_limit_N(const T&)
+{
+ return (std::numeric_limits<float>::max)();
+}
+inline float erf_asymptotic_limit_N(const mpl::int_<24>&)
+{
+ return 2.8F;
+}
+inline float erf_asymptotic_limit_N(const mpl::int_<53>&)
+{
+ return 4.3F;
+}
+inline float erf_asymptotic_limit_N(const mpl::int_<64>&)
+{
+ return 4.8F;
+}
+inline float erf_asymptotic_limit_N(const mpl::int_<106>&)
+{
+ return 6.5F;
+}
+inline float erf_asymptotic_limit_N(const mpl::int_<113>&)
+{
+ return 6.8F;
+}
+
+template <class T, class Policy>
+inline T erf_asymptotic_limit()
+{
+ typedef typename policies::precision<T, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<24> >,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<0>,
+ mpl::int_<24>
+ >::type,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<106> >,
+ mpl::int_<106>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<113>,
+ mpl::int_<0>
+ >::type
+ >::type
+ >::type
+ >::type
+ >::type tag_type;
+ return erf_asymptotic_limit_N(tag_type());
+}
+
+template <class T, class Policy, class Tag>
+T erf_imp(T z, bool invert, const Policy& pol, const Tag& t)
+{
+ BOOST_MATH_STD_USING
+
+ BOOST_MATH_INSTRUMENT_CODE("Generic erf_imp called");
+
+ if(z < 0)
+ {
+ if(!invert)
+ return -erf_imp(T(-z), invert, pol, t);
+ else
+ return 1 + erf_imp(T(-z), false, pol, t);
+ }
+
+ T result;
+
+ if(!invert && (z > detail::erf_asymptotic_limit<T, Policy>()))
+ {
+ detail::erf_asympt_series_t<T> s(z);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+ result = boost::math::tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter, 1);
+ policies::check_series_iterations<T>("boost::math::erf<%1%>(%1%, %1%)", max_iter, pol);
+ }
+ else
+ {
+ T x = z * z;
+ if(x < 0.6)
+ {
+ // Compute P:
+ result = z * exp(-x);
+ result /= sqrt(boost::math::constants::pi<T>());
+ if(result != 0)
+ result *= 2 * detail::lower_gamma_series(T(0.5f), x, pol);
+ }
+ else if(x < 1.1f)
+ {
+ // Compute Q:
+ invert = !invert;
+ result = tgamma_small_upper_part(T(0.5f), x, pol);
+ result /= sqrt(boost::math::constants::pi<T>());
+ }
+ else
+ {
+ // Compute Q:
+ invert = !invert;
+ result = z * exp(-x);
+ result /= sqrt(boost::math::constants::pi<T>());
+ result *= upper_gamma_fraction(T(0.5f), x, policies::get_epsilon<T, Policy>());
+ }
+ }
+ if(invert)
+ result = 1 - result;
+ return result;
+}
+
+template <class T, class Policy>
+T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<53>& t)
+{
+ BOOST_MATH_STD_USING
+
+ BOOST_MATH_INSTRUMENT_CODE("53-bit precision erf_imp called");
+
+ if(z < 0)
+ {
+ if(!invert)
+ return -erf_imp(T(-z), invert, pol, t);
+ else if(z < -0.5)
+ return 2 - erf_imp(T(-z), invert, pol, t);
+ else
+ return 1 + erf_imp(T(-z), false, pol, t);
+ }
+
+ T result;
+
+ //
+ // Big bunch of selection statements now to pick
+ // which implementation to use,
+ // try to put most likely options first:
+ //
+ if(z < 0.5)
+ {
+ //
+ // We're going to calculate erf:
+ //
+ if(z < 1e-10)
+ {
+ if(z == 0)
+ {
+ result = T(0);
+ }
+ else
+ {
+ static const T c = BOOST_MATH_BIG_CONSTANT(T, 53, 0.003379167095512573896158903121545171688);
+ result = static_cast<T>(z * 1.125f + z * c);
+ }
+ }
+ else
+ {
+ // Maximum Deviation Found: 1.561e-17
+ // Expected Error Term: 1.561e-17
+ // Maximum Relative Change in Control Points: 1.155e-04
+ // Max Error found at double precision = 2.961182e-17
+
+ static const T Y = 1.044948577880859375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0834305892146531832907),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.338165134459360935041),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0509990735146777432841),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00772758345802133288487),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.000322780120964605683831),
+ };
+ static const T Q[] = {
+ 1L,
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.455004033050794024546),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0875222600142252549554),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00858571925074406212772),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000370900071787748000569),
+ };
+ T zz = z * z;
+ result = z * (Y + tools::evaluate_polynomial(P, zz) / tools::evaluate_polynomial(Q, zz));
+ }
+ }
+ else if(invert ? (z < 28) : (z < 5.8f))
+ {
+ //
+ // We'll be calculating erfc:
+ //
+ invert = !invert;
+ if(z < 1.5f)
+ {
+ // Maximum Deviation Found: 3.702e-17
+ // Expected Error Term: 3.702e-17
+ // Maximum Relative Change in Control Points: 2.845e-04
+ // Max Error found at double precision = 4.841816e-17
+ static const T Y = 0.405935764312744140625f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.098090592216281240205),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.178114665841120341155),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.191003695796775433986),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0888900368967884466578),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0195049001251218801359),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00180424538297014223957),
+ };
+ static const T Q[] = {
+ 1L,
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.84759070983002217845),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.42628004845511324508),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.578052804889902404909),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.12385097467900864233),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0113385233577001411017),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.337511472483094676155e-5),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 0.5)) / tools::evaluate_polynomial(Q, T(z - 0.5));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 2.5f)
+ {
+ // Max Error found at double precision = 6.599585e-18
+ // Maximum Deviation Found: 3.909e-18
+ // Expected Error Term: 3.909e-18
+ // Maximum Relative Change in Control Points: 9.886e-05
+ static const T Y = 0.50672817230224609375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0243500476207698441272),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0386540375035707201728),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.04394818964209516296),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0175679436311802092299),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00323962406290842133584),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000235839115596880717416),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.53991494948552447182),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.982403709157920235114),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.325732924782444448493),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0563921837420478160373),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00410369723978904575884),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 1.5)) / tools::evaluate_polynomial(Q, T(z - 1.5));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 4.5f)
+ {
+ // Maximum Deviation Found: 1.512e-17
+ // Expected Error Term: 1.512e-17
+ // Maximum Relative Change in Control Points: 2.222e-04
+ // Max Error found at double precision = 2.062515e-17
+ static const T Y = 0.5405750274658203125f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00295276716530971662634),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0137384425896355332126),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00840807615555585383007),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00212825620914618649141),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000250269961544794627958),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.113212406648847561139e-4),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.04217814166938418171),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.442597659481563127003),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0958492726301061423444),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0105982906484876531489),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000479411269521714493907),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 3.5)) / tools::evaluate_polynomial(Q, T(z - 3.5));
+ result *= exp(-z * z) / z;
+ }
+ else
+ {
+ // Max Error found at double precision = 2.997958e-17
+ // Maximum Deviation Found: 2.860e-17
+ // Expected Error Term: 2.859e-17
+ // Maximum Relative Change in Control Points: 1.357e-05
+ static const T Y = 0.5579090118408203125f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00628057170626964891937),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0175389834052493308818),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.212652252872804219852),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.687717681153649930619),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -2.5518551727311523996),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -3.22729451764143718517),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -2.8175401114513378771),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 2.79257750980575282228),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 11.0567237927800161565),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 15.930646027911794143),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 22.9367376522880577224),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 13.5064170191802889145),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 5.48409182238641741584),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(1 / z)) / tools::evaluate_polynomial(Q, T(1 / z));
+ result *= exp(-z * z) / z;
+ }
+ }
+ else
+ {
+ //
+ // Any value of z larger than 28 will underflow to zero:
+ //
+ result = 0;
+ invert = !invert;
+ }
+
+ if(invert)
+ {
+ result = 1 - result;
+ }
+
+ return result;
+} // template <class T, class Lanczos>T erf_imp(T z, bool invert, const Lanczos& l, const mpl::int_<53>& t)
+
+
+template <class T, class Policy>
+T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<64>& t)
+{
+ BOOST_MATH_STD_USING
+
+ BOOST_MATH_INSTRUMENT_CODE("64-bit precision erf_imp called");
+
+ if(z < 0)
+ {
+ if(!invert)
+ return -erf_imp(T(-z), invert, pol, t);
+ else if(z < -0.5)
+ return 2 - erf_imp(T(-z), invert, pol, t);
+ else
+ return 1 + erf_imp(T(-z), false, pol, t);
+ }
+
+ T result;
+
+ //
+ // Big bunch of selection statements now to pick which
+ // implementation to use, try to put most likely options
+ // first:
+ //
+ if(z < 0.5)
+ {
+ //
+ // We're going to calculate erf:
+ //
+ if(z == 0)
+ {
+ result = 0;
+ }
+ else if(z < 1e-10)
+ {
+ static const T c = BOOST_MATH_BIG_CONSTANT(T, 64, 0.003379167095512573896158903121545171688);
+ result = z * 1.125 + z * c;
+ }
+ else
+ {
+ // Max Error found at long double precision = 1.623299e-20
+ // Maximum Deviation Found: 4.326e-22
+ // Expected Error Term: -4.326e-22
+ // Maximum Relative Change in Control Points: 1.474e-04
+ static const T Y = 1.044948577880859375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0834305892146531988966),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.338097283075565413695),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0509602734406067204596),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00904906346158537794396),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.000489468651464798669181),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.200305626366151877759e-4),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.455817300515875172439),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0916537354356241792007),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0102722652675910031202),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000650511752687851548735),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.189532519105655496778e-4),
+ };
+ result = z * (Y + tools::evaluate_polynomial(P, T(z * z)) / tools::evaluate_polynomial(Q, T(z * z)));
+ }
+ }
+ else if(invert ? (z < 110) : (z < 6.4f))
+ {
+ //
+ // We'll be calculating erfc:
+ //
+ invert = !invert;
+ if(z < 1.5)
+ {
+ // Max Error found at long double precision = 3.239590e-20
+ // Maximum Deviation Found: 2.241e-20
+ // Expected Error Term: -2.241e-20
+ // Maximum Relative Change in Control Points: 5.110e-03
+ static const T Y = 0.405935764312744140625f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0980905922162812031672),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.159989089922969141329),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.222359821619935712378),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.127303921703577362312),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0384057530342762400273),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00628431160851156719325),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000441266654514391746428),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.266689068336295642561e-7),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 2.03237474985469469291),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.78355454954969405222),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.867940326293760578231),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.248025606990021698392),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0396649631833002269861),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00279220237309449026796),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 0.5f)) / tools::evaluate_polynomial(Q, T(z - 0.5f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 2.5)
+ {
+ // Max Error found at long double precision = 3.686211e-21
+ // Maximum Deviation Found: 1.495e-21
+ // Expected Error Term: -1.494e-21
+ // Maximum Relative Change in Control Points: 1.793e-04
+ static const T Y = 0.50672817230224609375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.024350047620769840217),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0343522687935671451309),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0505420824305544949541),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0257479325917757388209),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00669349844190354356118),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00090807914416099524444),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.515917266698050027934e-4),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.71657861671930336344),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.26409634824280366218),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.512371437838969015941),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.120902623051120950935),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0158027197831887485261),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000897871370778031611439),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 1.5f)) / tools::evaluate_polynomial(Q, T(z - 1.5f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 4.5)
+ {
+ // Maximum Deviation Found: 1.107e-20
+ // Expected Error Term: -1.106e-20
+ // Maximum Relative Change in Control Points: 1.709e-04
+ // Max Error found at long double precision = 1.446908e-20
+ static const T Y = 0.5405750274658203125f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0029527671653097284033),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0141853245895495604051),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0104959584626432293901),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00343963795976100077626),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00059065441194877637899),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.523435380636174008685e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.189896043050331257262e-5),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.19352160185285642574),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.603256964363454392857),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.165411142458540585835),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0259729870946203166468),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00221657568292893699158),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.804149464190309799804e-4),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 3.5f)) / tools::evaluate_polynomial(Q, T(z - 3.5f));
+ result *= exp(-z * z) / z;
+ }
+ else
+ {
+ // Max Error found at long double precision = 7.961166e-21
+ // Maximum Deviation Found: 6.677e-21
+ // Expected Error Term: 6.676e-21
+ // Maximum Relative Change in Control Points: 2.319e-05
+ static const T Y = 0.55825519561767578125f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00593438793008050214106),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0280666231009089713937),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.141597835204583050043),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.978088201154300548842),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -5.47351527796012049443),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -13.8677304660245326627),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -27.1274948720539821722),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -29.2545152747009461519),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -16.8865774499799676937),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 4.72948911186645394541),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 23.6750543147695749212),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 60.0021517335693186785),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 131.766251645149522868),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 178.167924971283482513),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 182.499390505915222699),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 104.365251479578577989),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 30.8365511891224291717),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(1 / z)) / tools::evaluate_polynomial(Q, T(1 / z));
+ result *= exp(-z * z) / z;
+ }
+ }
+ else
+ {
+ //
+ // Any value of z larger than 110 will underflow to zero:
+ //
+ result = 0;
+ invert = !invert;
+ }
+
+ if(invert)
+ {
+ result = 1 - result;
+ }
+
+ return result;
+} // template <class T, class Lanczos>T erf_imp(T z, bool invert, const Lanczos& l, const mpl::int_<64>& t)
+
+
+template <class T, class Policy>
+T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<113>& t)
+{
+ BOOST_MATH_STD_USING
+
+ BOOST_MATH_INSTRUMENT_CODE("113-bit precision erf_imp called");
+
+ if(z < 0)
+ {
+ if(!invert)
+ return -erf_imp(T(-z), invert, pol, t);
+ else if(z < -0.5)
+ return 2 - erf_imp(T(-z), invert, pol, t);
+ else
+ return 1 + erf_imp(T(-z), false, pol, t);
+ }
+
+ T result;
+
+ //
+ // Big bunch of selection statements now to pick which
+ // implementation to use, try to put most likely options
+ // first:
+ //
+ if(z < 0.5)
+ {
+ //
+ // We're going to calculate erf:
+ //
+ if(z == 0)
+ {
+ result = 0;
+ }
+ else if(z < 1e-20)
+ {
+ static const T c = BOOST_MATH_BIG_CONSTANT(T, 113, 0.003379167095512573896158903121545171688);
+ result = z * 1.125 + z * c;
+ }
+ else
+ {
+ // Max Error found at long double precision = 2.342380e-35
+ // Maximum Deviation Found: 6.124e-36
+ // Expected Error Term: -6.124e-36
+ // Maximum Relative Change in Control Points: 3.492e-10
+ static const T Y = 1.0841522216796875f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0442269454158250738961589031215451778),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.35549265736002144875335323556961233),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0582179564566667896225454670863270393),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0112694696904802304229950538453123925),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000805730648981801146251825329609079099),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.566304966591936566229702842075966273e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.169655010425186987820201021510002265e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.344448249920445916714548295433198544e-7),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.466542092785657604666906909196052522),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.100005087012526447295176964142107611),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0128341535890117646540050072234142603),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00107150448466867929159660677016658186),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.586168368028999183607733369248338474e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.196230608502104324965623171516808796e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.313388521582925207734229967907890146e-7),
+ };
+ result = z * (Y + tools::evaluate_polynomial(P, T(z * z)) / tools::evaluate_polynomial(Q, T(z * z)));
+ }
+ }
+ else if(invert ? (z < 110) : (z < 8.65f))
+ {
+ //
+ // We'll be calculating erfc:
+ //
+ invert = !invert;
+ if(z < 1)
+ {
+ // Max Error found at long double precision = 3.246278e-35
+ // Maximum Deviation Found: 1.388e-35
+ // Expected Error Term: 1.387e-35
+ // Maximum Relative Change in Control Points: 6.127e-05
+ static const T Y = 0.371877193450927734375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0640320213544647969396032886581290455),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.200769874440155895637857443946706731),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.378447199873537170666487408805779826),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.30521399466465939450398642044975127),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.146890026406815277906781824723458196),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0464837937749539978247589252732769567),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00987895759019540115099100165904822903),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00137507575429025512038051025154301132),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0001144764551085935580772512359680516),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.436544865032836914773944382339900079e-5),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.47651182872457465043733800302427977),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.78706486002517996428836400245547955),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.87295924621659627926365005293130693),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.829375825174365625428280908787261065),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.251334771307848291593780143950311514),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0522110268876176186719436765734722473),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00718332151250963182233267040106902368),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000595279058621482041084986219276392459),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.226988669466501655990637599399326874e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.270666232259029102353426738909226413e-10),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 0.5f)) / tools::evaluate_polynomial(Q, T(z - 0.5f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 1.5)
+ {
+ // Max Error found at long double precision = 2.215785e-35
+ // Maximum Deviation Found: 1.539e-35
+ // Expected Error Term: 1.538e-35
+ // Maximum Relative Change in Control Points: 6.104e-05
+ static const T Y = 0.45658016204833984375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0289965858925328393392496555094848345),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0868181194868601184627743162571779226),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.169373435121178901746317404936356745),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.13350446515949251201104889028133486),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0617447837290183627136837688446313313),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0185618495228251406703152962489700468),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00371949406491883508764162050169531013),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000485121708792921297742105775823900772),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.376494706741453489892108068231400061e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.133166058052466262415271732172490045e-5),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.32970330146503867261275580968135126),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.46325715420422771961250513514928746),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.55307882560757679068505047390857842),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.644274289865972449441174485441409076),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.182609091063258208068606847453955649),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0354171651271241474946129665801606795),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00454060370165285246451879969534083997),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000349871943711566546821198612518656486),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.123749319840299552925421880481085392e-4),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 1.0f)) / tools::evaluate_polynomial(Q, T(z - 1.0f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 2.25)
+ {
+ // Maximum Deviation Found: 1.418e-35
+ // Expected Error Term: 1.418e-35
+ // Maximum Relative Change in Control Points: 1.316e-04
+ // Max Error found at long double precision = 1.998462e-35
+ static const T Y = 0.50250148773193359375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0201233630504573402185161184151016606),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0331864357574860196516686996302305002),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0716562720864787193337475444413405461),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0545835322082103985114927569724880658),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0236692635189696678976549720784989593),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00656970902163248872837262539337601845),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00120282643299089441390490459256235021),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000142123229065182650020762792081622986),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.991531438367015135346716277792989347e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.312857043762117596999398067153076051e-6),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.13506082409097783827103424943508554),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.06399257267556230937723190496806215),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.18678481279932541314830499880691109),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.447733186643051752513538142316799562),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.11505680005657879437196953047542148),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.020163993632192726170219663831914034),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00232708971840141388847728782209730585),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000160733201627963528519726484608224112),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.507158721790721802724402992033269266e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.18647774409821470950544212696270639e-12),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 1.5f)) / tools::evaluate_polynomial(Q, T(z - 1.5f));
+ result *= exp(-z * z) / z;
+ }
+ else if (z < 3)
+ {
+ // Maximum Deviation Found: 3.575e-36
+ // Expected Error Term: 3.575e-36
+ // Maximum Relative Change in Control Points: 7.103e-05
+ // Max Error found at long double precision = 5.794737e-36
+ static const T Y = 0.52896785736083984375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00902152521745813634562524098263360074),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0145207142776691539346923710537580927),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0301681239582193983824211995978678571),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0215548540823305814379020678660434461),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00864683476267958365678294164340749949),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00219693096885585491739823283511049902),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000364961639163319762492184502159894371),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.388174251026723752769264051548703059e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.241918026931789436000532513553594321e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.676586625472423508158937481943649258e-7),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.93669171363907292305550231764920001),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.69468476144051356810672506101377494),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.880023580986436640372794392579985511),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.299099106711315090710836273697708402),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0690593962363545715997445583603382337),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0108427016361318921960863149875360222),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00111747247208044534520499324234317695),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.686843205749767250666787987163701209e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.192093541425429248675532015101904262e-5),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 2.25f)) / tools::evaluate_polynomial(Q, T(z - 2.25f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 3.5)
+ {
+ // Maximum Deviation Found: 8.126e-37
+ // Expected Error Term: -8.126e-37
+ // Maximum Relative Change in Control Points: 1.363e-04
+ // Max Error found at long double precision = 1.747062e-36
+ static const T Y = 0.54037380218505859375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0033703486408887424921155540591370375),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0104948043110005245215286678898115811),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0148530118504000311502310457390417795),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00816693029245443090102738825536188916),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00249716579989140882491939681805594585),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0004655591010047353023978045800916647),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.531129557920045295895085236636025323e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.343526765122727069515775194111741049e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.971120407556888763695313774578711839e-7),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.59911256167540354915906501335919317),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.136006830764025173864831382946934),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.468565867990030871678574840738423023),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.122821824954470343413956476900662236),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0209670914950115943338996513330141633),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00227845718243186165620199012883547257),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000144243326443913171313947613547085553),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.407763415954267700941230249989140046e-5),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 3.0f)) / tools::evaluate_polynomial(Q, T(z - 3.0f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 5.5)
+ {
+ // Maximum Deviation Found: 5.804e-36
+ // Expected Error Term: -5.803e-36
+ // Maximum Relative Change in Control Points: 2.475e-05
+ // Max Error found at long double precision = 1.349545e-35
+ static const T Y = 0.55000019073486328125f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00118142849742309772151454518093813615),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0072201822885703318172366893469382745),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0078782276276860110721875733778481505),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00418229166204362376187593976656261146),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00134198400587769200074194304298642705),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000283210387078004063264777611497435572),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.405687064094911866569295610914844928e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.39348283801568113807887364414008292e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.248798540917787001526976889284624449e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.929502490223452372919607105387474751e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.156161469668275442569286723236274457e-9),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.52955245103668419479878456656709381),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.06263944820093830054635017117417064),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.441684612681607364321013134378316463),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.121665258426166960049773715928906382),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0232134512374747691424978642874321434),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00310778180686296328582860464875562636),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000288361770756174705123674838640161693),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.177529187194133944622193191942300132e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.655068544833064069223029299070876623e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.11005507545746069573608988651927452e-7),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 4.5f)) / tools::evaluate_polynomial(Q, T(z - 4.5f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 7.5)
+ {
+ // Maximum Deviation Found: 1.007e-36
+ // Expected Error Term: 1.007e-36
+ // Maximum Relative Change in Control Points: 1.027e-03
+ // Max Error found at long double precision = 2.646420e-36
+ static const T Y = 0.5574436187744140625f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000293236907400849056269309713064107674),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00225110719535060642692275221961480162),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00190984458121502831421717207849429799),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000747757733460111743833929141001680706),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000170663175280949889583158597373928096),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.246441188958013822253071608197514058e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.229818000860544644974205957895688106e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.134886977703388748488480980637704864e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.454764611880548962757125070106650958e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.673002744115866600294723141176820155e-10),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.12843690320861239631195353379313367),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.569900657061622955362493442186537259),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.169094404206844928112348730277514273),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0324887449084220415058158657252147063),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00419252877436825753042680842608219552),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00036344133176118603523976748563178578),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.204123895931375107397698245752850347e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.674128352521481412232785122943508729e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.997637501418963696542159244436245077e-8),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z - 6.5f)) / tools::evaluate_polynomial(Q, T(z - 6.5f));
+ result *= exp(-z * z) / z;
+ }
+ else if(z < 11.5)
+ {
+ // Maximum Deviation Found: 8.380e-36
+ // Expected Error Term: 8.380e-36
+ // Maximum Relative Change in Control Points: 2.632e-06
+ // Max Error found at long double precision = 9.849522e-36
+ static const T Y = 0.56083202362060546875f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000282420728751494363613829834891390121),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00175387065018002823433704079355125161),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0021344978564889819420775336322920375),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00124151356560137532655039683963075661),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000423600733566948018555157026862139644),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.914030340865175237133613697319509698e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.126999927156823363353809747017945494e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.110610959842869849776179749369376402e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.55075079477173482096725348704634529e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.119735694018906705225870691331543806e-8),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.69889613396167354566098060039549882),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.28824647372749624464956031163282674),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.572297795434934493541628008224078717),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.164157697425571712377043857240773164),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0315311145224594430281219516531649562),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00405588922155632380812945849777127458),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000336929033691445666232029762868642417),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.164033049810404773469413526427932109e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.356615210500531410114914617294694857e-6),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(z / 2 - 4.75f)) / tools::evaluate_polynomial(Q, T(z / 2 - 4.75f));
+ result *= exp(-z * z) / z;
+ }
+ else
+ {
+ // Maximum Deviation Found: 1.132e-35
+ // Expected Error Term: -1.132e-35
+ // Maximum Relative Change in Control Points: 4.674e-04
+ // Max Error found at long double precision = 1.162590e-35
+ static const T Y = 0.5632686614990234375f;
+ static const T P[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000920922048732849448079451574171836943),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00321439044532288750501700028748922439),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.250455263029390118657884864261823431),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.906807635364090342031792404764598142),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -8.92233572835991735876688745989985565),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -21.7797433494422564811782116907878495),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -91.1451915251976354349734589601171659),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -144.1279109655993927069052125017673),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -313.845076581796338665519022313775589),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -273.11378811923343424081101235736475),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -271.651566205951067025696102600443452),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -60.0530577077238079968843307523245547),
+ };
+ static const T Q[] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 3.49040448075464744191022350947892036),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 34.3563592467165971295915749548313227),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 84.4993232033879023178285731843850461),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 376.005865281206894120659401340373818),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 629.95369438888946233003926191755125),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1568.35771983533158591604513304269098),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1646.02452040831961063640827116581021),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2299.96860633240298708910425594484895),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1222.73204392037452750381340219906374),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 799.359797306084372350264298361110448),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 72.7415265778588087243442792401576737),
+ };
+ result = Y + tools::evaluate_polynomial(P, T(1 / z)) / tools::evaluate_polynomial(Q, T(1 / z));
+ result *= exp(-z * z) / z;
+ }
+ }
+ else
+ {
+ //
+ // Any value of z larger than 110 will underflow to zero:
+ //
+ result = 0;
+ invert = !invert;
+ }
+
+ if(invert)
+ {
+ result = 1 - result;
+ }
+
+ return result;
+} // template <class T, class Lanczos>T erf_imp(T z, bool invert, const Lanczos& l, const mpl::int_<113>& t)
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type erf(T z, 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;
+
+ BOOST_MATH_INSTRUMENT_CODE("result_type = " << typeid(result_type).name());
+ BOOST_MATH_INSTRUMENT_CODE("value_type = " << typeid(value_type).name());
+ BOOST_MATH_INSTRUMENT_CODE("precision_type = " << typeid(precision_type).name());
+
+ typedef typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>, // double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>, // 80-bit long double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<113>, // 128-bit long double
+ mpl::int_<0> // too many bits, use generic version.
+ >::type
+ >::type
+ >::type
+ >::type tag_type;
+
+ BOOST_MATH_INSTRUMENT_CODE("tag_type = " << typeid(tag_type).name());
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::erf_imp(
+ static_cast<value_type>(z),
+ false,
+ forwarding_policy(),
+ tag_type()), "boost::math::erf<%1%>(%1%, %1%)");
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type erfc(T z, 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;
+
+ BOOST_MATH_INSTRUMENT_CODE("result_type = " << typeid(result_type).name());
+ BOOST_MATH_INSTRUMENT_CODE("value_type = " << typeid(value_type).name());
+ BOOST_MATH_INSTRUMENT_CODE("precision_type = " << typeid(precision_type).name());
+
+ typedef typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>, // double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>, // 80-bit long double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<113>, // 128-bit long double
+ mpl::int_<0> // too many bits, use generic version.
+ >::type
+ >::type
+ >::type
+ >::type tag_type;
+
+ BOOST_MATH_INSTRUMENT_CODE("tag_type = " << typeid(tag_type).name());
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::erf_imp(
+ static_cast<value_type>(z),
+ true,
+ forwarding_policy(),
+ tag_type()), "boost::math::erfc<%1%>(%1%, %1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type erf(T z)
+{
+ return boost::math::erf(z, policies::policy<>());
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type erfc(T z)
+{
+ return boost::math::erfc(z, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#include <boost/math/special_functions/detail/erf_inv.hpp>
+
+#endif // BOOST_MATH_SPECIAL_ERF_HPP
+
+
+
+
diff --git a/boost/math/special_functions/expint.hpp b/boost/math/special_functions/expint.hpp
new file mode 100644
index 0000000000..06bd78ff48
--- /dev/null
+++ b/boost/math/special_functions/expint.hpp
@@ -0,0 +1,1579 @@
+// 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_EXPINT_HPP
+#define BOOST_MATH_EXPINT_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/math/tools/fraction.hpp>
+#include <boost/math/tools/series.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/digamma.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+#include <boost/math/special_functions/pow.hpp>
+
+namespace boost{ namespace math{
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ expint(unsigned n, T z, const Policy& /*pol*/);
+
+namespace detail{
+
+template <class T>
+inline T expint_1_rational(const T& z, const mpl::int_<0>&)
+{
+ // this function is never actually called
+ BOOST_ASSERT(0);
+ return z;
+}
+
+template <class T>
+T expint_1_rational(const T& z, const mpl::int_<53>&)
+{
+ BOOST_MATH_STD_USING
+ T result;
+ if(z <= 1)
+ {
+ // Maximum Deviation Found: 2.006e-18
+ // Expected Error Term: 2.006e-18
+ // Max error found at double precision: 2.760e-17
+ static const T Y = 0.66373538970947265625F;
+ static const T P[6] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0865197248079397976498),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0320913665303559189999),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.245088216639761496153),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0368031736257943745142),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00399167106081113256961),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.000111507792921197858394)
+ };
+ static const T Q[6] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.37091387659397013215),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.056770677104207528384),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00427347600017103698101),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000131049900798434683324),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.528611029520217142048e-6)
+ };
+ result = tools::evaluate_polynomial(P, z)
+ / tools::evaluate_polynomial(Q, z);
+ result += z - log(z) - Y;
+ }
+ else if(z < -boost::math::tools::log_min_value<T>())
+ {
+ // Maximum Deviation Found (interpolated): 1.444e-17
+ // Max error found at double precision: 3.119e-17
+ static const T P[11] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.121013190657725568138e-18),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.999999999999998811143),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -43.3058660811817946037),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -724.581482791462469795),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -6046.8250112711035463),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -27182.6254466733970467),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -66598.2652345418633509),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -86273.1567711649528784),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -54844.4587226402067411),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -14751.4895786128450662),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -1185.45720315201027667)
+ };
+ static const T Q[12] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 45.3058660811801465927),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 809.193214954550328455),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 7417.37624454689546708),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 38129.5594484818471461),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 113057.05869159631492),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 192104.047790227984431),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 180329.498380501819718),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 86722.3403467334749201),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 18455.4124737722049515),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1229.20784182403048905),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.776491285282330997549)
+ };
+ T recip = 1 / z;
+ result = 1 + tools::evaluate_polynomial(P, recip)
+ / tools::evaluate_polynomial(Q, recip);
+ result *= exp(-z) * recip;
+ }
+ else
+ {
+ result = 0;
+ }
+ return result;
+}
+
+template <class T>
+T expint_1_rational(const T& z, const mpl::int_<64>&)
+{
+ BOOST_MATH_STD_USING
+ T result;
+ if(z <= 1)
+ {
+ // Maximum Deviation Found: 3.807e-20
+ // Expected Error Term: 3.807e-20
+ // Max error found at long double precision: 6.249e-20
+
+ static const T Y = 0.66373538970947265625F;
+ static const T P[6] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0865197248079397956816),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0275114007037026844633),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.246594388074877139824),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0237624819878732642231),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00259113319641673986276),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.30853660894346057053e-4)
+ };
+ static const T Q[7] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.317978365797784100273),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0393622602554758722511),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00204062029115966323229),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.732512107100088047854e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.202872781770207871975e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.52779248094603709945e-7)
+ };
+ result = tools::evaluate_polynomial(P, z)
+ / tools::evaluate_polynomial(Q, z);
+ result += z - log(z) - Y;
+ }
+ else if(z < -boost::math::tools::log_min_value<T>())
+ {
+ // Maximum Deviation Found (interpolated): 2.220e-20
+ // Max error found at long double precision: 1.346e-19
+ static const T P[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.534401189080684443046e-23),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.999999999999999999905),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -62.1517806091379402505),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -1568.45688271895145277),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -21015.3431990874009619),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -164333.011755931661949),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -777917.270775426696103),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -2244188.56195255112937),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -3888702.98145335643429),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -3909822.65621952648353),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -2149033.9538897398457),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -584705.537139793925189),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -65815.2605361889477244),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -2038.82870680427258038)
+ };
+ static const T Q[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 64.1517806091379399478),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1690.76044393722763785),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 24035.9534033068949426),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 203679.998633572361706),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1074661.58459976978285),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 3586552.65020899358773),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 7552186.84989547621411),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 9853333.79353054111434),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 7689642.74550683631258),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 3385553.35146759180739),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 763218.072732396428725),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 73930.2995984054930821),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 2063.86994219629165937)
+ };
+ T recip = 1 / z;
+ result = 1 + tools::evaluate_polynomial(P, recip)
+ / tools::evaluate_polynomial(Q, recip);
+ result *= exp(-z) * recip;
+ }
+ else
+ {
+ result = 0;
+ }
+ return result;
+}
+
+template <class T>
+T expint_1_rational(const T& z, const mpl::int_<113>&)
+{
+ BOOST_MATH_STD_USING
+ T result;
+ if(z <= 1)
+ {
+ // Maximum Deviation Found: 2.477e-35
+ // Expected Error Term: 2.477e-35
+ // Max error found at long double precision: 6.810e-35
+
+ static const T Y = 0.66373538970947265625F;
+ static const T P[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0865197248079397956434879099175975937),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0369066175910795772830865304506087759),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.24272036838415474665971599314725545),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0502166331248948515282379137550178307),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00768384138547489410285101483730424919),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000612574337702109683505224915484717162),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.380207107950635046971492617061708534e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.136528159460768830763009294683628406e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.346839106212658259681029388908658618e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.340500302777838063940402160594523429e-9)
+ };
+ static const T Q[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.426568827778942588160423015589537302),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0841384046470893490592450881447510148),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0100557215850668029618957359471132995),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000799334870474627021737357294799839363),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.434452090903862735242423068552687688e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.15829674748799079874182885081231252e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.354406206738023762100882270033082198e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.369373328141051577845488477377890236e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.274149801370933606409282434677600112e-12)
+ };
+ result = tools::evaluate_polynomial(P, z)
+ / tools::evaluate_polynomial(Q, z);
+ result += z - log(z) - Y;
+ }
+ else if(z <= 4)
+ {
+ // Max error in interpolated form: 5.614e-35
+ // Max error found at long double precision: 7.979e-35
+
+ static const T Y = 0.70190334320068359375F;
+
+ static const T P[16] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.298096656795020369955077350585959794),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 12.9314045995266142913135497455971247),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 226.144334921582637462526628217345501),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2070.83670924261732722117682067381405),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 10715.1115684330959908244769731347186),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 30728.7876355542048019664777316053311),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 38520.6078609349855436936232610875297),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -27606.0780981527583168728339620565165),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -169026.485055785605958655247592604835),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -254361.919204983608659069868035092282),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -195765.706874132267953259272028679935),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -83352.6826013533205474990119962408675),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -19251.6828496869586415162597993050194),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -2226.64251774578542836725386936102339),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -109.009437301400845902228611986479816),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -1.51492042209561411434644938098833499)
+ };
+ static const T Q[16] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 46.734521442032505570517810766704587),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 908.694714348462269000247450058595655),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 9701.76053033673927362784882748513195),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 63254.2815292641314236625196594947774),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 265115.641285880437335106541757711092),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 732707.841188071900498536533086567735),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1348514.02492635723327306628712057794),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1649986.81455283047769673308781585991),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1326000.828522976970116271208812099),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 683643.09490612171772350481773951341),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 217640.505137263607952365685653352229),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 40288.3467237411710881822569476155485),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 3932.89353979531632559232883283175754),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 169.845369689596739824177412096477219),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.17607292280092201170768401876895354)
+ };
+ T recip = 1 / z;
+ result = Y + tools::evaluate_polynomial(P, recip)
+ / tools::evaluate_polynomial(Q, recip);
+ result *= exp(-z) * recip;
+ }
+ else if(z < -boost::math::tools::log_min_value<T>())
+ {
+ // Max error in interpolated form: 4.413e-35
+ // Max error found at long double precision: 8.928e-35
+
+ static const T P[19] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.559148411832951463689610809550083986e-40),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.999999999999999999999999999999999997),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -166.542326331163836642960118190147367),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -12204.639128796330005065904675153652),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -520807.069767086071806275022036146855),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -14435981.5242137970691490903863125326),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -274574945.737064301247496460758654196),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -3691611582.99810039356254671781473079),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -35622515944.8255047299363690814678763),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -248040014774.502043161750715548451142),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -1243190389769.53458416330946622607913),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -4441730126135.54739052731990368425339),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -11117043181899.7388524310281751971366),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -18976497615396.9717776601813519498961),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -21237496819711.1011661104761906067131),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -14695899122092.5161620333466757812848),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -5737221535080.30569711574295785864903),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -1077042281708.42654526404581272546244),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -68028222642.1941480871395695677675137)
+ };
+ static const T Q[20] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 168.542326331163836642960118190147311),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 12535.7237814586576783518249115343619),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 544891.263372016404143120911148640627),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 15454474.7241010258634446523045237762),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 302495899.896629522673410325891717381),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 4215565948.38886507646911672693270307),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 42552409471.7951815668506556705733344),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 313592377066.753173979584098301610186),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1688763640223.4541980740597514904542),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 6610992294901.59589748057620192145704),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 18601637235659.6059890851321772682606),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 36944278231087.2571020964163402941583),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 50425858518481.7497071917028793820058),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 45508060902865.0899967797848815980644),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 25649955002765.3817331501988304758142),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 8259575619094.6518520988612711292331),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1299981487496.12607474362723586264515),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 70242279152.8241187845178443118302693),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -37633302.9409263839042721539363416685)
+ };
+ T recip = 1 / z;
+ result = 1 + tools::evaluate_polynomial(P, recip)
+ / tools::evaluate_polynomial(Q, recip);
+ result *= exp(-z) * recip;
+ }
+ else
+ {
+ result = 0;
+ }
+ return result;
+}
+
+template <class T>
+struct expint_fraction
+{
+ typedef std::pair<T,T> result_type;
+ expint_fraction(unsigned n_, T z_) : b(n_ + z_), i(-1), n(n_){}
+ std::pair<T,T> operator()()
+ {
+ std::pair<T,T> result = std::make_pair(-static_cast<T>((i+1) * (n+i)), b);
+ b += 2;
+ ++i;
+ return result;
+ }
+private:
+ T b;
+ int i;
+ unsigned n;
+};
+
+template <class T, class Policy>
+inline T expint_as_fraction(unsigned n, T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ BOOST_MATH_INSTRUMENT_VARIABLE(z)
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+ expint_fraction<T> f(n, z);
+ T result = tools::continued_fraction_b(
+ f,
+ boost::math::policies::get_epsilon<T, Policy>(),
+ max_iter);
+ policies::check_series_iterations<T>("boost::math::expint_continued_fraction<%1%>(unsigned,%1%)", max_iter, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ BOOST_MATH_INSTRUMENT_VARIABLE(max_iter)
+ result = exp(-z) / result;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ return result;
+}
+
+template <class T>
+struct expint_series
+{
+ typedef T result_type;
+ expint_series(unsigned k_, T z_, T x_k_, T denom_, T fact_)
+ : k(k_), z(z_), x_k(x_k_), denom(denom_), fact(fact_){}
+ T operator()()
+ {
+ x_k *= -z;
+ denom += 1;
+ fact *= ++k;
+ return x_k / (denom * fact);
+ }
+private:
+ unsigned k;
+ T z;
+ T x_k;
+ T denom;
+ T fact;
+};
+
+template <class T, class Policy>
+inline T expint_as_series(unsigned n, T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+
+ BOOST_MATH_INSTRUMENT_VARIABLE(z)
+
+ T result = 0;
+ T x_k = -1;
+ T denom = T(1) - n;
+ T fact = 1;
+ unsigned k = 0;
+ for(; k < n - 1;)
+ {
+ result += x_k / (denom * fact);
+ denom += 1;
+ x_k *= -z;
+ fact *= ++k;
+ }
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result += pow(-z, static_cast<T>(n - 1))
+ * (boost::math::digamma(static_cast<T>(n)) - log(z)) / fact;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+
+ expint_series<T> s(k, z, x_k, denom, fact);
+ result = tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter, result);
+ policies::check_series_iterations<T>("boost::math::expint_series<%1%>(unsigned,%1%)", max_iter, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ BOOST_MATH_INSTRUMENT_VARIABLE(max_iter)
+ return result;
+}
+
+template <class T, class Policy, class Tag>
+T expint_imp(unsigned n, T z, const Policy& pol, const Tag& tag)
+{
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::expint<%1%>(unsigned, %1%)";
+ if(z < 0)
+ return policies::raise_domain_error<T>(function, "Function requires z >= 0 but got %1%.", z, pol);
+ if(z == 0)
+ return n == 1 ? policies::raise_overflow_error<T>(function, 0, pol) : T(1 / (static_cast<T>(n - 1)));
+
+ T result;
+
+ bool f;
+ if(n < 3)
+ {
+ f = z < 0.5;
+ }
+ else
+ {
+ f = z < (static_cast<T>(n - 2) / static_cast<T>(n - 1));
+ }
+#ifdef BOOST_MSVC
+# pragma warning(push)
+# pragma warning(disable:4127) // conditional expression is constant
+#endif
+ if(n == 0)
+ result = exp(-z) / z;
+ else if((n == 1) && (Tag::value))
+ {
+ result = expint_1_rational(z, tag);
+ }
+ else if(f)
+ result = expint_as_series(n, z, pol);
+ else
+ result = expint_as_fraction(n, z, pol);
+#ifdef BOOST_MSVC
+# pragma warning(pop)
+#endif
+
+ return result;
+}
+
+template <class T>
+struct expint_i_series
+{
+ typedef T result_type;
+ expint_i_series(T z_) : k(0), z_k(1), z(z_){}
+ T operator()()
+ {
+ z_k *= z / ++k;
+ return z_k / k;
+ }
+private:
+ unsigned k;
+ T z_k;
+ T z;
+};
+
+template <class T, class Policy>
+T expint_i_as_series(T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T result = log(z); // (log(z) - log(1 / z)) / 2;
+ result += constants::euler<T>();
+ expint_i_series<T> s(z);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+ result = tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter, result);
+ policies::check_series_iterations<T>("boost::math::expint_i_series<%1%>(%1%)", max_iter, pol);
+ return result;
+}
+
+template <class T, class Policy, class Tag>
+T expint_i_imp(T z, const Policy& pol, const Tag& tag)
+{
+ static const char* function = "boost::math::expint<%1%>(%1%)";
+ if(z < 0)
+ return -expint_imp(1, T(-z), pol, tag);
+ if(z == 0)
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+ return expint_i_as_series(z, pol);
+}
+
+template <class T, class Policy>
+T expint_i_imp(T z, const Policy& pol, const mpl::int_<53>& tag)
+{
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::expint<%1%>(%1%)";
+ if(z < 0)
+ return -expint_imp(1, T(-z), pol, tag);
+ if(z == 0)
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+
+ T result;
+
+ if(z <= 6)
+ {
+ // Maximum Deviation Found: 2.852e-18
+ // Expected Error Term: 2.852e-18
+ // Max Error found at double precision = Poly: 2.636335e-16 Cheb: 4.187027e-16
+ static const T P[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 2.98677224343598593013),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.356343618769377415068),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.780836076283730801839),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.114670926327032002811),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0499434773576515260534),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00726224593341228159561),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00115478237227804306827),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000116419523609765200999),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.798296365679269702435e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.2777056254402008721e-6)
+ };
+ static const T Q[8] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -1.17090412365413911947),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.62215109846016746276),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.195114782069495403315),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0391523431392967238166),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00504800158663705747345),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000389034007436065401822),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.138972589601781706598e-4)
+ };
+
+ static const T c1 = BOOST_MATH_BIG_CONSTANT(T, 53, 1677624236387711.0);
+ static const T c2 = BOOST_MATH_BIG_CONSTANT(T, 53, 4503599627370496.0);
+ static const T r1 = static_cast<T>(c1 / c2);
+ static const T r2 = BOOST_MATH_BIG_CONSTANT(T, 53, 0.131401834143860282009280387409357165515556574352422001206362e-16);
+ static const T r = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 53, 0.372507410781366634461991866580119133535689497771654051555657435242200120636201854384926049951548942392));
+ T t = (z / 3) - 1;
+ result = tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ t = (z - r1) - r2;
+ result *= t;
+ if(fabs(t) < 0.1)
+ {
+ result += boost::math::log1p(t / r);
+ }
+ else
+ {
+ result += log(z / r);
+ }
+ }
+ else if (z <= 10)
+ {
+ // Maximum Deviation Found: 6.546e-17
+ // Expected Error Term: 6.546e-17
+ // Max Error found at double precision = Poly: 6.890169e-17 Cheb: 6.772128e-17
+ static const T Y = 1.158985137939453125F;
+ static const T P[8] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00139324086199402804173),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0349921221823888744966),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0264095520754134848538),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00761224003005476438412),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00247496209592143627977),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.000374885917942100256775),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.554086272024881826253e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.396487648924804510056e-5)
+ };
+ static const T Q[8] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.744625566823272107711),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.329061095011767059236),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.100128624977313872323),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0223851099128506347278),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00365334190742316650106),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000402453408512476836472),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.263649630720255691787e-4)
+ };
+ T t = z / 2 - 4;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+ }
+ else if(z <= 20)
+ {
+ // Maximum Deviation Found: 1.843e-17
+ // Expected Error Term: -1.842e-17
+ // Max Error found at double precision = Poly: 4.375868e-17 Cheb: 5.860967e-17
+
+ static const T Y = 1.0869731903076171875F;
+ static const T P[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00893891094356945667451),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0484607730127134045806),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0652810444222236895772),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0478447572647309671455),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0226059218923777094596),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00720603636917482065907),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00155941947035972031334),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.000209750022660200888349),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.138652200349182596186e-4)
+ };
+ static const T Q[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.97017214039061194971),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.86232465043073157508),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.09601437090337519977),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.438873285773088870812),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.122537731979686102756),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0233458478275769288159),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00278170769163303669021),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.000159150281166108755531)
+ };
+ T t = z / 5 - 3;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+ }
+ else if(z <= 40)
+ {
+ // Maximum Deviation Found: 5.102e-18
+ // Expected Error Term: 5.101e-18
+ // Max Error found at double precision = Poly: 1.441088e-16 Cheb: 1.864792e-16
+
+
+ static const T Y = 1.03937530517578125F;
+ static const T P[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00356165148914447597995),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0229930320357982333406),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0449814350482277917716),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0453759383048193402336),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0272050837209380717069),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00994403059883350813295),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.00207592267812291726961),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.000192178045857733706044),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.113161784705911400295e-9)
+ };
+ static const T Q[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 2.84354408840148561131),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 3.6599610090072393012),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 2.75088464344293083595),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1.2985244073998398643),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.383213198510794507409),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.0651165455496281337831),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.00488071077519227853585)
+ };
+ T t = z / 10 - 3;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+ }
+ else
+ {
+ // Max Error found at double precision = 3.381886e-17
+ static const T exp40 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 53, 2.35385266837019985407899910749034804508871617254555467236651e17));
+ static const T Y= 1.013065338134765625F;
+ static const T P[6] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, -0.0130653381347656243849),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 0.19029710559486576682),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 94.7365094537197236011),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -2516.35323679844256203),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 18932.0850014925993025),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -38703.1431362056714134)
+ };
+ static const T Q[7] = {
+ BOOST_MATH_BIG_CONSTANT(T, 53, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 61.9733592849439884145),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -2354.56211323420194283),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 22329.1459489893079041),
+ BOOST_MATH_BIG_CONSTANT(T, 53, -70126.245140396567133),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 54738.2833147775537106),
+ BOOST_MATH_BIG_CONSTANT(T, 53, 8297.16296356518409347)
+ };
+ T t = 1 / z;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ if(z < 41)
+ result *= exp(z) / z;
+ else
+ {
+ // Avoid premature overflow if we can:
+ t = z - 40;
+ if(t > tools::log_max_value<T>())
+ {
+ result = policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else
+ {
+ result *= exp(z - 40) / z;
+ if(result > tools::max_value<T>() / exp40)
+ {
+ result = policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else
+ {
+ result *= exp40;
+ }
+ }
+ }
+ result += z;
+ }
+ return result;
+}
+
+template <class T, class Policy>
+T expint_i_imp(T z, const Policy& pol, const mpl::int_<64>& tag)
+{
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::expint<%1%>(%1%)";
+ if(z < 0)
+ return -expint_imp(1, T(-z), pol, tag);
+ if(z == 0)
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+
+ T result;
+
+ if(z <= 6)
+ {
+ // Maximum Deviation Found: 3.883e-21
+ // Expected Error Term: 3.883e-21
+ // Max Error found at long double precision = Poly: 3.344801e-19 Cheb: 4.989937e-19
+
+ static const T P[11] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 2.98677224343598593764),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.25891613550886736592),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.789323584998672832285),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.092432587824602399339),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0514236978728625906656),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00658477469745132977921),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00124914538197086254233),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000131429679565472408551),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.11293331317982763165e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.629499283139417444244e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.177833045143692498221e-7)
+ };
+ static const T Q[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -1.20352377969742325748),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.66707904942606479811),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.223014531629140771914),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0493340022262908008636),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00741934273050807310677),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00074353567782087939294),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.455861727069603367656e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.131515429329812837701e-5)
+ };
+
+ static const T c1 = BOOST_MATH_BIG_CONSTANT(T, 64, 1677624236387711.0);
+ static const T c2 = BOOST_MATH_BIG_CONSTANT(T, 64, 4503599627370496.0);
+ static const T r1 = c1 / c2;
+ static const T r2 = BOOST_MATH_BIG_CONSTANT(T, 64, 0.131401834143860282009280387409357165515556574352422001206362e-16);
+ static const T r = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.372507410781366634461991866580119133535689497771654051555657435242200120636201854384926049951548942392));
+ T t = (z / 3) - 1;
+ result = tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ t = (z - r1) - r2;
+ result *= t;
+ if(fabs(t) < 0.1)
+ {
+ result += boost::math::log1p(t / r);
+ }
+ else
+ {
+ result += log(z / r);
+ }
+ }
+ else if (z <= 10)
+ {
+ // Maximum Deviation Found: 2.622e-21
+ // Expected Error Term: -2.622e-21
+ // Max Error found at long double precision = Poly: 1.208328e-20 Cheb: 1.073723e-20
+
+ static const T Y = 1.158985137939453125F;
+ static const T P[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00139324086199409049399),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0345238388952337563247),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0382065278072592940767),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0156117003070560727392),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00383276012430495387102),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.000697070540945496497992),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.877310384591205930343e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.623067256376494930067e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.377246883283337141444e-6)
+ };
+ static const T Q[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.08073635708902053767),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.553681133533942532909),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.176763647137553797451),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0387891748253869928121),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0060603004848394727017),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000670519492939992806051),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.4947357050100855646e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.204339282037446434827e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.146951181174930425744e-7)
+ };
+ T t = z / 2 - 4;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+ }
+ else if(z <= 20)
+ {
+ // Maximum Deviation Found: 3.220e-20
+ // Expected Error Term: 3.220e-20
+ // Max Error found at long double precision = Poly: 7.696841e-20 Cheb: 6.205163e-20
+
+
+ static const T Y = 1.0869731903076171875F;
+ static const T P[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00893891094356946995368),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0487562980088748775943),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0670568657950041926085),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0509577352851442932713),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.02551800927409034206),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00892913759760086687083),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00224469630207344379888),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.000392477245911296982776),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.44424044184395578775e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.252788029251437017959e-5)
+ };
+ static const T Q[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 2.00323265503572414261),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.94688958187256383178),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.19733638134417472296),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.513137726038353385661),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.159135395578007264547),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0358233587351620919881),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0056716655597009417875),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000577048986213535829925),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.290976943033493216793e-4)
+ };
+ T t = z / 5 - 3;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+ }
+ else if(z <= 40)
+ {
+ // Maximum Deviation Found: 2.940e-21
+ // Expected Error Term: -2.938e-21
+ // Max Error found at long double precision = Poly: 3.419893e-19 Cheb: 3.359874e-19
+
+ static const T Y = 1.03937530517578125F;
+ static const T P[12] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00356165148914447278177),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0240235006148610849678),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0516699967278057976119),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0586603078706856245674),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0409960120868776180825),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0185485073689590665153),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00537842101034123222417),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.000920988084778273760609),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.716742618812210980263e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.504623302166487346677e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.712662196671896837736e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.533769629702262072175e-11)
+ };
+ static const T Q[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 3.13286733695729715455),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 4.49281223045653491929),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 3.84900294427622911374),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 2.15205199043580378211),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.802912186540269232424),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.194793170017818925388),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0280128013584653182994),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00182034930799902922549)
+ };
+ T t = z / 10 - 3;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result *= exp(z) / z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result += z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ }
+ else
+ {
+ // Maximum Deviation Found: 3.536e-20
+ // Max Error found at long double precision = Poly: 1.310671e-19 Cheb: 8.630943e-11
+
+ static const T exp40 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.35385266837019985407899910749034804508871617254555467236651e17));
+ static const T Y= 1.013065338134765625F;
+ static const T P[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0130653381347656250004),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.644487780349757303739),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 143.995670348227433964),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -13918.9322758014173709),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 476260.975133624194484),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -7437102.15135982802122),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 53732298.8764767916542),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -160695051.957997452509),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 137839271.592778020028)
+ };
+ static const T Q[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 27.2103343964943718802),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -8785.48528692879413676),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 397530.290000322626766),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -7356441.34957799368252),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 63050914.5343400957524),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -246143779.638307701369),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 384647824.678554961174),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -166288297.874583961493)
+ };
+ T t = 1 / z;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ if(z < 41)
+ result *= exp(z) / z;
+ else
+ {
+ // Avoid premature overflow if we can:
+ t = z - 40;
+ if(t > tools::log_max_value<T>())
+ {
+ result = policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else
+ {
+ result *= exp(z - 40) / z;
+ if(result > tools::max_value<T>() / exp40)
+ {
+ result = policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else
+ {
+ result *= exp40;
+ }
+ }
+ }
+ result += z;
+ }
+ return result;
+}
+
+template <class T>
+void expint_i_imp_113a(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 1.230e-36
+ // Expected Error Term: -1.230e-36
+ // Max Error found at long double precision = Poly: 4.355299e-34 Cheb: 7.512581e-34
+
+
+ static const T P[15] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.98677224343598593765287235997328555),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.333256034674702967028780537349334037),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.851831522798101228384971644036708463),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0657854833494646206186773614110374948),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0630065662557284456000060708977935073),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00311759191425309373327784154659649232),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00176213568201493949664478471656026771),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.491548660404172089488535218163952295e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.207764227621061706075562107748176592e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.225445398156913584846374273379402765e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.996939977231410319761273881672601592e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.212546902052178643330520878928100847e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.154646053060262871360159325115980023e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.143971277122049197323415503594302307e-11),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.306243138978114692252817805327426657e-13)
+ };
+ static const T Q[15] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -1.40178870313943798705491944989231793),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.943810968269701047641218856758605284),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.405026631534345064600850391026113165),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.123924153524614086482627660399122762),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0286364505373369439591132549624317707),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00516148845910606985396596845494015963),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000738330799456364820380739850924783649),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.843737760991856114061953265870882637e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.767957673431982543213661388914587589e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.549136847313854595809952100614840031e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.299801381513743676764008325949325404e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.118419479055346106118129130945423483e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.30372295663095470359211949045344607e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.382742953753485333207877784720070523e-12)
+ };
+
+ static const T c1 = BOOST_MATH_BIG_CONSTANT(T, 113, 1677624236387711.0);
+ static const T c2 = BOOST_MATH_BIG_CONSTANT(T, 113, 4503599627370496.0);
+ static const T c3 = BOOST_MATH_BIG_CONSTANT(T, 113, 266514582277687.0);
+ static const T c4 = BOOST_MATH_BIG_CONSTANT(T, 113, 4503599627370496.0);
+ static const T c5 = BOOST_MATH_BIG_CONSTANT(T, 113, 4503599627370496.0);
+ static const T r1 = c1 / c2;
+ static const T r2 = c3 / c4 / c5;
+ static const T r3 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.283806480836357377069325311780969887585024578164571984232357e-31));
+ static const T r = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.372507410781366634461991866580119133535689497771654051555657435242200120636201854384926049951548942392));
+ T t = (z / 3) - 1;
+ result = tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ t = ((z - r1) - r2) - r3;
+ result *= t;
+ if(fabs(t) < 0.1)
+ {
+ result += boost::math::log1p(t / r);
+ }
+ else
+ {
+ result += log(z / r);
+ }
+}
+
+template <class T>
+void expint_i_113b(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 7.779e-36
+ // Expected Error Term: -7.779e-36
+ // Max Error found at long double precision = Poly: 2.576723e-35 Cheb: 1.236001e-34
+
+ static const T Y = 1.158985137939453125F;
+ static const T P[15] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00139324086199409049282472239613554817),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0338173111691991289178779840307998955),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0555972290794371306259684845277620556),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0378677976003456171563136909186202177),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0152221583517528358782902783914356667),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00428283334203873035104248217403126905),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000922782631491644846511553601323435286),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000155513428088853161562660696055496696),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.205756580255359882813545261519317096e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.220327406578552089820753181821115181e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.189483157545587592043421445645377439e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.122426571518570587750898968123803867e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.635187358949437991465353268374523944e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.203015132965870311935118337194860863e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.384276705503357655108096065452950822e-12)
+ };
+ static const T Q[15] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.58784732785354597996617046880946257),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.18550755302279446339364262338114098),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.55598993549661368604527040349702836),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.184290888380564236919107835030984453),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0459658051803613282360464632326866113),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0089505064268613225167835599456014705),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00139042673882987693424772855926289077),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000174210708041584097450805790176479012),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.176324034009707558089086875136647376e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.142935845999505649273084545313710581e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.907502324487057260675816233312747784e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.431044337808893270797934621235918418e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.139007266881450521776529705677086902e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.234715286125516430792452741830364672e-11)
+ };
+ T t = z / 2 - 4;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+}
+
+template <class T>
+void expint_i_113c(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 1.082e-34
+ // Expected Error Term: 1.080e-34
+ // Max Error found at long double precision = Poly: 1.958294e-34 Cheb: 2.472261e-34
+
+
+ static const T Y = 1.091579437255859375F;
+ static const T P[17] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00685089599550151282724924894258520532),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0443313550253580053324487059748497467),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.071538561252424027443296958795814874),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0622923153354102682285444067843300583),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0361631270264607478205393775461208794),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0153192826839624850298106509601033261),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00496967904961260031539602977748408242),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00126989079663425780800919171538920589),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000258933143097125199914724875206326698),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.422110326689204794443002330541441956e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.546004547590412661451073996127115221e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.546775260262202177131068692199272241e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.404157632825805803833379568956559215e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.200612596196561323832327013027419284e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.502538501472133913417609379765434153e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.326283053716799774936661568391296584e-13),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.869226483473172853557775877908693647e-15)
+ };
+ static const T Q[15] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.23227220874479061894038229141871087),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.40221000361027971895657505660959863),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.65476320985936174728238416007084214),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.816828602963895720369875535001248227),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.306337922909446903672123418670921066),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0902400121654409267774593230720600752),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0212708882169429206498765100993228086),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00404442626252467471957713495828165491),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0006195601618842253612635241404054589),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.755930932686543009521454653994321843e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.716004532773778954193609582677482803e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.500881663076471627699290821742924233e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.233593219218823384508105943657387644e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.554900353169148897444104962034267682e-9)
+ };
+ T t = z / 4 - 3.5;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+}
+
+template <class T>
+void expint_i_113d(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 3.163e-35
+ // Expected Error Term: 3.163e-35
+ // Max Error found at long double precision = Poly: 4.158110e-35 Cheb: 5.385532e-35
+
+ static const T Y = 1.051731109619140625F;
+ static const T P[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00144552494420652573815404828020593565),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0126747451594545338365684731262912741),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.01757394877502366717526779263438073),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0126838952395506921945756139424722588),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0060045057928894974954756789352443522),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00205349237147226126653803455793107903),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000532606040579654887676082220195624207),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000107344687098019891474772069139014662),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.169536802705805811859089949943435152e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.20863311729206543881826553010120078e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.195670358542116256713560296776654385e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.133291168587253145439184028259772437e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.595500337089495614285777067722823397e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.133141358866324100955927979606981328e-10)
+ };
+ static const T Q[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.72490783907582654629537013560044682),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.44524329516800613088375685659759765),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.778241785539308257585068744978050181),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.300520486589206605184097270225725584),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0879346899691339661394537806057953957),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0200802415843802892793583043470125006),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00362842049172586254520256100538273214),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000519731362862955132062751246769469957),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.584092147914050999895178697392282665e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.501851497707855358002773398333542337e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.313085677467921096644895738538865537e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.127552010539733113371132321521204458e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.25737310826983451144405899970774587e-9)
+ };
+ T t = z / 4 - 5.5;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result *= exp(z) / z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result += z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+}
+
+template <class T>
+void expint_i_113e(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 7.972e-36
+ // Expected Error Term: 7.962e-36
+ // Max Error found at long double precision = Poly: 1.711721e-34 Cheb: 3.100018e-34
+
+ static const T Y = 1.032726287841796875F;
+ static const T P[15] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00141056919297307534690895009969373233),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0123384175302540291339020257071411437),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0298127270706864057791526083667396115),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0390686759471630584626293670260768098),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0338226792912607409822059922949035589),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0211659736179834946452561197559654582),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0100428887460879377373158821400070313),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00370717396015165148484022792801682932),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0010768667551001624764329000496561659),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000246127328761027039347584096573123531),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.437318110527818613580613051861991198e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.587532682329299591501065482317771497e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.565697065670893984610852937110819467e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.350233957364028523971768887437839573e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.105428907085424234504608142258423505e-8)
+ };
+ static const T Q[16] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 3.17261315255467581204685605414005525),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 4.85267952971640525245338392887217426),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 4.74341914912439861451492872946725151),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 3.31108463283559911602405970817931801),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.74657006336994649386607925179848899),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.718255607416072737965933040353653244),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.234037553177354542791975767960643864),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0607470145906491602476833515412605389),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0125048143774226921434854172947548724),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00201034366420433762935768458656609163),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000244823338417452367656368849303165721),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.213511655166983177960471085462540807e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.119323998465870686327170541547982932e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.322153582559488797803027773591727565e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.161635525318683508633792845159942312e-16)
+ };
+ T t = z / 8 - 4.25;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result *= exp(z) / z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result += z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+}
+
+template <class T>
+void expint_i_113f(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 4.469e-36
+ // Expected Error Term: 4.468e-36
+ // Max Error found at long double precision = Poly: 1.288958e-35 Cheb: 2.304586e-35
+
+ static const T Y = 1.0216197967529296875F;
+ static const T P[12] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000322999116096627043476023926572650045),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00385606067447365187909164609294113346),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00686514524727568176735949971985244415),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00606260649593050194602676772589601799),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00334382362017147544335054575436194357),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00126108534260253075708625583630318043),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000337881489347846058951220431209276776),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.648480902304640018785370650254018022e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.87652644082970492211455290209092766e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.794712243338068631557849449519994144e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.434084023639508143975983454830954835e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.107839681938752337160494412638656696e-8)
+ };
+ static const T Q[12] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.09913805456661084097134805151524958),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.07041755535439919593503171320431849),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.26406517226052371320416108604874734),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.529689923703770353961553223973435569),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.159578150879536711042269658656115746),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0351720877642000691155202082629857131),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00565313621289648752407123620997063122),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000646920278540515480093843570291218295),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.499904084850091676776993523323213591e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.233740058688179614344680531486267142e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.498800627828842754845418576305379469e-7)
+ };
+ T t = z / 7 - 7;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result *= exp(z) / z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result += z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+}
+
+template <class T>
+void expint_i_113g(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 5.588e-35
+ // Expected Error Term: -5.566e-35
+ // Max Error found at long double precision = Poly: 9.976345e-35 Cheb: 8.358865e-35
+
+ static const T Y = 1.015148162841796875F;
+ static const T P[11] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000435714784725086961464589957142615216),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00432114324353830636009453048419094314),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0100740363285526177522819204820582424),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0116744115827059174392383504427640362),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00816145387784261141360062395898644652),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00371380272673500791322744465394211508),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00112958263488611536502153195005736563),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000228316462389404645183269923754256664),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.29462181955852860250359064291292577e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.21972450610957417963227028788460299e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.720558173805289167524715527536874694e-7)
+ };
+ static const T Q[11] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 2.95918362458402597039366979529287095),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 3.96472247520659077944638411856748924),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 3.15563251550528513747923714884142131),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.64674612007093983894215359287448334),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.58695020129846594405856226787156424),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.144358385319329396231755457772362793),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.024146911506411684815134916238348063),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0026257132337460784266874572001650153),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000167479843750859222348869769094711093),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.475673638665358075556452220192497036e-5)
+ };
+ T t = z / 14 - 5;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result *= exp(z) / z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+ result += z;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result)
+}
+
+template <class T>
+void expint_i_113h(T& result, const T& z)
+{
+ BOOST_MATH_STD_USING
+ // Maximum Deviation Found: 4.448e-36
+ // Expected Error Term: 4.445e-36
+ // Max Error found at long double precision = Poly: 2.058532e-35 Cheb: 2.165465e-27
+
+ static const T Y= 1.00849151611328125F;
+ static const T P[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0084915161132812500000001440233607358),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.84479378737716028341394223076147872),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -130.431146923726715674081563022115568),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 4336.26945491571504885214176203512015),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -76279.0031974974730095170437591004177),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 729577.956271997673695191455111727774),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -3661928.69330208734947103004900349266),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 8570600.041606912735872059184527855),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -6758379.93672362080947905580906028645)
+ };
+ static const T Q[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -99.4868026047611434569541483506091713),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 3879.67753690517114249705089803055473),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -76495.82413252517165830203774900806),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 820773.726408311894342553758526282667),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -4803087.64956923577571031564909646579),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 14521246.227703545012713173740895477),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -19762752.0196769712258527849159393044),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 8354144.67882768405803322344185185517),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 355076.853106511136734454134915432571)
+ };
+ T t = 1 / z;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ result *= exp(z) / z;
+ result += z;
+}
+
+template <class T, class Policy>
+T expint_i_imp(T z, const Policy& pol, const mpl::int_<113>& tag)
+{
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::expint<%1%>(%1%)";
+ if(z < 0)
+ return -expint_imp(1, T(-z), pol, tag);
+ if(z == 0)
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+
+ T result;
+
+ if(z <= 6)
+ {
+ expint_i_imp_113a(result, z);
+ }
+ else if (z <= 10)
+ {
+ expint_i_113b(result, z);
+ }
+ else if(z <= 18)
+ {
+ expint_i_113c(result, z);
+ }
+ else if(z <= 26)
+ {
+ expint_i_113d(result, z);
+ }
+ else if(z <= 42)
+ {
+ expint_i_113e(result, z);
+ }
+ else if(z <= 56)
+ {
+ expint_i_113f(result, z);
+ }
+ else if(z <= 84)
+ {
+ expint_i_113g(result, z);
+ }
+ else if(z <= 210)
+ {
+ expint_i_113h(result, z);
+ }
+ else // z > 210
+ {
+ // Maximum Deviation Found: 3.963e-37
+ // Expected Error Term: 3.963e-37
+ // Max Error found at long double precision = Poly: 1.248049e-36 Cheb: 2.843486e-29
+
+ static const T exp40 = static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2.35385266837019985407899910749034804508871617254555467236651e17));
+ static const T Y= 1.00252532958984375F;
+ static const T P[8] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00252532958984375000000000000000000085),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.16591386866059087390621952073890359),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -67.8483431314018462417456828499277579),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1567.68688154683822956359536287575892),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -17335.4683325819116482498725687644986),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 93632.6567462673524739954389166550069),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -225025.189335919133214440347510936787),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 175864.614717440010942804684741336853)
+ };
+ static const T Q[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -65.6998869881600212224652719706425129),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1642.73850032324014781607859416890077),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -19937.2610222467322481947237312818575),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 124136.267326632742667972126625064538),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -384614.251466704550678760562965502293),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 523355.035910385688578278384032026998),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -217809.552260834025885677791936351294),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -8555.81719551123640677261226549550872)
+ };
+ T t = 1 / z;
+ result = Y + tools::evaluate_polynomial(P, t)
+ / tools::evaluate_polynomial(Q, t);
+ if(z < 41)
+ result *= exp(z) / z;
+ else
+ {
+ // Avoid premature overflow if we can:
+ t = z - 40;
+ if(t > tools::log_max_value<T>())
+ {
+ result = policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else
+ {
+ result *= exp(z - 40) / z;
+ if(result > tools::max_value<T>() / exp40)
+ {
+ result = policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ else
+ {
+ result *= exp40;
+ }
+ }
+ }
+ result += z;
+ }
+ return result;
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ expint_forwarder(T z, const Policy& /*pol*/, mpl::true_ const&)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::precision<result_type, Policy>::type precision_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ typedef typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>, // double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>, // 80-bit long double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<113>, // 128-bit long double
+ mpl::int_<0> // too many bits, use generic version.
+ >::type
+ >::type
+ >::type
+ >::type tag_type;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::expint_i_imp(
+ static_cast<value_type>(z),
+ forwarding_policy(),
+ tag_type()), "boost::math::expint<%1%>(%1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+expint_forwarder(unsigned n, T z, const mpl::false_&)
+{
+ return boost::math::expint(n, z, policies::policy<>());
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ expint(unsigned n, T z, 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_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>, // double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>, // 80-bit long double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<113>, // 128-bit long double
+ mpl::int_<0> // too many bits, use generic version.
+ >::type
+ >::type
+ >::type
+ >::type tag_type;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::expint_imp(
+ n,
+ static_cast<value_type>(z),
+ forwarding_policy(),
+ tag_type()), "boost::math::expint<%1%>(unsigned, %1%)");
+}
+
+template <class T, class U>
+inline typename detail::expint_result<T, U>::type
+ expint(T const z, U const u)
+{
+ typedef typename policies::is_policy<U>::type tag_type;
+ return detail::expint_forwarder(z, u, tag_type());
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ expint(T z)
+{
+ return expint(z, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_EXPINT_HPP
+
+
diff --git a/boost/math/special_functions/expm1.hpp b/boost/math/special_functions/expm1.hpp
new file mode 100644
index 0000000000..345220fcee
--- /dev/null
+++ b/boost/math/special_functions/expm1.hpp
@@ -0,0 +1,344 @@
+// (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, bool b = boost::is_pod<T>::value>
+struct expm1_init_on_startup
+{
+ struct init
+ {
+ init()
+ {
+ boost::math::expm1(T(0.5f));
+ }
+ void do_nothing()const{}
+ };
+
+ static void do_nothing()
+ {
+ initializer.do_nothing();
+ }
+
+ static const init initializer;
+};
+
+template <class T, bool b>
+const typename expm1_init_on_startup<T, b>::init expm1_init_on_startup<T, b>::initializer;
+
+template <class T>
+struct expm1_init_on_startup<T, true>
+{
+ static void do_nothing(){}
+};
+//
+// Algorithm expm1 is part of C99, but is not yet provided by many compilers.
+//
+// This version uses a Taylor series expansion for 0.5 > |x| > epsilon.
+//
+template <class T, class Policy>
+T expm1_imp(T x, const mpl::int_<0>&, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ T a = fabs(x);
+ if(a > T(0.5f))
+ {
+ if(a >= tools::log_max_value<T>())
+ {
+ if(x > 0)
+ return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", 0, pol);
+ return -1;
+ }
+ return exp(x) - T(1);
+ }
+ if(a < tools::epsilon<T>())
+ return x;
+ detail::expm1_series<T> s(x);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) && !BOOST_WORKAROUND(__EDG_VERSION__, <= 245)
+ T result = tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter);
+#else
+ T zero = 0;
+ T result = tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter, zero);
+#endif
+ policies::check_series_iterations<T>("boost::math::expm1<%1%>(%1%)", max_iter, pol);
+ return result;
+}
+
+template <class T, class P>
+T expm1_imp(T x, const mpl::int_<53>&, const P& pol)
+{
+ BOOST_MATH_STD_USING
+
+ expm1_init_on_startup<T>::do_nothing();
+
+ T a = fabs(x);
+ if(a > T(0.5L))
+ {
+ if(a >= tools::log_max_value<T>())
+ {
+ if(x > 0)
+ return policies::raise_overflow_error<T>("boost::math::expm1<%1%>(%1%)", 0, pol);
+ return -1;
+ }
+ return exp(x) - T(1);
+ }
+ if(a < tools::epsilon<T>())
+ return x;
+
+ static const float Y = 0.10281276702880859e1f;
+ static const T n[] = { -0.28127670288085937e-1, 0.51278186299064534e0, -0.6310029069350198e-1, 0.11638457975729296e-1, -0.52143390687521003e-3, 0.21491399776965688e-4 };
+ static const T d[] = { 1, -0.45442309511354755e0, 0.90850389570911714e-1, -0.10088963629815502e-1, 0.63003407478692265e-3, -0.17976570003654402e-4 };
+
+ T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
+ return result;
+}
+
+template <class T, class P>
+T expm1_imp(T x, const mpl::int_<64>&, const P& pol)
+{
+ BOOST_MATH_STD_USING
+
+ expm1_init_on_startup<T>::do_nothing();
+
+ 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[] = {
+ 1,
+ 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
+
+ expm1_init_on_startup<T>::do_nothing();
+
+ 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[] = {
+ 1,
+ 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::expm1_imp(
+ static_cast<value_type>(x),
+ tag_type(), forwarding_policy()), "boost::math::expm1<%1%>(%1%)");
+}
+
+#ifdef expm1
+# ifndef BOOST_HAS_expm1
+# define BOOST_HAS_expm1
+# endif
+# undef expm1
+#endif
+
+#if defined(BOOST_HAS_EXPM1) && !(defined(__osf__) && defined(__DECCXX_VER))
+# ifdef BOOST_MATH_USE_C99
+inline float expm1(float x, const policies::policy<>&){ return ::expm1f(x); }
+# ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+inline long double expm1(long double x, const policies::policy<>&){ return ::expm1l(x); }
+# endif
+# else
+inline float expm1(float x, const policies::policy<>&){ return ::expm1(x); }
+# endif
+inline double expm1(double x, const policies::policy<>&){ return ::expm1(x); }
+#endif
+
+template <class T>
+inline typename tools::promote_args<T>::type expm1(T x)
+{
+ return expm1(x, policies::policy<>());
+}
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+inline float expm1(float z)
+{
+ return expm1<float>(z);
+}
+inline double expm1(double z)
+{
+ return expm1<double>(z);
+}
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+inline long double expm1(long double z)
+{
+ return expm1<long double>(z);
+}
+#endif
+#endif
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_HYPOT_INCLUDED
+
+
+
+
diff --git a/boost/math/special_functions/factorials.hpp b/boost/math/special_functions/factorials.hpp
new file mode 100644
index 0000000000..f57147ebfa
--- /dev/null
+++ b/boost/math/special_functions/factorials.hpp
@@ -0,0 +1,240 @@
+// Copyright John Maddock 2006, 2010.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SP_FACTORIALS_HPP
+#define BOOST_MATH_SP_FACTORIALS_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/gamma.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/detail/unchecked_factorial.hpp>
+#include <boost/array.hpp>
+#ifdef BOOST_MSVC
+#pragma warning(push) // Temporary until lexical cast fixed.
+#pragma warning(disable: 4127 4701)
+#endif
+#include <boost/lexical_cast.hpp>
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+#include <boost/config/no_tr1/cmath.hpp>
+
+namespace boost { namespace math
+{
+
+template <class T, class Policy>
+inline T factorial(unsigned i, const Policy& pol)
+{
+ BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
+ // factorial<unsigned int>(n) is not implemented
+ // because it would overflow integral type T for too small n
+ // to be useful. Use instead a floating-point type,
+ // and convert to an unsigned type if essential, for example:
+ // unsigned int nfac = static_cast<unsigned int>(factorial<double>(n));
+ // See factorial documentation for more detail.
+
+ BOOST_MATH_STD_USING // Aid ADL for floor.
+
+ if(i <= max_factorial<T>::value)
+ return unchecked_factorial<T>(i);
+ T result = boost::math::tgamma(static_cast<T>(i+1), pol);
+ if(result > tools::max_value<T>())
+ return result; // Overflowed value! (But tgamma will have signalled the error already).
+ return floor(result + 0.5f);
+}
+
+template <class T>
+inline T factorial(unsigned i)
+{
+ return factorial<T>(i, policies::policy<>());
+}
+/*
+// Can't have these in a policy enabled world?
+template<>
+inline float factorial<float>(unsigned i)
+{
+ if(i <= max_factorial<float>::value)
+ return unchecked_factorial<float>(i);
+ return tools::overflow_error<float>(BOOST_CURRENT_FUNCTION);
+}
+
+template<>
+inline double factorial<double>(unsigned i)
+{
+ if(i <= max_factorial<double>::value)
+ return unchecked_factorial<double>(i);
+ return tools::overflow_error<double>(BOOST_CURRENT_FUNCTION);
+}
+*/
+template <class T, class Policy>
+T double_factorial(unsigned i, const Policy& pol)
+{
+ BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
+ BOOST_MATH_STD_USING // ADL lookup of std names
+ if(i & 1)
+ {
+ // odd i:
+ if(i < max_factorial<T>::value)
+ {
+ unsigned n = (i - 1) / 2;
+ return ceil(unchecked_factorial<T>(i) / (ldexp(T(1), (int)n) * unchecked_factorial<T>(n)) - 0.5f);
+ }
+ //
+ // Fallthrough: i is too large to use table lookup, try the
+ // gamma function instead.
+ //
+ T result = boost::math::tgamma(static_cast<T>(i) / 2 + 1, pol) / sqrt(constants::pi<T>());
+ if(ldexp(tools::max_value<T>(), -static_cast<int>(i+1) / 2) > result)
+ return ceil(result * ldexp(T(1), static_cast<int>(i+1) / 2) - 0.5f);
+ }
+ else
+ {
+ // even i:
+ unsigned n = i / 2;
+ T result = factorial<T>(n, pol);
+ if(ldexp(tools::max_value<T>(), -(int)n) > result)
+ return result * ldexp(T(1), (int)n);
+ }
+ //
+ // If we fall through to here then the result is infinite:
+ //
+ return policies::raise_overflow_error<T>("boost::math::double_factorial<%1%>(unsigned)", 0, pol);
+}
+
+template <class T>
+inline T double_factorial(unsigned i)
+{
+ return double_factorial<T>(i, policies::policy<>());
+}
+
+namespace detail{
+
+template <class T, class Policy>
+T rising_factorial_imp(T x, int n, const Policy& pol)
+{
+ BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
+ if(x < 0)
+ {
+ //
+ // For x less than zero, we really have a falling
+ // factorial, modulo a possible change of sign.
+ //
+ // Note that the falling factorial isn't defined
+ // for negative n, so we'll get rid of that case
+ // first:
+ //
+ bool inv = false;
+ if(n < 0)
+ {
+ x += n;
+ n = -n;
+ inv = true;
+ }
+ T result = ((n&1) ? -1 : 1) * falling_factorial(-x, n, pol);
+ if(inv)
+ result = 1 / result;
+ return result;
+ }
+ if(n == 0)
+ return 1;
+ //
+ // We don't optimise this for small n, because
+ // tgamma_delta_ratio is alreay optimised for that
+ // use case:
+ //
+ return 1 / boost::math::tgamma_delta_ratio(x, static_cast<T>(n), pol);
+}
+
+template <class T, class Policy>
+inline T falling_factorial_imp(T x, unsigned n, const Policy& pol)
+{
+ BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
+ BOOST_MATH_STD_USING // ADL of std names
+ if(x == 0)
+ return 0;
+ if(x < 0)
+ {
+ //
+ // For x < 0 we really have a rising factorial
+ // modulo a possible change of sign:
+ //
+ return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol);
+ }
+ if(n == 0)
+ return 1;
+ if(x < n-1)
+ {
+ //
+ // x+1-n will be negative and tgamma_delta_ratio won't
+ // handle it, split the product up into three parts:
+ //
+ T xp1 = x + 1;
+ unsigned n2 = itrunc((T)floor(xp1), pol);
+ if(n2 == xp1)
+ return 0;
+ T result = boost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol);
+ x -= n2;
+ result *= x;
+ ++n2;
+ if(n2 < n)
+ result *= falling_factorial(x - 1, n - n2, pol);
+ return result;
+ }
+ //
+ // Simple case: just the ratio of two
+ // (positive argument) gamma functions.
+ // Note that we don't optimise this for small n,
+ // because tgamma_delta_ratio is alreay optimised
+ // for that use case:
+ //
+ return boost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol);
+}
+
+} // namespace detail
+
+template <class RT>
+inline typename tools::promote_args<RT>::type
+ falling_factorial(RT x, unsigned n)
+{
+ typedef typename tools::promote_args<RT>::type result_type;
+ return detail::falling_factorial_imp(
+ static_cast<result_type>(x), n, policies::policy<>());
+}
+
+template <class RT, class Policy>
+inline typename tools::promote_args<RT>::type
+ falling_factorial(RT x, unsigned n, const Policy& pol)
+{
+ typedef typename tools::promote_args<RT>::type result_type;
+ return detail::falling_factorial_imp(
+ static_cast<result_type>(x), n, pol);
+}
+
+template <class RT>
+inline typename tools::promote_args<RT>::type
+ rising_factorial(RT x, int n)
+{
+ typedef typename tools::promote_args<RT>::type result_type;
+ return detail::rising_factorial_imp(
+ static_cast<result_type>(x), n, policies::policy<>());
+}
+
+template <class RT, class Policy>
+inline typename tools::promote_args<RT>::type
+ rising_factorial(RT x, int n, const Policy& pol)
+{
+ typedef typename tools::promote_args<RT>::type result_type;
+ return detail::rising_factorial_imp(
+ static_cast<result_type>(x), n, pol);
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SP_FACTORIALS_HPP
+
diff --git a/boost/math/special_functions/fpclassify.hpp b/boost/math/special_functions/fpclassify.hpp
new file mode 100644
index 0000000000..2abec5fa84
--- /dev/null
+++ b/boost/math/special_functions/fpclassify.hpp
@@ -0,0 +1,533 @@
+// Copyright John Maddock 2005-2008.
+// Copyright (c) 2006-2008 Johan Rade
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_FPCLASSIFY_HPP
+#define BOOST_MATH_FPCLASSIFY_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <math.h>
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/limits.hpp>
+#include <boost/math/tools/real_cast.hpp>
+#include <boost/type_traits/is_floating_point.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/detail/fp_traits.hpp>
+/*!
+ \file fpclassify.hpp
+ \brief Classify floating-point value as normal, subnormal, zero, infinite, or NaN.
+ \version 1.0
+ \author John Maddock
+ */
+
+/*
+
+1. If the platform is C99 compliant, then the native floating point
+classification functions are used. However, note that we must only
+define the functions which call std::fpclassify etc if that function
+really does exist: otherwise a compiler may reject the code even though
+the template is never instantiated.
+
+2. If the platform is not C99 compliant, and the binary format for
+a floating point type (float, double or long double) can be determined
+at compile time, then the following algorithm is used:
+
+ If all exponent bits, the flag bit (if there is one),
+ and all significand bits are 0, then the number is zero.
+
+ If all exponent bits and the flag bit (if there is one) are 0,
+ and at least one significand bit is 1, then the number is subnormal.
+
+ If all exponent bits are 1 and all significand bits are 0,
+ then the number is infinity.
+
+ If all exponent bits are 1 and at least one significand bit is 1,
+ then the number is a not-a-number.
+
+ Otherwise the number is normal.
+
+ This algorithm works for the IEEE 754 representation,
+ and also for several non IEEE 754 formats.
+
+ Most formats have the structure
+ sign bit + exponent bits + significand bits.
+
+ A few have the structure
+ sign bit + exponent bits + flag bit + significand bits.
+ The flag bit is 0 for zero and subnormal numbers,
+ and 1 for normal numbers and NaN.
+ It is 0 (Motorola 68K) or 1 (Intel) for infinity.
+
+ To get the bits, the four or eight most significant bytes are copied
+ into an uint32_t or uint64_t and bit masks are applied.
+ This covers all the exponent bits and the flag bit (if there is one),
+ but not always all the significand bits.
+ Some of the functions below have two implementations,
+ depending on whether all the significand bits are copied or not.
+
+3. If the platform is not C99 compliant, and the binary format for
+a floating point type (float, double or long double) can not be determined
+at compile time, then comparison with std::numeric_limits values
+is used.
+
+*/
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#include <float.h>
+#endif
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+ namespace std{ using ::abs; using ::fabs; }
+#endif
+
+namespace boost{
+
+//
+// This must not be located in any namespace under boost::math
+// otherwise we can get into an infinite loop if isnan is
+// a #define for "isnan" !
+//
+namespace math_detail{
+
+template <class T>
+inline bool is_nan_helper(T t, const boost::true_type&)
+{
+#ifdef isnan
+ return isnan(t);
+#elif defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY) || !defined(BOOST_HAS_FPCLASSIFY)
+ return false;
+#else // BOOST_HAS_FPCLASSIFY
+ return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == (int)FP_NAN);
+#endif
+}
+
+template <class T>
+inline bool is_nan_helper(T, const boost::false_type&)
+{
+ return false;
+}
+
+}
+
+namespace math{
+
+namespace detail{
+
+#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
+template <class T>
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const native_tag&)
+{
+ return (std::fpclassify)(t);
+}
+#endif
+
+template <class T>
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<true>&)
+{
+ BOOST_MATH_INSTRUMENT_VARIABLE(t);
+
+ // whenever possible check for Nan's first:
+#if defined(BOOST_HAS_FPCLASSIFY) && !defined(BOOST_MATH_DISABLE_STD_FPCLASSIFY)
+ if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
+ return FP_NAN;
+#elif defined(isnan)
+ if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
+ return FP_NAN;
+#elif defined(_MSC_VER) || defined(__BORLANDC__)
+ if(::_isnan(boost::math::tools::real_cast<double>(t)))
+ return FP_NAN;
+#endif
+ // std::fabs broken on a few systems especially for long long!!!!
+ T at = (t < T(0)) ? -t : t;
+
+ // Use a process of exclusion to figure out
+ // what kind of type we have, this relies on
+ // IEEE conforming reals that will treat
+ // Nan's as unordered. Some compilers
+ // don't do this once optimisations are
+ // turned on, hence the check for nan's above.
+ if(at <= (std::numeric_limits<T>::max)())
+ {
+ if(at >= (std::numeric_limits<T>::min)())
+ return FP_NORMAL;
+ return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
+ }
+ else if(at > (std::numeric_limits<T>::max)())
+ return FP_INFINITE;
+ return FP_NAN;
+}
+
+template <class T>
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const generic_tag<false>&)
+{
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return 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)
+template <>
+inline int fpclassify_imp<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
+{
+ return boost::math::detail::fpclassify_imp(t, generic_tag<true>());
+}
+#endif
+
+} // namespace detail
+
+template <class T>
+inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized && detail::is_generic_tag_false(static_cast<method*>(0)))
+ return detail::fpclassify_imp(t, detail::generic_tag<true>());
+ return detail::fpclassify_imp(t, method());
+#else
+ return detail::fpclassify_imp(t, method());
+#endif
+}
+
+namespace detail {
+
+#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
+ template<class T>
+ inline bool isfinite_impl(T x, native_tag const&)
+ {
+ return (std::isfinite)(x);
+ }
+#endif
+
+ template<class T>
+ inline bool isfinite_impl(T x, generic_tag<true> const&)
+ {
+ return x >= -(std::numeric_limits<T>::max)()
+ && x <= (std::numeric_limits<T>::max)();
+ }
+
+ template<class T>
+ inline bool isfinite_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isfinite_impl(x, generic_tag<true>());
+#endif
+ (void)x; // warning supression.
+ return true;
+ }
+
+ template<class T>
+ inline bool isfinite_impl(T x, ieee_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME detail::fp_traits<T>::type traits;
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent;
+ return a != traits::exponent;
+ }
+
+#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
+template <>
+inline bool isfinite_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
+{
+ return boost::math::detail::isfinite_impl(t, generic_tag<true>());
+}
+#endif
+
+}
+
+template<class T>
+inline bool (isfinite)(T x)
+{ //!< \brief return true if floating-point type t is finite.
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isfinite_impl(x, method());
+}
+
+//------------------------------------------------------------------------------
+
+namespace detail {
+
+#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
+ template<class T>
+ inline bool isnormal_impl(T x, native_tag const&)
+ {
+ return (std::isnormal)(x);
+ }
+#endif
+
+ template<class T>
+ inline bool isnormal_impl(T x, generic_tag<true> const&)
+ {
+ if(x < 0) x = -x;
+ return x >= (std::numeric_limits<T>::min)()
+ && x <= (std::numeric_limits<T>::max)();
+ }
+
+ template<class T>
+ inline bool isnormal_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isnormal_impl(x, 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)
+template <>
+inline bool isnormal_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
+{
+ return boost::math::detail::isnormal_impl(t, generic_tag<true>());
+}
+#endif
+
+}
+
+template<class T>
+inline bool (isnormal)(T x)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isnormal_impl(x, method());
+}
+
+//------------------------------------------------------------------------------
+
+namespace detail {
+
+#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
+ template<class T>
+ inline bool isinf_impl(T x, native_tag const&)
+ {
+ return (std::isinf)(x);
+ }
+#endif
+
+ template<class T>
+ inline bool isinf_impl(T x, generic_tag<true> const&)
+ {
+ (void)x; // in case the compiler thinks that x is unused because std::numeric_limits<T>::has_infinity is false
+ return std::numeric_limits<T>::has_infinity
+ && ( x == std::numeric_limits<T>::infinity()
+ || x == -std::numeric_limits<T>::infinity());
+ }
+
+ template<class T>
+ inline bool isinf_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isinf_impl(x, generic_tag<true>());
+#endif
+ (void)x; // warning supression.
+ return false;
+ }
+
+ template<class T>
+ inline bool isinf_impl(T x, ieee_copy_all_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::significand;
+ return a == traits::exponent;
+ }
+
+ template<class T>
+ inline bool isinf_impl(T x, ieee_copy_leading_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::significand;
+ if(a != traits::exponent)
+ return false;
+
+ traits::set_bits(x,0);
+ return x == 0;
+ }
+
+#if defined(BOOST_MATH_USE_STD_FPCLASSIFY) && defined(BOOST_MATH_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
+template <>
+inline bool isinf_impl<long double> BOOST_NO_MACRO_EXPAND(long double t, const native_tag&)
+{
+ return boost::math::detail::isinf_impl(t, generic_tag<true>());
+}
+#endif
+
+} // namespace detail
+
+template<class T>
+inline bool (isinf)(T x)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isinf_impl(x, method());
+}
+
+//------------------------------------------------------------------------------
+
+namespace detail {
+
+#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
+ template<class T>
+ inline bool isnan_impl(T x, native_tag const&)
+ {
+ return (std::isnan)(x);
+ }
+#endif
+
+ template<class T>
+ inline bool isnan_impl(T x, generic_tag<true> const&)
+ {
+ return std::numeric_limits<T>::has_infinity
+ ? !(x <= std::numeric_limits<T>::infinity())
+ : x != x;
+ }
+
+ template<class T>
+ inline bool isnan_impl(T x, generic_tag<false> const&)
+ {
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return isnan_impl(x, generic_tag<true>());
+#endif
+ (void)x; // warning supression
+ return false;
+ }
+
+ template<class T>
+ inline bool isnan_impl(T x, ieee_copy_all_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a &= traits::exponent | traits::significand;
+ return a > traits::exponent;
+ }
+
+ template<class T>
+ inline bool isnan_impl(T x, ieee_copy_leading_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+
+ a &= traits::exponent | traits::significand;
+ if(a < traits::exponent)
+ return false;
+
+ a &= traits::significand;
+ traits::set_bits(x,a);
+ return x != 0;
+ }
+
+} // namespace detail
+
+template<class T> bool (isnan)(T x)
+{ //!< \brief return true if floating-point type t is NaN (Not A Number).
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::isnan_impl(x, method());
+}
+
+#ifdef isnan
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
+#endif
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_FPCLASSIFY_HPP
+
diff --git a/boost/math/special_functions/gamma.hpp b/boost/math/special_functions/gamma.hpp
new file mode 100644
index 0000000000..1ae965f18c
--- /dev/null
+++ b/boost/math/special_functions/gamma.hpp
@@ -0,0 +1,1551 @@
+
+// Copyright John Maddock 2006-7.
+// 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_GAMMA_HPP
+#define BOOST_MATH_SF_GAMMA_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/config.hpp>
+#ifdef BOOST_MSVC
+# pragma warning(push)
+# pragma warning(disable: 4127 4701)
+// // For lexical_cast, until fixed in 1.35?
+// // conditional expression is constant &
+// // Potentially uninitialized local variable 'name' used
+#endif
+#include <boost/lexical_cast.hpp>
+#ifdef BOOST_MSVC
+# pragma warning(pop)
+#endif
+#include <boost/math/tools/series.hpp>
+#include <boost/math/tools/fraction.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <boost/math/special_functions/powm1.hpp>
+#include <boost/math/special_functions/sqrt1pm1.hpp>
+#include <boost/math/special_functions/lanczos.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/detail/igamma_large.hpp>
+#include <boost/math/special_functions/detail/unchecked_factorial.hpp>
+#include <boost/math/special_functions/detail/lgamma_small.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/assert.hpp>
+#include <boost/mpl/greater.hpp>
+#include <boost/mpl/equal_to.hpp>
+#include <boost/mpl/greater.hpp>
+
+#include <boost/config/no_tr1/cmath.hpp>
+#include <algorithm>
+
+#ifdef BOOST_MATH_INSTRUMENT
+#include <iostream>
+#include <iomanip>
+#include <typeinfo>
+#endif
+
+#ifdef BOOST_MSVC
+# pragma warning(push)
+# pragma warning(disable: 4702) // unreachable code (return after domain_error throw).
+# pragma warning(disable: 4127) // conditional expression is constant.
+# pragma warning(disable: 4100) // unreferenced formal parameter.
+// Several variables made comments,
+// but some difficulty as whether referenced on not may depend on macro values.
+// So to be safe, 4100 warnings suppressed.
+// TODO - revisit this?
+#endif
+
+namespace boost{ namespace math{
+
+namespace detail{
+
+template <class T>
+inline bool is_odd(T v, const boost::true_type&)
+{
+ int i = static_cast<int>(v);
+ return i&1;
+}
+template <class T>
+inline bool is_odd(T v, const boost::false_type&)
+{
+ // Oh dear can't cast T to int!
+ BOOST_MATH_STD_USING
+ T modulus = v - 2 * floor(v/2);
+ return static_cast<bool>(modulus != 0);
+}
+template <class T>
+inline bool is_odd(T v)
+{
+ return is_odd(v, ::boost::is_convertible<T, int>());
+}
+
+template <class T>
+T sinpx(T z)
+{
+ // Ad hoc function calculates x * sin(pi * x),
+ // taking extra care near when x is near a whole number.
+ BOOST_MATH_STD_USING
+ int sign = 1;
+ if(z < 0)
+ {
+ z = -z;
+ }
+ else
+ {
+ sign = -sign;
+ }
+ T fl = floor(z);
+ T dist;
+ if(is_odd(fl))
+ {
+ fl += 1;
+ dist = fl - z;
+ sign = -sign;
+ }
+ else
+ {
+ dist = z - fl;
+ }
+ BOOST_ASSERT(fl >= 0);
+ if(dist > 0.5)
+ dist = 1 - dist;
+ T result = sin(dist*boost::math::constants::pi<T>());
+ return sign*z*result;
+} // template <class T> T sinpx(T z)
+//
+// tgamma(z), with Lanczos support:
+//
+template <class T, class Policy, class Lanczos>
+T gamma_imp(T z, const Policy& pol, const Lanczos& l)
+{
+ BOOST_MATH_STD_USING
+
+ T result = 1;
+
+#ifdef BOOST_MATH_INSTRUMENT
+ static bool b = false;
+ if(!b)
+ {
+ std::cout << "tgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl;
+ b = true;
+ }
+#endif
+ static const char* function = "boost::math::tgamma<%1%>(%1%)";
+
+ if(z <= 0)
+ {
+ if(floor(z) == z)
+ return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
+ if(z <= -20)
+ {
+ result = gamma_imp(T(-z), pol, l) * sinpx(z);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ if((fabs(result) < 1) && (tools::max_value<T>() * fabs(result) < boost::math::constants::pi<T>()))
+ return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
+ result = -boost::math::constants::pi<T>() / result;
+ if(result == 0)
+ return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
+ if((boost::math::fpclassify)(result) == (int)FP_SUBNORMAL)
+ return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", result, pol);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ return result;
+ }
+
+ // shift z to > 1:
+ while(z < 0)
+ {
+ result /= z;
+ z += 1;
+ }
+ }
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ if((floor(z) == z) && (z < max_factorial<T>::value))
+ {
+ result *= unchecked_factorial<T>(itrunc(z, pol) - 1);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ result *= Lanczos::lanczos_sum(z);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ BOOST_MATH_INSTRUMENT_VARIABLE(tools::log_max_value<T>());
+ if(z * log(z) > tools::log_max_value<T>())
+ {
+ // we're going to overflow unless this is done with care:
+ T zgh = (z + static_cast<T>(Lanczos::g()) - boost::math::constants::half<T>());
+ BOOST_MATH_INSTRUMENT_VARIABLE(zgh);
+ if(log(zgh) * z / 2 > tools::log_max_value<T>())
+ return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
+ T hp = pow(zgh, (z / 2) - T(0.25));
+ BOOST_MATH_INSTRUMENT_VARIABLE(hp);
+ result *= hp / exp(zgh);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ if(tools::max_value<T>() / hp < result)
+ return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
+ result *= hp;
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ else
+ {
+ T zgh = (z + static_cast<T>(Lanczos::g()) - boost::math::constants::half<T>());
+ BOOST_MATH_INSTRUMENT_VARIABLE(zgh);
+ BOOST_MATH_INSTRUMENT_VARIABLE(pow(zgh, z - boost::math::constants::half<T>()));
+ BOOST_MATH_INSTRUMENT_VARIABLE(exp(zgh));
+ result *= pow(zgh, z - boost::math::constants::half<T>()) / exp(zgh);
+ BOOST_MATH_INSTRUMENT_VARIABLE(result);
+ }
+ }
+ return result;
+}
+//
+// lgamma(z) with Lanczos support:
+//
+template <class T, class Policy, class Lanczos>
+T lgamma_imp(T z, const Policy& pol, const Lanczos& l, int* sign = 0)
+{
+#ifdef BOOST_MATH_INSTRUMENT
+ static bool b = false;
+ if(!b)
+ {
+ std::cout << "lgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl;
+ b = true;
+ }
+#endif
+
+ BOOST_MATH_STD_USING
+
+ static const char* function = "boost::math::lgamma<%1%>(%1%)";
+
+ T result = 0;
+ int sresult = 1;
+ if(z <= 0)
+ {
+ // reflection formula:
+ if(floor(z) == z)
+ return policies::raise_pole_error<T>(function, "Evaluation of lgamma at a negative integer %1%.", z, pol);
+
+ T t = sinpx(z);
+ z = -z;
+ if(t < 0)
+ {
+ t = -t;
+ }
+ else
+ {
+ sresult = -sresult;
+ }
+ result = log(boost::math::constants::pi<T>()) - lgamma_imp(z, pol, l) - log(t);
+ }
+ else if(z < 15)
+ {
+ typedef typename policies::precision<T, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::and_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::greater<precision_type, mpl::int_<0> >
+ >,
+ mpl::int_<64>,
+ typename mpl::if_<
+ mpl::and_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::greater<precision_type, mpl::int_<0> >
+ >,
+ mpl::int_<113>, mpl::int_<0> >::type
+ >::type tag_type;
+ result = lgamma_small_imp<T>(z, T(z - 1), T(z - 2), tag_type(), pol, l);
+ }
+ else if((z >= 3) && (z < 100))
+ {
+ // taking the log of tgamma reduces the error, no danger of overflow here:
+ result = log(gamma_imp(z, pol, l));
+ }
+ else
+ {
+ // regular evaluation:
+ T zgh = static_cast<T>(z + Lanczos::g() - boost::math::constants::half<T>());
+ result = log(zgh) - 1;
+ result *= z - 0.5f;
+ result += log(Lanczos::lanczos_sum_expG_scaled(z));
+ }
+
+ if(sign)
+ *sign = sresult;
+ return result;
+}
+
+//
+// Incomplete gamma functions follow:
+//
+template <class T>
+struct upper_incomplete_gamma_fract
+{
+private:
+ T z, a;
+ int k;
+public:
+ typedef std::pair<T,T> result_type;
+
+ upper_incomplete_gamma_fract(T a1, T z1)
+ : z(z1-a1+1), a(a1), k(0)
+ {
+ }
+
+ result_type operator()()
+ {
+ ++k;
+ z += 2;
+ return result_type(k * (a - k), z);
+ }
+};
+
+template <class T>
+inline T upper_gamma_fraction(T a, T z, T eps)
+{
+ // Multiply result by z^a * e^-z to get the full
+ // upper incomplete integral. Divide by tgamma(z)
+ // to normalise.
+ upper_incomplete_gamma_fract<T> f(a, z);
+ return 1 / (z - a + 1 + boost::math::tools::continued_fraction_a(f, eps));
+}
+
+template <class T>
+struct lower_incomplete_gamma_series
+{
+private:
+ T a, z, result;
+public:
+ typedef T result_type;
+ lower_incomplete_gamma_series(T a1, T z1) : a(a1), z(z1), result(1){}
+
+ T operator()()
+ {
+ T r = result;
+ a += 1;
+ result *= z/a;
+ return r;
+ }
+};
+
+template <class T, class Policy>
+inline T lower_gamma_series(T a, T z, const Policy& pol, T init_value = 0)
+{
+ // Multiply result by ((z^a) * (e^-z) / a) to get the full
+ // lower incomplete integral. Then divide by tgamma(a)
+ // to get the normalised value.
+ lower_incomplete_gamma_series<T> s(a, z);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+ T factor = policies::get_epsilon<T, Policy>();
+ T result = boost::math::tools::sum_series(s, factor, max_iter, init_value);
+ policies::check_series_iterations<T>("boost::math::detail::lower_gamma_series<%1%>(%1%)", max_iter, pol);
+ return result;
+}
+
+//
+// Fully generic tgamma and lgamma use the incomplete partial
+// sums added together:
+//
+template <class T, class Policy>
+T gamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos& l)
+{
+ static const char* function = "boost::math::tgamma<%1%>(%1%)";
+ BOOST_MATH_STD_USING
+ if((z <= 0) && (floor(z) == z))
+ return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
+ if(z <= -20)
+ {
+ T result = gamma_imp(T(-z), pol, l) * sinpx(z);
+ if((fabs(result) < 1) && (tools::max_value<T>() * fabs(result) < boost::math::constants::pi<T>()))
+ return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
+ result = -boost::math::constants::pi<T>() / result;
+ if(result == 0)
+ return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
+ if((boost::math::fpclassify)(result) == (int)FP_SUBNORMAL)
+ return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", result, pol);
+ return result;
+ }
+ //
+ // The upper gamma fraction is *very* slow for z < 6, actually it's very
+ // slow to converge everywhere but recursing until z > 6 gets rid of the
+ // worst of it's behaviour.
+ //
+ T prefix = 1;
+ while(z < 6)
+ {
+ prefix /= z;
+ z += 1;
+ }
+ BOOST_MATH_INSTRUMENT_CODE(prefix);
+ if((floor(z) == z) && (z < max_factorial<T>::value))
+ {
+ prefix *= unchecked_factorial<T>(itrunc(z, pol) - 1);
+ }
+ else
+ {
+ prefix = prefix * pow(z / boost::math::constants::e<T>(), z);
+ BOOST_MATH_INSTRUMENT_CODE(prefix);
+ T sum = detail::lower_gamma_series(z, z, pol) / z;
+ BOOST_MATH_INSTRUMENT_CODE(sum);
+ sum += detail::upper_gamma_fraction(z, z, ::boost::math::policies::get_epsilon<T, Policy>());
+ BOOST_MATH_INSTRUMENT_CODE(sum);
+ if(fabs(tools::max_value<T>() / prefix) < fabs(sum))
+ return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
+ BOOST_MATH_INSTRUMENT_CODE((sum * prefix));
+ return sum * prefix;
+ }
+ return prefix;
+}
+
+template <class T, class Policy>
+T lgamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos& l, int*sign)
+{
+ BOOST_MATH_STD_USING
+
+ static const char* function = "boost::math::lgamma<%1%>(%1%)";
+ T result = 0;
+ int sresult = 1;
+ if(z <= 0)
+ {
+ if(floor(z) == z)
+ return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
+ T t = detail::sinpx(z);
+ z = -z;
+ if(t < 0)
+ {
+ t = -t;
+ }
+ else
+ {
+ sresult = -sresult;
+ }
+ result = log(boost::math::constants::pi<T>()) - lgamma_imp(z, pol, l, 0) - log(t);
+ }
+ else if((z != 1) && (z != 2))
+ {
+ T limit = (std::max)(T(z+1), T(10));
+ T prefix = z * log(limit) - limit;
+ T sum = detail::lower_gamma_series(z, limit, pol) / z;
+ sum += detail::upper_gamma_fraction(z, limit, ::boost::math::policies::get_epsilon<T, Policy>());
+ result = log(sum) + prefix;
+ }
+ if(sign)
+ *sign = sresult;
+ return result;
+}
+//
+// This helper calculates tgamma(dz+1)-1 without cancellation errors,
+// used by the upper incomplete gamma with z < 1:
+//
+template <class T, class Policy, class Lanczos>
+T tgammap1m1_imp(T dz, Policy const& pol, const Lanczos& l)
+{
+ BOOST_MATH_STD_USING
+
+ 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_<113> >
+ >,
+ typename mpl::if_<
+ is_same<Lanczos, lanczos::lanczos24m113>,
+ mpl::int_<113>,
+ mpl::int_<0>
+ >::type,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>, mpl::int_<113> >::type
+ >::type tag_type;
+
+ T result;
+ if(dz < 0)
+ {
+ if(dz < -0.5)
+ {
+ // Best method is simply to subtract 1 from tgamma:
+ result = boost::math::tgamma(1+dz, pol) - 1;
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ else
+ {
+ // Use expm1 on lgamma:
+ result = boost::math::expm1(-boost::math::log1p(dz, pol)
+ + lgamma_small_imp<T>(dz+2, dz + 1, dz, tag_type(), pol, l));
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ }
+ else
+ {
+ if(dz < 2)
+ {
+ // Use expm1 on lgamma:
+ result = boost::math::expm1(lgamma_small_imp<T>(dz+1, dz, dz-1, tag_type(), pol, l), pol);
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ else
+ {
+ // Best method is simply to subtract 1 from tgamma:
+ result = boost::math::tgamma(1+dz, pol) - 1;
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ }
+
+ return result;
+}
+
+template <class T, class Policy>
+inline T tgammap1m1_imp(T dz, Policy const& pol,
+ const ::boost::math::lanczos::undefined_lanczos& l)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ //
+ // There should be a better solution than this, but the
+ // algebra isn't easy for the general case....
+ // Start by subracting 1 from tgamma:
+ //
+ T result = gamma_imp(T(1 + dz), pol, l) - 1;
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ //
+ // Test the level of cancellation error observed: we loose one bit
+ // for each power of 2 the result is less than 1. If we would get
+ // more bits from our most precise lgamma rational approximation,
+ // then use that instead:
+ //
+ BOOST_MATH_INSTRUMENT_CODE((dz > -0.5));
+ BOOST_MATH_INSTRUMENT_CODE((dz < 2));
+ BOOST_MATH_INSTRUMENT_CODE((ldexp(1.0, boost::math::policies::digits<T, Policy>()) * fabs(result) < 1e34));
+ if((dz > -0.5) && (dz < 2) && (ldexp(1.0, boost::math::policies::digits<T, Policy>()) * fabs(result) < 1e34))
+ {
+ result = tgammap1m1_imp(dz, pol, boost::math::lanczos::lanczos24m113());
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ return result;
+}
+
+//
+// Series representation for upper fraction when z is small:
+//
+template <class T>
+struct small_gamma2_series
+{
+ typedef T result_type;
+
+ small_gamma2_series(T a_, T x_) : result(-x_), x(-x_), apn(a_+1), n(1){}
+
+ T operator()()
+ {
+ T r = result / (apn);
+ result *= x;
+ result /= ++n;
+ apn += 1;
+ return r;
+ }
+
+private:
+ T result, x, apn;
+ int n;
+};
+//
+// calculate power term prefix (z^a)(e^-z) used in the non-normalised
+// incomplete gammas:
+//
+template <class T, class Policy>
+T full_igamma_prefix(T a, T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ T prefix;
+ T alz = a * log(z);
+
+ if(z >= 1)
+ {
+ if((alz < tools::log_max_value<T>()) && (-z > tools::log_min_value<T>()))
+ {
+ prefix = pow(z, a) * exp(-z);
+ }
+ else if(a >= 1)
+ {
+ prefix = pow(z / exp(z/a), a);
+ }
+ else
+ {
+ prefix = exp(alz - z);
+ }
+ }
+ else
+ {
+ if(alz > tools::log_min_value<T>())
+ {
+ prefix = pow(z, a) * exp(-z);
+ }
+ else if(z/a < tools::log_max_value<T>())
+ {
+ prefix = pow(z / exp(z/a), a);
+ }
+ else
+ {
+ prefix = exp(alz - z);
+ }
+ }
+ //
+ // This error handling isn't very good: it happens after the fact
+ // rather than before it...
+ //
+ if((boost::math::fpclassify)(prefix) == (int)FP_INFINITE)
+ policies::raise_overflow_error<T>("boost::math::detail::full_igamma_prefix<%1%>(%1%, %1%)", "Result of incomplete gamma function is too large to represent.", pol);
+
+ return prefix;
+}
+//
+// Compute (z^a)(e^-z)/tgamma(a)
+// most if the error occurs in this function:
+//
+template <class T, class Policy, class Lanczos>
+T regularised_gamma_prefix(T a, T z, const Policy& pol, const Lanczos& l)
+{
+ BOOST_MATH_STD_USING
+ T agh = a + static_cast<T>(Lanczos::g()) - T(0.5);
+ T prefix;
+ T d = ((z - a) - static_cast<T>(Lanczos::g()) + T(0.5)) / agh;
+
+ if(a < 1)
+ {
+ //
+ // We have to treat a < 1 as a special case because our Lanczos
+ // approximations are optimised against the factorials with a > 1,
+ // and for high precision types especially (128-bit reals for example)
+ // very small values of a can give rather eroneous results for gamma
+ // unless we do this:
+ //
+ // TODO: is this still required? Lanczos approx should be better now?
+ //
+ if(z <= tools::log_min_value<T>())
+ {
+ // Oh dear, have to use logs, should be free of cancellation errors though:
+ return exp(a * log(z) - z - lgamma_imp(a, pol, l));
+ }
+ else
+ {
+ // direct calculation, no danger of overflow as gamma(a) < 1/a
+ // for small a.
+ return pow(z, a) * exp(-z) / gamma_imp(a, pol, l);
+ }
+ }
+ else if((fabs(d*d*a) <= 100) && (a > 150))
+ {
+ // special case for large a and a ~ z.
+ prefix = a * boost::math::log1pmx(d, pol) + z * static_cast<T>(0.5 - Lanczos::g()) / agh;
+ prefix = exp(prefix);
+ }
+ else
+ {
+ //
+ // general case.
+ // direct computation is most accurate, but use various fallbacks
+ // for different parts of the problem domain:
+ //
+ T alz = a * log(z / agh);
+ T amz = a - z;
+ if(((std::min)(alz, amz) <= tools::log_min_value<T>()) || ((std::max)(alz, amz) >= tools::log_max_value<T>()))
+ {
+ T amza = amz / a;
+ if(((std::min)(alz, amz)/2 > tools::log_min_value<T>()) && ((std::max)(alz, amz)/2 < tools::log_max_value<T>()))
+ {
+ // compute square root of the result and then square it:
+ T sq = pow(z / agh, a / 2) * exp(amz / 2);
+ prefix = sq * sq;
+ }
+ else if(((std::min)(alz, amz)/4 > tools::log_min_value<T>()) && ((std::max)(alz, amz)/4 < tools::log_max_value<T>()) && (z > a))
+ {
+ // compute the 4th root of the result then square it twice:
+ T sq = pow(z / agh, a / 4) * exp(amz / 4);
+ prefix = sq * sq;
+ prefix *= prefix;
+ }
+ else if((amza > tools::log_min_value<T>()) && (amza < tools::log_max_value<T>()))
+ {
+ prefix = pow((z * exp(amza)) / agh, a);
+ }
+ else
+ {
+ prefix = exp(alz + amz);
+ }
+ }
+ else
+ {
+ prefix = pow(z / agh, a) * exp(amz);
+ }
+ }
+ prefix *= sqrt(agh / boost::math::constants::e<T>()) / Lanczos::lanczos_sum_expG_scaled(a);
+ return prefix;
+}
+//
+// And again, without Lanczos support:
+//
+template <class T, class Policy>
+T regularised_gamma_prefix(T a, T z, const Policy& pol, const lanczos::undefined_lanczos&)
+{
+ BOOST_MATH_STD_USING
+
+ T limit = (std::max)(T(10), a);
+ T sum = detail::lower_gamma_series(a, limit, pol) / a;
+ sum += detail::upper_gamma_fraction(a, limit, ::boost::math::policies::get_epsilon<T, Policy>());
+
+ if(a < 10)
+ {
+ // special case for small a:
+ T prefix = pow(z / 10, a);
+ prefix *= exp(10-z);
+ if(0 == prefix)
+ {
+ prefix = pow((z * exp((10-z)/a)) / 10, a);
+ }
+ prefix /= sum;
+ return prefix;
+ }
+
+ T zoa = z / a;
+ T amz = a - z;
+ T alzoa = a * log(zoa);
+ T prefix;
+ if(((std::min)(alzoa, amz) <= tools::log_min_value<T>()) || ((std::max)(alzoa, amz) >= tools::log_max_value<T>()))
+ {
+ T amza = amz / a;
+ if((amza <= tools::log_min_value<T>()) || (amza >= tools::log_max_value<T>()))
+ {
+ prefix = exp(alzoa + amz);
+ }
+ else
+ {
+ prefix = pow(zoa * exp(amza), a);
+ }
+ }
+ else
+ {
+ prefix = pow(zoa, a) * exp(amz);
+ }
+ prefix /= sum;
+ return prefix;
+}
+//
+// Upper gamma fraction for very small a:
+//
+template <class T, class Policy>
+inline T tgamma_small_upper_part(T a, T x, const Policy& pol, T* pgam = 0, bool invert = false, T* pderivative = 0)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+ //
+ // Compute the full upper fraction (Q) when a is very small:
+ //
+ T result;
+ result = boost::math::tgamma1pm1(a, pol);
+ if(pgam)
+ *pgam = (result + 1) / a;
+ T p = boost::math::powm1(x, a, pol);
+ result -= p;
+ result /= a;
+ detail::small_gamma2_series<T> s(a, x);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>() - 10;
+ p += 1;
+ if(pderivative)
+ *pderivative = p / (*pgam * exp(x));
+ T init_value = invert ? *pgam : 0;
+ result = -p * tools::sum_series(s, boost::math::policies::get_epsilon<T, Policy>(), max_iter, (init_value - result) / p);
+ policies::check_series_iterations<T>("boost::math::tgamma_small_upper_part<%1%>(%1%, %1%)", max_iter, pol);
+ if(invert)
+ result = -result;
+ return result;
+}
+//
+// Upper gamma fraction for integer a:
+//
+template <class T, class Policy>
+inline T finite_gamma_q(T a, T x, Policy const& pol, T* pderivative = 0)
+{
+ //
+ // Calculates normalised Q when a is an integer:
+ //
+ BOOST_MATH_STD_USING
+ T e = exp(-x);
+ T sum = e;
+ if(sum != 0)
+ {
+ T term = sum;
+ for(unsigned n = 1; n < a; ++n)
+ {
+ term /= n;
+ term *= x;
+ sum += term;
+ }
+ }
+ if(pderivative)
+ {
+ *pderivative = e * pow(x, a) / boost::math::unchecked_factorial<T>(itrunc(T(a - 1), pol));
+ }
+ return sum;
+}
+//
+// Upper gamma fraction for half integer a:
+//
+template <class T, class Policy>
+T finite_half_gamma_q(T a, T x, T* p_derivative, const Policy& pol)
+{
+ //
+ // Calculates normalised Q when a is a half-integer:
+ //
+ BOOST_MATH_STD_USING
+ T e = boost::math::erfc(sqrt(x), pol);
+ if((e != 0) && (a > 1))
+ {
+ T term = exp(-x) / sqrt(constants::pi<T>() * x);
+ term *= x;
+ static const T half = T(1) / 2;
+ term /= half;
+ T sum = term;
+ for(unsigned n = 2; n < a; ++n)
+ {
+ term /= n - half;
+ term *= x;
+ sum += term;
+ }
+ e += sum;
+ if(p_derivative)
+ {
+ *p_derivative = 0;
+ }
+ }
+ else if(p_derivative)
+ {
+ // We'll be dividing by x later, so calculate derivative * x:
+ *p_derivative = sqrt(x) * exp(-x) / constants::root_pi<T>();
+ }
+ return e;
+}
+//
+// Main incomplete gamma entry point, handles all four incomplete gamma's:
+//
+template <class T, class Policy>
+T gamma_incomplete_imp(T a, T x, bool normalised, bool invert,
+ const Policy& pol, T* p_derivative)
+{
+ static const char* function = "boost::math::gamma_p<%1%>(%1%, %1%)";
+ if(a <= 0)
+ policies::raise_domain_error<T>(function, "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
+ if(x < 0)
+ policies::raise_domain_error<T>(function, "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
+
+ BOOST_MATH_STD_USING
+
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+
+ T result = 0; // Just to avoid warning C4701: potentially uninitialized local variable 'result' used
+
+ BOOST_ASSERT((p_derivative == 0) || (normalised == true));
+
+ bool is_int, is_half_int;
+ bool is_small_a = (a < 30) && (a <= x + 1);
+ if(is_small_a)
+ {
+ T fa = floor(a);
+ is_int = (fa == a);
+ is_half_int = is_int ? false : (fabs(fa - a) == 0.5f);
+ }
+ else
+ {
+ is_int = is_half_int = false;
+ }
+
+ int eval_method;
+
+ if(is_int && (x > 0.6))
+ {
+ // calculate Q via finite sum:
+ invert = !invert;
+ eval_method = 0;
+ }
+ else if(is_half_int && (x > 0.2))
+ {
+ // calculate Q via finite sum for half integer a:
+ invert = !invert;
+ eval_method = 1;
+ }
+ else if(x < 0.5)
+ {
+ //
+ // Changeover criterion chosen to give a changeover at Q ~ 0.33
+ //
+ if(-0.4 / log(x) < a)
+ {
+ eval_method = 2;
+ }
+ else
+ {
+ eval_method = 3;
+ }
+ }
+ else if(x < 1.1)
+ {
+ //
+ // Changover here occurs when P ~ 0.75 or Q ~ 0.25:
+ //
+ if(x * 0.75f < a)
+ {
+ eval_method = 2;
+ }
+ else
+ {
+ eval_method = 3;
+ }
+ }
+ else
+ {
+ //
+ // Begin by testing whether we're in the "bad" zone
+ // where the result will be near 0.5 and the usual
+ // series and continued fractions are slow to converge:
+ //
+ bool use_temme = false;
+ if(normalised && std::numeric_limits<T>::is_specialized && (a > 20))
+ {
+ T sigma = fabs((x-a)/a);
+ if((a > 200) && (policies::digits<T, Policy>() <= 113))
+ {
+ //
+ // This limit is chosen so that we use Temme's expansion
+ // only if the result would be larger than about 10^-6.
+ // Below that the regular series and continued fractions
+ // converge OK, and if we use Temme's method we get increasing
+ // errors from the dominant erfc term as it's (inexact) argument
+ // increases in magnitude.
+ //
+ if(20 / a > sigma * sigma)
+ use_temme = true;
+ }
+ else if(policies::digits<T, Policy>() <= 64)
+ {
+ // Note in this zone we can't use Temme's expansion for
+ // types longer than an 80-bit real:
+ // it would require too many terms in the polynomials.
+ if(sigma < 0.4)
+ use_temme = true;
+ }
+ }
+ if(use_temme)
+ {
+ eval_method = 5;
+ }
+ else
+ {
+ //
+ // Regular case where the result will not be too close to 0.5.
+ //
+ // Changeover here occurs at P ~ Q ~ 0.5
+ // Note that series computation of P is about x2 faster than continued fraction
+ // calculation of Q, so try and use the CF only when really necessary, especially
+ // for small x.
+ //
+ if(x - (1 / (3 * x)) < a)
+ {
+ eval_method = 2;
+ }
+ else
+ {
+ eval_method = 4;
+ invert = !invert;
+ }
+ }
+ }
+
+ switch(eval_method)
+ {
+ case 0:
+ {
+ result = finite_gamma_q(a, x, pol, p_derivative);
+ if(normalised == false)
+ result *= boost::math::tgamma(a, pol);
+ break;
+ }
+ case 1:
+ {
+ result = finite_half_gamma_q(a, x, p_derivative, pol);
+ if(normalised == false)
+ result *= boost::math::tgamma(a, pol);
+ if(p_derivative && (*p_derivative == 0))
+ *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
+ break;
+ }
+ case 2:
+ {
+ // Compute P:
+ result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
+ if(p_derivative)
+ *p_derivative = result;
+ if(result != 0)
+ {
+ T init_value = 0;
+ if(invert)
+ {
+ init_value = -a * (normalised ? 1 : boost::math::tgamma(a, pol)) / result;
+ }
+ result *= detail::lower_gamma_series(a, x, pol, init_value) / a;
+ if(invert)
+ {
+ invert = false;
+ result = -result;
+ }
+ }
+ break;
+ }
+ case 3:
+ {
+ // Compute Q:
+ invert = !invert;
+ T g;
+ result = tgamma_small_upper_part(a, x, pol, &g, invert, p_derivative);
+ invert = false;
+ if(normalised)
+ result /= g;
+ break;
+ }
+ case 4:
+ {
+ // Compute Q:
+ result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
+ if(p_derivative)
+ *p_derivative = result;
+ if(result != 0)
+ result *= upper_gamma_fraction(a, x, policies::get_epsilon<T, Policy>());
+ break;
+ }
+ case 5:
+ {
+ //
+ // Use compile time dispatch to the appropriate
+ // Temme asymptotic expansion. This may be dead code
+ // if T does not have numeric limits support, or has
+ // too many digits for the most precise version of
+ // these expansions, in that case we'll be calling
+ // an empty function.
+ //
+ typedef typename policies::precision<T, Policy>::type precision_type;
+
+ typedef typename mpl::if_<
+ mpl::or_<mpl::equal_to<precision_type, mpl::int_<0> >,
+ mpl::greater<precision_type, mpl::int_<113> > >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>,
+ mpl::int_<113>
+ >::type
+ >::type
+ >::type tag_type;
+
+ result = igamma_temme_large(a, x, pol, static_cast<tag_type const*>(0));
+ if(x >= a)
+ invert = !invert;
+ if(p_derivative)
+ *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
+ break;
+ }
+ }
+
+ if(normalised && (result > 1))
+ result = 1;
+ if(invert)
+ {
+ T gam = normalised ? 1 : boost::math::tgamma(a, pol);
+ result = gam - result;
+ }
+ if(p_derivative)
+ {
+ //
+ // Need to convert prefix term to derivative:
+ //
+ if((x < 1) && (tools::max_value<T>() * x < *p_derivative))
+ {
+ // overflow, just return an arbitrarily large value:
+ *p_derivative = tools::max_value<T>() / 2;
+ }
+
+ *p_derivative /= x;
+ }
+
+ return result;
+}
+
+//
+// Ratios of two gamma functions:
+//
+template <class T, class Policy, class Lanczos>
+T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const Lanczos&)
+{
+ BOOST_MATH_STD_USING
+ T zgh = z + Lanczos::g() - constants::half<T>();
+ T result;
+ if(fabs(delta) < 10)
+ {
+ result = exp((constants::half<T>() - z) * boost::math::log1p(delta / zgh, pol));
+ }
+ else
+ {
+ result = pow(zgh / (zgh + delta), z - constants::half<T>());
+ }
+ result *= pow(constants::e<T>() / (zgh + delta), delta);
+ result *= Lanczos::lanczos_sum(z) / Lanczos::lanczos_sum(T(z + delta));
+ return result;
+}
+//
+// And again without Lanczos support this time:
+//
+template <class T, class Policy>
+T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const lanczos::undefined_lanczos&)
+{
+ BOOST_MATH_STD_USING
+ //
+ // The upper gamma fraction is *very* slow for z < 6, actually it's very
+ // slow to converge everywhere but recursing until z > 6 gets rid of the
+ // worst of it's behaviour.
+ //
+ T prefix = 1;
+ T zd = z + delta;
+ while((zd < 6) && (z < 6))
+ {
+ prefix /= z;
+ prefix *= zd;
+ z += 1;
+ zd += 1;
+ }
+ if(delta < 10)
+ {
+ prefix *= exp(-z * boost::math::log1p(delta / z, pol));
+ }
+ else
+ {
+ prefix *= pow(z / zd, z);
+ }
+ prefix *= pow(constants::e<T>() / zd, delta);
+ T sum = detail::lower_gamma_series(z, z, pol) / z;
+ sum += detail::upper_gamma_fraction(z, z, ::boost::math::policies::get_epsilon<T, Policy>());
+ T sumd = detail::lower_gamma_series(zd, zd, pol) / zd;
+ sumd += detail::upper_gamma_fraction(zd, zd, ::boost::math::policies::get_epsilon<T, Policy>());
+ sum /= sumd;
+ if(fabs(tools::max_value<T>() / prefix) < fabs(sum))
+ return policies::raise_overflow_error<T>("boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)", "Result of tgamma is too large to represent.", pol);
+ return sum * prefix;
+}
+
+template <class T, class Policy>
+T tgamma_delta_ratio_imp(T z, T delta, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ if(z <= 0)
+ policies::raise_domain_error<T>("boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)", "Gamma function ratios only implemented for positive arguments (got a=%1%).", z, pol);
+ if(z+delta <= 0)
+ policies::raise_domain_error<T>("boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)", "Gamma function ratios only implemented for positive arguments (got b=%1%).", z+delta, pol);
+
+ if(floor(delta) == delta)
+ {
+ if(floor(z) == z)
+ {
+ //
+ // Both z and delta are integers, see if we can just use table lookup
+ // of the factorials to get the result:
+ //
+ if((z <= max_factorial<T>::value) && (z + delta <= max_factorial<T>::value))
+ {
+ return unchecked_factorial<T>((unsigned)itrunc(z, pol) - 1) / unchecked_factorial<T>((unsigned)itrunc(T(z + delta), pol) - 1);
+ }
+ }
+ if(fabs(delta) < 20)
+ {
+ //
+ // delta is a small integer, we can use a finite product:
+ //
+ if(delta == 0)
+ return 1;
+ if(delta < 0)
+ {
+ z -= 1;
+ T result = z;
+ while(0 != (delta += 1))
+ {
+ z -= 1;
+ result *= z;
+ }
+ return result;
+ }
+ else
+ {
+ T result = 1 / z;
+ while(0 != (delta -= 1))
+ {
+ z += 1;
+ result /= z;
+ }
+ return result;
+ }
+ }
+ }
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+ return tgamma_delta_ratio_imp_lanczos(z, delta, pol, lanczos_type());
+}
+
+template <class T, class Policy>
+T gamma_p_derivative_imp(T a, T x, const Policy& pol)
+{
+ //
+ // Usual error checks first:
+ //
+ if(a <= 0)
+ policies::raise_domain_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", "Argument a to the incomplete gamma function must be greater than zero (got a=%1%).", a, pol);
+ if(x < 0)
+ policies::raise_domain_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", "Argument x to the incomplete gamma function must be >= 0 (got x=%1%).", x, pol);
+ //
+ // Now special cases:
+ //
+ if(x == 0)
+ {
+ return (a > 1) ? 0 :
+ (a == 1) ? 1 : policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", 0, pol);
+ }
+ //
+ // Normal case:
+ //
+ typedef typename lanczos::lanczos<T, Policy>::type lanczos_type;
+ T f1 = detail::regularised_gamma_prefix(a, x, pol, lanczos_type());
+ if((x < 1) && (tools::max_value<T>() * x < f1))
+ {
+ // overflow:
+ return policies::raise_overflow_error<T>("boost::math::gamma_p_derivative<%1%>(%1%, %1%)", 0, pol);
+ }
+
+ f1 /= x;
+
+ return f1;
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ tgamma(T z, const Policy& /* pol */, const mpl::true_)
+{
+ 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 lanczos::lanczos<value_type, 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;
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::gamma_imp(static_cast<value_type>(z), forwarding_policy(), evaluation_type()), "boost::math::tgamma<%1%>(%1%)");
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma(T1 a, T2 z, const Policy&, const mpl::false_)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename lanczos::lanczos<value_type, 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;
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::gamma_incomplete_imp(static_cast<value_type>(a),
+ static_cast<value_type>(z), false, true,
+ forwarding_policy(), static_cast<value_type*>(0)), "boost::math::tgamma<%1%>(%1%, %1%)");
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma(T1 a, T2 z, const mpl::false_ tag)
+{
+ return tgamma(a, z, policies::policy<>(), tag);
+}
+
+} // namespace detail
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ tgamma(T z)
+{
+ return tgamma(z, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ lgamma(T z, int* sign, 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 lanczos::lanczos<value_type, 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;
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::lgamma_imp(static_cast<value_type>(z), forwarding_policy(), evaluation_type(), sign), "boost::math::lgamma<%1%>(%1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ lgamma(T z, int* sign)
+{
+ return lgamma(z, sign, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ lgamma(T x, const Policy& pol)
+{
+ return ::boost::math::lgamma(x, 0, pol);
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ lgamma(T x)
+{
+ return ::boost::math::lgamma(x, 0, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ tgamma1pm1(T z, const Policy& /* pol */)
+{
+ 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 lanczos::lanczos<value_type, 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;
+
+ return policies::checked_narrowing_cast<typename remove_cv<result_type>::type, forwarding_policy>(detail::tgammap1m1_imp(static_cast<value_type>(z), forwarding_policy(), evaluation_type()), "boost::math::tgamma1pm1<%!%>(%1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ tgamma1pm1(T z)
+{
+ return tgamma1pm1(z, policies::policy<>());
+}
+
+//
+// Full upper incomplete gamma:
+//
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma(T1 a, T2 z)
+{
+ //
+ // Type T2 could be a policy object, or a value, select the
+ // right overload based on T2:
+ //
+ typedef typename policies::is_policy<T2>::type maybe_policy;
+ return detail::tgamma(a, z, maybe_policy());
+}
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma(T1 a, T2 z, const Policy& pol)
+{
+ return detail::tgamma(a, z, pol, mpl::false_());
+}
+//
+// Full lower incomplete gamma:
+//
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma_lower(T1 a, T2 z, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename lanczos::lanczos<value_type, 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::gamma_incomplete_imp(static_cast<value_type>(a),
+ static_cast<value_type>(z), false, false,
+ forwarding_policy(), static_cast<value_type*>(0)), "tgamma_lower<%1%>(%1%, %1%)");
+}
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma_lower(T1 a, T2 z)
+{
+ return tgamma_lower(a, z, policies::policy<>());
+}
+//
+// Regularised upper incomplete gamma:
+//
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_q(T1 a, T2 z, const Policy& /* pol */)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename lanczos::lanczos<value_type, 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::gamma_incomplete_imp(static_cast<value_type>(a),
+ static_cast<value_type>(z), true, true,
+ forwarding_policy(), static_cast<value_type*>(0)), "gamma_q<%1%>(%1%, %1%)");
+}
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_q(T1 a, T2 z)
+{
+ return gamma_q(a, z, policies::policy<>());
+}
+//
+// Regularised lower incomplete gamma:
+//
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p(T1 a, T2 z, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename lanczos::lanczos<value_type, 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::gamma_incomplete_imp(static_cast<value_type>(a),
+ static_cast<value_type>(z), true, false,
+ forwarding_policy(), static_cast<value_type*>(0)), "gamma_p<%1%>(%1%, %1%)");
+}
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p(T1 a, T2 z)
+{
+ return gamma_p(a, z, policies::policy<>());
+}
+
+// ratios of gamma functions:
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma_delta_ratio(T1 z, T2 delta, const Policy& /* pol */)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::tgamma_delta_ratio_imp(static_cast<value_type>(z), static_cast<value_type>(delta), forwarding_policy()), "boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)");
+}
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma_delta_ratio(T1 z, T2 delta)
+{
+ return tgamma_delta_ratio(z, delta, policies::policy<>());
+}
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma_ratio(T1 a, T2 b, const Policy&)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::tgamma_delta_ratio_imp(static_cast<value_type>(a), static_cast<value_type>(static_cast<value_type>(b) - static_cast<value_type>(a)), forwarding_policy()), "boost::math::tgamma_delta_ratio<%1%>(%1%, %1%)");
+}
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ tgamma_ratio(T1 a, T2 b)
+{
+ return tgamma_ratio(a, b, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p_derivative(T1 a, T2 x, const Policy&)
+{
+ BOOST_FPU_EXCEPTION_GUARD
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::gamma_p_derivative_imp(static_cast<value_type>(a), static_cast<value_type>(x), forwarding_policy()), "boost::math::gamma_p_derivative<%1%>(%1%, %1%)");
+}
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ gamma_p_derivative(T1 a, T2 x)
+{
+ return gamma_p_derivative(a, x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#ifdef BOOST_MSVC
+# pragma warning(pop)
+#endif
+
+#include <boost/math/special_functions/detail/igamma_inverse.hpp>
+#include <boost/math/special_functions/detail/gamma_inva.hpp>
+#include <boost/math/special_functions/erf.hpp>
+
+#endif // BOOST_MATH_SF_GAMMA_HPP
+
+
+
+
diff --git a/boost/math/special_functions/hermite.hpp b/boost/math/special_functions/hermite.hpp
new file mode 100644
index 0000000000..1221f414dc
--- /dev/null
+++ b/boost/math/special_functions/hermite.hpp
@@ -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
+
+
+
diff --git a/boost/math/special_functions/hypot.hpp b/boost/math/special_functions/hypot.hpp
new file mode 100644
index 0000000000..efe1a3f211
--- /dev/null
+++ b/boost/math/special_functions/hypot.hpp
@@ -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
+
+
+
diff --git a/boost/math/special_functions/laguerre.hpp b/boost/math/special_functions/laguerre.hpp
new file mode 100644
index 0000000000..070927f26b
--- /dev/null
+++ b/boost/math/special_functions/laguerre.hpp
@@ -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
+
+
+
diff --git a/boost/math/special_functions/lanczos.hpp b/boost/math/special_functions/lanczos.hpp
new file mode 100644
index 0000000000..20ff969359
--- /dev/null
+++ b/boost/math/special_functions/lanczos.hpp
@@ -0,0 +1,1243 @@
+// (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
+#define BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/config.hpp>
+#include <boost/math/tools/big_constant.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/limits.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/policies/policy.hpp>
+#include <boost/mpl/less_equal.hpp>
+
+#include <limits.h>
+
+namespace boost{ namespace math{ namespace lanczos{
+
+//
+// Individual lanczos approximations start here.
+//
+// Optimal values for G for each N are taken from
+// http://web.mala.bc.ca/pughg/phdThesis/phdThesis.pdf,
+// as are the theoretical error bounds.
+//
+// Constants calculated using the method described by Godfrey
+// http://my.fit.edu/~gabdo/gamma.txt and elaborated by Toth at
+// http://www.rskey.org/gamma.htm using NTL::RR at 1000 bit precision.
+//
+// Lanczos Coefficients for N=6 G=5.581
+// Max experimental error (with arbitary precision arithmetic) 9.516e-12
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos6 : public mpl::int_<35>
+{
+ //
+ // Produces slightly better than float precision when evaluated at
+ // double precision:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[6] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 8706.349592549009182288174442774377925882)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 8523.650341121874633477483696775067709735)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 3338.029219476423550899999750161289306564)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 653.6424994294008795995653541449610986791)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 63.99951844938187085666201263218840287667)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 2.506628274631006311133031631822390264407))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = {
+ static_cast<boost::uint16_t>(0u),
+ static_cast<boost::uint16_t>(24u),
+ static_cast<boost::uint16_t>(50u),
+ static_cast<boost::uint16_t>(35u),
+ static_cast<boost::uint16_t>(10u),
+ static_cast<boost::uint16_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[6] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 32.81244541029783471623665933780748627823)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 32.12388941444332003446077108933558534361)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 12.58034729455216106950851080138931470954)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 2.463444478353241423633780693218408889251)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 0.2412010548258800231126240760264822486599)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 0.009446967704539249494420221613134244048319))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = {
+ static_cast<boost::uint16_t>(0u),
+ static_cast<boost::uint16_t>(24u),
+ static_cast<boost::uint16_t>(50u),
+ static_cast<boost::uint16_t>(35u),
+ static_cast<boost::uint16_t>(10u),
+ static_cast<boost::uint16_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[5] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 2.044879010930422922760429926121241330235)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, -2.751366405578505366591317846728753993668)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 1.02282965224225004296750609604264824677)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, -0.09786124911582813985028889636665335893627)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 0.0009829742267506615183144364420540766510112)),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[5] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 5.748142489536043490764289256167080091892)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, -7.734074268282457156081021756682138251825)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 2.875167944990511006997713242805893543947)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, -0.2750873773533504542306766137703788781776)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 35, 0.002763134585812698552178368447708846850353)),
+ };
+ T result = 0;
+ T z = dz + 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 5.581000000000000405009359383257105946541; }
+};
+
+//
+// Lanczos Coefficients for N=11 G=10.900511
+// Max experimental error (with arbitary precision arithmetic) 2.16676e-19
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos11 : public mpl::int_<60>
+{
+ //
+ // Produces slightly better than double precision when evaluated at
+ // extended-double precision:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[11] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 38474670393.31776828316099004518914832218)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 36857665043.51950660081971227404959150474)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 15889202453.72942008945006665994637853242)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 4059208354.298834770194507810788393801607)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 680547661.1834733286087695557084801366446)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 78239755.00312005289816041245285376206263)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 6246580.776401795264013335510453568106366)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 341986.3488721347032223777872763188768288)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 12287.19451182455120096222044424100527629)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 261.6140441641668190791708576058805625502)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 2.506628274631000502415573855452633787834))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[11] = {
+ static_cast<boost::uint32_t>(0u),
+ static_cast<boost::uint32_t>(362880u),
+ static_cast<boost::uint32_t>(1026576u),
+ static_cast<boost::uint32_t>(1172700u),
+ static_cast<boost::uint32_t>(723680u),
+ static_cast<boost::uint32_t>(269325u),
+ static_cast<boost::uint32_t>(63273u),
+ static_cast<boost::uint32_t>(9450u),
+ static_cast<boost::uint32_t>(870u),
+ static_cast<boost::uint32_t>(45u),
+ static_cast<boost::uint32_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[11] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 709811.662581657956893540610814842699825)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 679979.847415722640161734319823103390728)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 293136.785721159725251629480984140341656)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 74887.5403291467179935942448101441897121)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 12555.29058241386295096255111537516768137)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 1443.42992444170669746078056942194198252)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 115.2419459613734722083208906727972935065)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 6.30923920573262762719523981992008976989)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 0.2266840463022436475495508977579735223818)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 0.004826466289237661857584712046231435101741)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 0.4624429436045378766270459638520555557321e-4))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[11] = {
+ static_cast<boost::uint32_t>(0u),
+ static_cast<boost::uint32_t>(362880u),
+ static_cast<boost::uint32_t>(1026576u),
+ static_cast<boost::uint32_t>(1172700u),
+ static_cast<boost::uint32_t>(723680u),
+ static_cast<boost::uint32_t>(269325u),
+ static_cast<boost::uint32_t>(63273u),
+ static_cast<boost::uint32_t>(9450u),
+ static_cast<boost::uint32_t>(870u),
+ static_cast<boost::uint32_t>(45u),
+ static_cast<boost::uint32_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[10] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 4.005853070677940377969080796551266387954)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -13.17044315127646469834125159673527183164)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 17.19146865350790353683895137079288129318)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -11.36446409067666626185701599196274701126)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 4.024801119349323770107694133829772634737)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -0.7445703262078094128346501724255463005006)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 0.06513861351917497265045550019547857713172)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -0.00217899958561830354633560009312512312758)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 0.17655204574495137651670832229571934738e-4)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -0.1036282091079938047775645941885460820853e-7)),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[10] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 19.05889633808148715159575716844556056056)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -62.66183664701721716960978577959655644762)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 81.7929198065004751699057192860287512027)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -54.06941772964234828416072865069196553015)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 19.14904664790693019642068229478769661515)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -3.542488556926667589704590409095331790317)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 0.3099140334815639910894627700232804503017)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -0.01036716187296241640634252431913030440825)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, 0.8399926504443119927673843789048514017761e-4)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 60, -0.493038376656195010308610694048822561263e-7)),
+ };
+ T result = 0;
+ T z = dz + 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 10.90051099999999983936049829935654997826; }
+};
+
+//
+// Lanczos Coefficients for N=13 G=13.144565
+// Max experimental error (with arbitary precision arithmetic) 9.2213e-23
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos13 : public mpl::int_<72>
+{
+ //
+ // Produces slightly better than extended-double precision when evaluated at
+ // higher precision:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[13] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 44012138428004.60895436261759919070125699)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 41590453358593.20051581730723108131357995)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 18013842787117.99677796276038389462742949)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 4728736263475.388896889723995205703970787)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 837910083628.4046470415724300225777912264)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 105583707273.4299344907359855510105321192)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 9701363618.494999493386608345339104922694)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 654914397.5482052641016767125048538245644)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 32238322.94213356530668889463945849409184)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 1128514.219497091438040721811544858643121)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 26665.79378459858944762533958798805525125)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 381.8801248632926870394389468349331394196)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 2.506628274631000502415763426076722427007))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = {
+ static_cast<boost::uint32_t>(0u),
+ static_cast<boost::uint32_t>(39916800u),
+ static_cast<boost::uint32_t>(120543840u),
+ static_cast<boost::uint32_t>(150917976u),
+ static_cast<boost::uint32_t>(105258076u),
+ static_cast<boost::uint32_t>(45995730u),
+ static_cast<boost::uint32_t>(13339535u),
+ static_cast<boost::uint32_t>(2637558u),
+ static_cast<boost::uint32_t>(357423u),
+ static_cast<boost::uint32_t>(32670u),
+ static_cast<boost::uint32_t>(1925u),
+ static_cast<boost::uint32_t>(66u),
+ static_cast<boost::uint32_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[13] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 86091529.53418537217994842267760536134841)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 81354505.17858011242874285785316135398567)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 35236626.38815461910817650960734605416521)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 9249814.988024471294683815872977672237195)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 1639024.216687146960253839656643518985826)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 206530.8157641225032631778026076868855623)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 18976.70193530288915698282139308582105936)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 1281.068909912559479885759622791374106059)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 63.06093343420234536146194868906771599354)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 2.207470909792527638222674678171050209691)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 0.05216058694613505427476207805814960742102)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 0.0007469903808915448316510079585999893674101)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 0.4903180573459871862552197089738373164184e-5))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = {
+ static_cast<boost::uint32_t>(0u),
+ static_cast<boost::uint32_t>(39916800u),
+ static_cast<boost::uint32_t>(120543840u),
+ static_cast<boost::uint32_t>(150917976u),
+ static_cast<boost::uint32_t>(105258076u),
+ static_cast<boost::uint32_t>(45995730u),
+ static_cast<boost::uint32_t>(13339535u),
+ static_cast<boost::uint32_t>(2637558u),
+ static_cast<boost::uint32_t>(357423u),
+ static_cast<boost::uint32_t>(32670u),
+ static_cast<boost::uint32_t>(1925u),
+ static_cast<boost::uint32_t>(66u),
+ static_cast<boost::uint32_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[12] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 4.832115561461656947793029596285626840312)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -19.86441536140337740383120735104359034688)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 33.9927422807443239927197864963170585331)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -31.41520692249765980987427413991250886138)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 17.0270866009599345679868972409543597821)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -5.5077216950865501362506920516723682167)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 1.037811741948214855286817963800439373362)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -0.106640468537356182313660880481398642811)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 0.005276450526660653288757565778182586742831)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -0.0001000935625597121545867453746252064770029)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 0.462590910138598083940803704521211569234e-6)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -0.1735307814426389420248044907765671743012e-9)),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[12] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 26.96979819614830698367887026728396466395)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -110.8705424709385114023884328797900204863)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 189.7258846119231466417015694690434770085)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -175.3397202971107486383321670769397356553)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 95.03437648691551457087250340903980824948)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -30.7406022781665264273675797983497141978)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 5.792405601630517993355102578874590410552)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -0.5951993240669148697377539518639997795831)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 0.02944979359164017509944724739946255067671)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -0.0005586586555377030921194246330399163602684)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, 0.2581888478270733025288922038673392636029e-5)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 72, -0.9685385411006641478305219367315965391289e-9)),
+ };
+ T result = 0;
+ T z = z = 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 13.1445650000000000545696821063756942749; }
+};
+
+//
+// Lanczos Coefficients for N=22 G=22.61891
+// Max experimental error (with arbitary precision arithmetic) 2.9524e-38
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos22 : public mpl::int_<120>
+{
+ //
+ // Produces slightly better than 128-bit long-double precision when
+ // evaluated at higher precision:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[22] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 46198410803245094237463011094.12173081986)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 43735859291852324413622037436.321513777)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 19716607234435171720534556386.97481377748)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 5629401471315018442177955161.245623932129)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 1142024910634417138386281569.245580222392)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 175048529315951173131586747.695329230778)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 21044290245653709191654675.41581372963167)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 2033001410561031998451380.335553678782601)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 160394318862140953773928.8736211601848891)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 10444944438396359705707.48957290388740896)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 565075825801617290121.1466393747967538948)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 25475874292116227538.99448534450411942597)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 957135055846602154.6720835535232270205725)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 29874506304047462.23662392445173880821515)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 769651310384737.2749087590725764959689181)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 16193289100889.15989633624378404096011797)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 273781151680.6807433264462376754578933261)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 3630485900.32917021712188739762161583295)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 36374352.05577334277856865691538582936484)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 258945.7742115532455441786924971194951043)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 1167.501919472435718934219997431551246996)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 2.50662827463100050241576528481104525333))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[22] = {
+ BOOST_MATH_INT_VALUE_SUFFIX(0, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(2432902008176640000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(8752948036761600000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(13803759753640704000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(12870931245150988800, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(8037811822645051776, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(3599979517947607200, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1206647803780373360, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(311333643161390640, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(63030812099294896, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(10142299865511450, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1307535010540395, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(135585182899530, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(11310276995381, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(756111184500, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(40171771630, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1672280820, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(53327946, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1256850, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(20615, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(210, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1, uLL)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[22] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 6939996264376682180.277485395074954356211)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 6570067992110214451.87201438870245659384)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 2961859037444440551.986724631496417064121)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 845657339772791245.3541226499766163431651)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 171556737035449095.2475716923888737881837)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 26296059072490867.7822441885603400926007)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 3161305619652108.433798300149816829198706)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 305400596026022.4774396904484542582526472)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 24094681058862.55120507202622377623528108)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 1569055604375.919477574824168939428328839)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 84886558909.02047889339710230696942513159)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 3827024985.166751989686050643579753162298)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 143782298.9273215199098728674282885500522)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 4487794.24541641841336786238909171265944)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 115618.2025760830513505888216285273541959)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 2432.580773108508276957461757328744780439)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 41.12782532742893597168530008461874360191)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.5453771709477689805460179187388702295792)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.005464211062612080347167337964166505282809)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.388992321263586767037090706042788910953e-4)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.1753839324538447655939518484052327068859e-6)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.3765495513732730583386223384116545391759e-9))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[22] = {
+ BOOST_MATH_INT_VALUE_SUFFIX(0, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(2432902008176640000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(8752948036761600000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(13803759753640704000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(12870931245150988800, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(8037811822645051776, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(3599979517947607200, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1206647803780373360, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(311333643161390640, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(63030812099294896, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(10142299865511450, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1307535010540395, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(135585182899530, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(11310276995381, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(756111184500, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(40171771630, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1672280820, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(53327946, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1256850, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(20615, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(210, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1, uLL)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[21] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 8.318998691953337183034781139546384476554)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -63.15415991415959158214140353299240638675)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 217.3108224383632868591462242669081540163)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -448.5134281386108366899784093610397354889)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 619.2903759363285456927248474593012711346)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -604.1630177420625418522025080080444177046)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 428.8166750424646119935047118287362193314)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -224.6988753721310913866347429589434550302)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 87.32181627555510833499451817622786940961)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -25.07866854821128965662498003029199058098)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 5.264398125689025351448861011657789005392)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.792518936256495243383586076579921559914)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.08317448364744713773350272460937904691566)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.005845345166274053157781068150827567998882)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.0002599412126352082483326238522490030412391)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.6748102079670763884917431338234783496303e-5)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.908824383434109002762325095643458603605e-7)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.5299325929309389890892469299969669579725e-9)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.994306085859549890267983602248532869362e-12)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.3499893692975262747371544905820891835298e-15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.7260746353663365145454867069182884694961e-20)),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[21] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 75.39272007105208086018421070699575462226)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -572.3481967049935412452681346759966390319)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 1969.426202741555335078065370698955484358)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -4064.74968778032030891520063865996757519)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 5612.452614138013929794736248384309574814)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -5475.357667500026172903620177988213902339)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 3886.243614216111328329547926490398103492)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -2036.382026072125407192448069428134470564)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 791.3727954936062108045551843636692287652)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -227.2808432388436552794021219198885223122)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 47.70974355562144229897637024320739257284)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -7.182373807798293545187073539819697141572)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.7537866989631514559601547530490976100468)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.05297470142240154822658739758236594717787)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.00235577330936380542539812701472320434133)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.6115613067659273118098229498679502138802e-4)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.8236417010170941915758315020695551724181e-6)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.4802628430993048190311242611330072198089e-8)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.9011113376981524418952720279739624707342e-11)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, -0.3171854152689711198382455703658589996796e-14)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 120, 0.6580207998808093935798753964580596673177e-19)),
+ };
+ T result = 0;
+ T z = dz + 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 22.61890999999999962710717227309942245483; }
+};
+
+//
+// Lanczos Coefficients for N=6 G=1.428456135094165802001953125
+// Max experimental error (with arbitary precision arithmetic) 8.111667e-8
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos6m24 : public mpl::int_<24>
+{
+ //
+ // Use for float precision, when evaluated as a float:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[6] = {
+ static_cast<T>(58.52061591769095910314047740215847630266L),
+ static_cast<T>(182.5248962595894264831189414768236280862L),
+ static_cast<T>(211.0971093028510041839168287718170827259L),
+ static_cast<T>(112.2526547883668146736465390902227161763L),
+ static_cast<T>(27.5192015197455403062503721613097825345L),
+ static_cast<T>(2.50662858515256974113978724717473206342L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = {
+ static_cast<boost::uint16_t>(0u),
+ static_cast<boost::uint16_t>(24u),
+ static_cast<boost::uint16_t>(50u),
+ static_cast<boost::uint16_t>(35u),
+ static_cast<boost::uint16_t>(10u),
+ static_cast<boost::uint16_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[6] = {
+ static_cast<T>(14.0261432874996476619570577285003839357L),
+ static_cast<T>(43.74732405540314316089531289293124360129L),
+ static_cast<T>(50.59547402616588964511581430025589038612L),
+ static_cast<T>(26.90456680562548195593733429204228910299L),
+ static_cast<T>(6.595765571169314946316366571954421695196L),
+ static_cast<T>(0.6007854010515290065101128585795542383721L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint16_t) denom[6] = {
+ static_cast<boost::uint16_t>(0u),
+ static_cast<boost::uint16_t>(24u),
+ static_cast<boost::uint16_t>(50u),
+ static_cast<boost::uint16_t>(35u),
+ static_cast<boost::uint16_t>(10u),
+ static_cast<boost::uint16_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[5] = {
+ static_cast<T>(0.4922488055204602807654354732674868442106L),
+ static_cast<T>(0.004954497451132152436631238060933905650346L),
+ static_cast<T>(-0.003374784572167105840686977985330859371848L),
+ static_cast<T>(0.001924276018962061937026396537786414831385L),
+ static_cast<T>(-0.00056533046336427583708166383712907694434L),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[5] = {
+ static_cast<T>(0.6534966888520080645505805298901130485464L),
+ static_cast<T>(0.006577461728560758362509168026049182707101L),
+ static_cast<T>(-0.004480276069269967207178373559014835978161L),
+ static_cast<T>(0.00255461870648818292376982818026706528842L),
+ static_cast<T>(-0.000750517993690428370380996157470900204524L),
+ };
+ T result = 0;
+ T z = dz + 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 1.428456135094165802001953125; }
+};
+
+//
+// Lanczos Coefficients for N=13 G=6.024680040776729583740234375
+// Max experimental error (with arbitary precision arithmetic) 1.196214e-17
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos13m53 : public mpl::int_<53>
+{
+ //
+ // Use for double precision, when evaluated as a double:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[13] = {
+ static_cast<T>(23531376880.41075968857200767445163675473L),
+ static_cast<T>(42919803642.64909876895789904700198885093L),
+ static_cast<T>(35711959237.35566804944018545154716670596L),
+ static_cast<T>(17921034426.03720969991975575445893111267L),
+ static_cast<T>(6039542586.35202800506429164430729792107L),
+ static_cast<T>(1439720407.311721673663223072794912393972L),
+ static_cast<T>(248874557.8620541565114603864132294232163L),
+ static_cast<T>(31426415.58540019438061423162831820536287L),
+ static_cast<T>(2876370.628935372441225409051620849613599L),
+ static_cast<T>(186056.2653952234950402949897160456992822L),
+ static_cast<T>(8071.672002365816210638002902272250613822L),
+ static_cast<T>(210.8242777515793458725097339207133627117L),
+ static_cast<T>(2.506628274631000270164908177133837338626L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = {
+ static_cast<boost::uint32_t>(0u),
+ static_cast<boost::uint32_t>(39916800u),
+ static_cast<boost::uint32_t>(120543840u),
+ static_cast<boost::uint32_t>(150917976u),
+ static_cast<boost::uint32_t>(105258076u),
+ static_cast<boost::uint32_t>(45995730u),
+ static_cast<boost::uint32_t>(13339535u),
+ static_cast<boost::uint32_t>(2637558u),
+ static_cast<boost::uint32_t>(357423u),
+ static_cast<boost::uint32_t>(32670u),
+ static_cast<boost::uint32_t>(1925u),
+ static_cast<boost::uint32_t>(66u),
+ static_cast<boost::uint32_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[13] = {
+ static_cast<T>(56906521.91347156388090791033559122686859L),
+ static_cast<T>(103794043.1163445451906271053616070238554L),
+ static_cast<T>(86363131.28813859145546927288977868422342L),
+ static_cast<T>(43338889.32467613834773723740590533316085L),
+ static_cast<T>(14605578.08768506808414169982791359218571L),
+ static_cast<T>(3481712.15498064590882071018964774556468L),
+ static_cast<T>(601859.6171681098786670226533699352302507L),
+ static_cast<T>(75999.29304014542649875303443598909137092L),
+ static_cast<T>(6955.999602515376140356310115515198987526L),
+ static_cast<T>(449.9445569063168119446858607650988409623L),
+ static_cast<T>(19.51992788247617482847860966235652136208L),
+ static_cast<T>(0.5098416655656676188125178644804694509993L),
+ static_cast<T>(0.006061842346248906525783753964555936883222L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint32_t) denom[13] = {
+ static_cast<boost::uint32_t>(0u),
+ static_cast<boost::uint32_t>(39916800u),
+ static_cast<boost::uint32_t>(120543840u),
+ static_cast<boost::uint32_t>(150917976u),
+ static_cast<boost::uint32_t>(105258076u),
+ static_cast<boost::uint32_t>(45995730u),
+ static_cast<boost::uint32_t>(13339535u),
+ static_cast<boost::uint32_t>(2637558u),
+ static_cast<boost::uint32_t>(357423u),
+ static_cast<boost::uint32_t>(32670u),
+ static_cast<boost::uint32_t>(1925u),
+ static_cast<boost::uint32_t>(66u),
+ static_cast<boost::uint32_t>(1u)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[12] = {
+ static_cast<T>(2.208709979316623790862569924861841433016L),
+ static_cast<T>(-3.327150580651624233553677113928873034916L),
+ static_cast<T>(1.483082862367253753040442933770164111678L),
+ static_cast<T>(-0.1993758927614728757314233026257810172008L),
+ static_cast<T>(0.004785200610085071473880915854204301886437L),
+ static_cast<T>(-0.1515973019871092388943437623825208095123e-5L),
+ static_cast<T>(-0.2752907702903126466004207345038327818713e-7L),
+ static_cast<T>(0.3075580174791348492737947340039992829546e-7L),
+ static_cast<T>(-0.1933117898880828348692541394841204288047e-7L),
+ static_cast<T>(0.8690926181038057039526127422002498960172e-8L),
+ static_cast<T>(-0.2499505151487868335680273909354071938387e-8L),
+ static_cast<T>(0.3394643171893132535170101292240837927725e-9L),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[12] = {
+ static_cast<T>(6.565936202082889535528455955485877361223L),
+ static_cast<T>(-9.8907772644920670589288081640128194231L),
+ static_cast<T>(4.408830289125943377923077727900630927902L),
+ static_cast<T>(-0.5926941084905061794445733628891024027949L),
+ static_cast<T>(0.01422519127192419234315002746252160965831L),
+ static_cast<T>(-0.4506604409707170077136555010018549819192e-5L),
+ static_cast<T>(-0.8183698410724358930823737982119474130069e-7L),
+ static_cast<T>(0.9142922068165324132060550591210267992072e-7L),
+ static_cast<T>(-0.5746670642147041587497159649318454348117e-7L),
+ static_cast<T>(0.2583592566524439230844378948704262291927e-7L),
+ static_cast<T>(-0.7430396708998719707642735577238449585822e-8L),
+ static_cast<T>(0.1009141566987569892221439918230042368112e-8L),
+ };
+ T result = 0;
+ T z = dz + 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 6.024680040776729583740234375; }
+};
+
+//
+// Lanczos Coefficients for N=17 G=12.2252227365970611572265625
+// Max experimental error (with arbitary precision arithmetic) 2.7699e-26
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos17m64 : public mpl::int_<64>
+{
+ //
+ // Use for extended-double precision, when evaluated as an extended-double:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[17] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 553681095419291969.2230556393350368550504)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 731918863887667017.2511276782146694632234)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 453393234285807339.4627124634539085143364)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 174701893724452790.3546219631779712198035)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 46866125995234723.82897281620357050883077)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9281280675933215.169109622777099699054272)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1403600894156674.551057997617468721789536)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 165345984157572.7305349809894046783973837)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 15333629842677.31531822808737907246817024)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1123152927963.956626161137169462874517318)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 64763127437.92329018717775593533620578237)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2908830362.657527782848828237106640944457)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 99764700.56999856729959383751710026787811)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2525791.604886139959837791244686290089331)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 44516.94034970167828580039370201346554872)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 488.0063567520005730476791712814838113252)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2.50662827463100050241576877135758834683))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[17] = {
+ BOOST_MATH_INT_VALUE_SUFFIX(0, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1307674368000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(4339163001600, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(6165817614720, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(5056995703824, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(2706813345600, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1009672107080, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(272803210680, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(54631129553, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(8207628000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(928095740, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(78558480, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(4899622, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(218400, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(6580, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(120, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1, uLL)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[17] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2715894658327.717377557655133124376674911)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 3590179526097.912105038525528721129550434)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 2223966599737.814969312127353235818710172)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 856940834518.9562481809925866825485883417)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 229885871668.749072933597446453399395469)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 45526171687.54610815813502794395753410032)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 6884887713.165178784550917647709216424823)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 811048596.1407531864760282453852372777439)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 75213915.96540822314499613623119501704812)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 5509245.417224265151697527957954952830126)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 317673.5368435419126714931842182369574221)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 14268.27989845035520147014373320337523596)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 489.3618720403263670213909083601787814792)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 12.38941330038454449295883217865458609584)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.2183627389504614963941574507281683147897)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.002393749522058449186690627996063983095463)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.1229541408909435212800785616808830746135e-4))
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[17] = {
+ BOOST_MATH_INT_VALUE_SUFFIX(0, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1307674368000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(4339163001600, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(6165817614720, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(5056995703824, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(2706813345600, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1009672107080, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(272803210680, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(54631129553, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(8207628000, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(928095740, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(78558480, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(4899622, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(218400, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(6580, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(120, uLL),
+ BOOST_MATH_INT_VALUE_SUFFIX(1, uLL)
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[16] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 4.493645054286536365763334986866616581265)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -16.95716370392468543800733966378143997694)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 26.19196892983737527836811770970479846644)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -21.3659076437988814488356323758179283908)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 9.913992596774556590710751047594507535764)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -2.62888300018780199210536267080940382158)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.3807056693542503606384861890663080735588)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.02714647489697685807340312061034730486958)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.0007815484715461206757220527133967191796747)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.6108630817371501052576880554048972272435e-5)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.5037380238864836824167713635482801545086e-8)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.1483232144262638814568926925964858237006e-13)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.1346609158752142460943888149156716841693e-14)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.660492688923978805315914918995410340796e-15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.1472114697343266749193617793755763792681e-15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.1410901942033374651613542904678399264447e-16)),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[16] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 23.56409085052261327114594781581930373708)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -88.92116338946308797946237246006238652361)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 137.3472822086847596961177383569603988797)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -112.0400438263562152489272966461114852861)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 51.98768915202973863076166956576777843805)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -13.78552090862799358221343319574970124948)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 1.996371068830872830250406773917646121742)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.1423525874909934506274738563671862576161)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.004098338646046865122459664947239111298524)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.3203286637326511000882086573060433529094e-4)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.2641536751640138646146395939004587594407e-7)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.7777876663062235617693516558976641009819e-13)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.7061443477097101636871806229515157914789e-14)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.3463537849537988455590834887691613484813e-14)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, 0.7719578215795234036320348283011129450595e-15)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 64, -0.7398586479708476329563577384044188912075e-16)),
+ };
+ T result = 0;
+ T z = dz + 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 12.2252227365970611572265625; }
+};
+
+//
+// Lanczos Coefficients for N=24 G=20.3209821879863739013671875
+// Max experimental error (with arbitary precision arithmetic) 1.0541e-38
+// Generated with compiler: Microsoft Visual C++ version 8.0 on Win32 at Mar 23 2006
+//
+struct lanczos24m113 : public mpl::int_<113>
+{
+ //
+ // Use for long-double precision, when evaluated as an long-double:
+ //
+ template <class T>
+ static T lanczos_sum(const T& z)
+ {
+ static const T num[24] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2029889364934367661624137213253.22102954656825019111612712252027267955023987678816620961507)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2338599599286656537526273232565.2727349714338768161421882478417543004440597874814359063158)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1288527989493833400335117708406.3953711906175960449186720680201425446299360322830739180195)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 451779745834728745064649902914.550539158066332484594436145043388809847364393288132164411521)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 113141284461097964029239556815.291212318665536114012605167994061291631013303788706545334708)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 21533689802794625866812941616.7509064680880468667055339259146063256555368135236149614592432)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 3235510315314840089932120340.71494940111731241353655381919722177496659303550321056514776757)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 393537392344185475704891959.081297108513472083749083165179784098220158201055270548272414314)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 39418265082950435024868801.5005452240816902251477336582325944930252142622315101857742955673)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 3290158764187118871697791.05850632319194734270969161036889516414516566453884272345518372696)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 230677110449632078321772.618245845856640677845629174549731890660612368500786684333975350954)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 13652233645509183190158.5916189185218250859402806777406323001463296297553612462737044693697)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 683661466754325350495.216655026531202476397782296585200982429378069417193575896602446904762)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 28967871782219334117.0122379171041074970463982134039409352925258212207710168851968215545064)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1036104088560167006.2022834098572346459442601718514554488352117620272232373622553429728555)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 31128490785613152.8380102669349814751268126141105475287632676569913936040772990253369753962)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 779327504127342.536207878988196814811198475410572992436243686674896894543126229424358472541)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 16067543181294.643350688789124777020407337133926174150582333950666044399234540521336771876)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 268161795520.300916569439413185778557212729611517883948634711190170998896514639936969855484)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 3533216359.10528191668842486732408440112703691790824611391987708562111396961696753452085068)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 35378979.5479656110614685178752543826919239614088343789329169535932709470588426584501652577)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 253034.881362204346444503097491737872930637147096453940375713745904094735506180552724766444)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1151.61895453463992438325318456328526085882924197763140514450975619271382783957699017875304)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2.50662827463100050241576528481104515966515623051532908941425544355490413900497467936202516))
+ };
+ static const T denom[24] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.112400072777760768e22)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.414847677933545472e22)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 6756146673770930688000.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 6548684852703068697600.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 4280722865357147142912.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2021687376910682741568.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 720308216440924653696.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 199321978221066137360.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 43714229649594412832.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 7707401101297361068.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1103230881185949736.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 129006659818331295.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 12363045847086207.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 971250460939913.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 62382416421941.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 3256091103430.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 136717357942.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 4546047198.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 116896626)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2240315)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 30107)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 253)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1))
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+ template <class T>
+ static T lanczos_sum_expG_scaled(const T& z)
+ {
+ static const T num[24] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 3035162425359883494754.02878223286972654682199012688209026810841953293372712802258398358538)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 3496756894406430103600.16057175075063458536101374170860226963245118484234495645518505519827)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1926652656689320888654.01954015145958293168365236755537645929361841917596501251362171653478)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 675517066488272766316.083023742440619929434602223726894748181327187670231286180156444871912)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 169172853104918752780.086262749564831660238912144573032141700464995906149421555926000038492)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 32197935167225605785.6444116302160245528783954573163541751756353183343357329404208062043808)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 4837849542714083249.37587447454818124327561966323276633775195138872820542242539845253171632)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 588431038090493242.308438203986649553459461798968819276505178004064031201740043314534404158)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 58939585141634058.6206417889192563007809470547755357240808035714047014324843817783741669733)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 4919561837722192.82991866530802080996138070630296720420704876654726991998309206256077395868)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 344916580244240.407442753122831512004021081677987651622305356145640394384006997569631719101)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 20413302960687.8250598845969238472629322716685686993835561234733641729957841485003560103066)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1022234822943.78400752460970689311934727763870970686747383486600540378889311406851534545789)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 43313787191.9821354846952908076307094286897439975815501673706144217246093900159173598852503)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1549219505.59667418528481770869280437577581951167003505825834192510436144666564648361001914)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 46544421.1998761919380541579358096705925369145324466147390364674998568485110045455014967149)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1165278.06807504975090675074910052763026564833951579556132777702952882101173607903881127542)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 24024.759267256769471083727721827405338569868270177779485912486668586611981795179894572115)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 400.965008113421955824358063769761286758463521789765880962939528760888853281920872064838918)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 5.28299015654478269617039029170846385138134929147421558771949982217659507918482272439717603)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.0528999024412510102409256676599360516359062802002483877724963720047531347449011629466149805)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.000378346710654740685454266569593414561162134092347356968516522170279688139165340746957511115)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.172194142179211139195966608011235161516824700287310869949928393345257114743230967204370963e-5)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.374799931707148855771381263542708435935402853962736029347951399323367765509988401336565436e-8))
+ };
+ static const T denom[24] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.112400072777760768e22)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.414847677933545472e22)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 6756146673770930688000.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 6548684852703068697600.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 4280722865357147142912.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2021687376910682741568.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 720308216440924653696.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 199321978221066137360.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 43714229649594412832.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 7707401101297361068.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1103230881185949736.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 129006659818331295.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 12363045847086207.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 971250460939913.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 62382416421941.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 3256091103430.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 136717357942.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 4546047198.0)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 116896626)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2240315)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 30107)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 253)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1))
+ };
+ return boost::math::tools::evaluate_rational(num, denom, z);
+ }
+
+
+ template<class T>
+ static T lanczos_sum_near_1(const T& dz)
+ {
+ static const T d[23] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 7.4734083002469026177867421609938203388868806387315406134072298925733950040583068760685908)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -50.4225805042247530267317342133388132970816607563062253708655085754357843064134941138154171)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 152.288200621747008570784082624444625293884063492396162110698238568311211546361189979357019)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -271.894959539150384169327513139846971255640842175739337449692360299099322742181325023644769)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 319.240102980202312307047586791116902719088581839891008532114107693294261542869734803906793)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -259.493144143048088289689500935518073716201741349569864988870534417890269467336454358361499)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 149.747518319689708813209645403067832020714660918583227716408482877303972685262557460145835)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -61.9261301009341333289187201425188698128684426428003249782448828881580630606817104372760037)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 18.3077524177286961563937379403377462608113523887554047531153187277072451294845795496072365)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -3.82011322251948043097070160584761236869363471824695092089556195047949392738162970152230254)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.549382685505691522516705902336780999493262538301283190963770663549981309645795228539620711)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.0524814679715180697633723771076668718265358076235229045603747927518423453658004287459638024)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.00315392664003333528534120626687784812050217700942910879712808180705014754163256855643360698)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.000110098373127648510519799564665442121339511198561008748083409549601095293123407080388658329)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.19809382866681658224945717689377373458866950897791116315219376038432014207446832310901893e-5)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.152278977408600291408265615203504153130482270424202400677280558181047344681214058227949755e-7)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.364344768076106268872239259083188037615571711218395765792787047015406264051536972018235217e-10)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.148897510480440424971521542520683536298361220674662555578951242811522959610991621951203526e-13)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.261199241161582662426512749820666625442516059622425213340053324061794752786482115387573582e-18)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.780072664167099103420998436901014795601783313858454665485256897090476089641613851903791529e-24)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.303465867587106629530056603454807425512962762653755513440561256044986695349304176849392735e-24)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.615420597971283870342083342286977366161772327800327789325710571275345878439656918541092056e-25)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.499641233843540749369110053005439398774706583601830828776209650445427083113181961630763702e-26)),
+ };
+ T result = 0;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(k*dz + k*k);
+ }
+ return result;
+ }
+
+ template<class T>
+ static T lanczos_sum_near_2(const T& dz)
+ {
+ static const T d[23] = {
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 61.4165001061101455341808888883960361969557848005400286332291451422461117307237198559485365)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -414.372973678657049667308134761613915623353625332248315105320470271523320700386200587519147)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1251.50505818554680171298972755376376836161706773644771875668053742215217922228357204561873)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -2234.43389421602399514176336175766511311493214354568097811220122848998413358085613880612158)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 2623.51647746991904821899989145639147785427273427135380151752779100215839537090464785708684)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -2132.51572435428751962745870184529534443305617818870214348386131243463614597272260797772423)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 1230.62572059218405766499842067263311220019173335523810725664442147670956427061920234820189)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -508.90919151163744999377586956023909888833335885805154492270846381061182696305011395981929)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 150.453184562246579758706538566480316921938628645961177699894388251635886834047343195475395)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -31.3937061525822497422230490071156186113405446381476081565548185848237169870395131828731397)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 4.51482916590287954234936829724231512565732528859217337795452389161322923867318809206313688)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.431292919341108177524462194102701868233551186625103849565527515201492276412231365776131952)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.0259189820815586225636729971503340447445001375909094681698918294680345547092233915092128323)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.000904788882557558697594884691337532557729219389814315972435534723829065673966567231504429712)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.162793589759218213439218473348810982422449144393340433592232065020562974405674317564164312e-4)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.125142926178202562426432039899709511761368233479483128438847484617555752948755923647214487e-6)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.299418680048132583204152682950097239197934281178261879500770485862852229898797687301941982e-9)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.122364035267809278675627784883078206654408225276233049012165202996967011873995261617995421e-12)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.21465364366598631597052073538883430194257709353929022544344097235100199405814005393447785e-17)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.641064035802907518396608051803921688237330857546406669209280666066685733941549058513986818e-23)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.249388374622173329690271566855185869111237201309011956145463506483151054813346819490278951e-23)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, -0.505752900177513489906064295001851463338022055787536494321532352380960774349054239257683149e-24)),
+ static_cast<T>(BOOST_MATH_BIG_CONSTANT(T, 113, 0.410605371184590959139968810080063542546949719163227555918846829816144878123034347778284006e-25)),
+ };
+ T result = 0;
+ T z = dz + 2;
+ for(unsigned k = 1; k <= sizeof(d)/sizeof(d[0]); ++k)
+ {
+ result += (-d[k-1]*dz)/(z + k*z + k*k - 1);
+ }
+ return result;
+ }
+
+ static double g(){ return 20.3209821879863739013671875; }
+};
+
+
+//
+// placeholder for no lanczos info available:
+//
+struct undefined_lanczos : public mpl::int_<INT_MAX - 1> { };
+
+#if 0
+#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+#define BOOST_MATH_FLT_DIGITS ::std::numeric_limits<float>::digits
+#define BOOST_MATH_DBL_DIGITS ::std::numeric_limits<double>::digits
+#define BOOST_MATH_LDBL_DIGITS ::std::numeric_limits<long double>::digits
+#else
+#define BOOST_MATH_FLT_DIGITS FLT_MANT_DIG
+#define BOOST_MATH_DBL_DIGITS DBL_MANT_DIG
+#define BOOST_MATH_LDBL_DIGITS LDBL_MANT_DIG
+#endif
+#endif
+
+typedef mpl::list<
+ lanczos6m24,
+/* lanczos6, */
+ lanczos13m53,
+/* lanczos13, */
+ lanczos17m64,
+ lanczos24m113,
+ lanczos22,
+ undefined_lanczos> lanczos_list;
+
+template <class Real, class Policy>
+struct lanczos
+{
+ typedef typename mpl::if_<
+ typename mpl::less_equal<
+ typename policies::precision<Real, Policy>::type,
+ mpl::int_<0>
+ >::type,
+ mpl::int_<INT_MAX - 2>,
+ typename policies::precision<Real, Policy>::type
+ >::type target_precision;
+
+ typedef typename mpl::deref<typename mpl::find_if<
+ lanczos_list,
+ mpl::less_equal<target_precision, mpl::_1> >::type>::type type;
+};
+
+} // namespace lanczos
+} // namespace math
+} // namespace boost
+
+#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 <boost/math/special_functions/detail/lanczos_sse2.hpp>
+#endif
+#endif
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS
+
+
+
+
diff --git a/boost/math/special_functions/legendre.hpp b/boost/math/special_functions/legendre.hpp
new file mode 100644
index 0000000000..79e9756763
--- /dev/null
+++ b/boost/math/special_functions/legendre.hpp
@@ -0,0 +1,194 @@
+
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SPECIAL_LEGENDRE_HPP
+#define BOOST_MATH_SPECIAL_LEGENDRE_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/factorials.hpp>
+#include <boost/math/tools/config.hpp>
+
+namespace boost{
+namespace math{
+
+// Recurrance relation for legendre P and Q polynomials:
+template <class T1, class T2, class T3>
+inline typename tools::promote_args<T1, T2, T3>::type
+ legendre_next(unsigned l, T1 x, T2 Pl, T3 Plm1)
+{
+ typedef typename tools::promote_args<T1, T2, T3>::type result_type;
+ return ((2 * l + 1) * result_type(x) * result_type(Pl) - l * result_type(Plm1)) / (l + 1);
+}
+
+namespace detail{
+
+// Implement Legendre P and Q polynomials via recurrance:
+template <class T, class Policy>
+T legendre_imp(unsigned l, T x, const Policy& pol, bool second = false)
+{
+ static const char* function = "boost::math::legrendre_p<%1%>(unsigned, %1%)";
+ // Error handling:
+ if((x < -1) || (x > 1))
+ return policies::raise_domain_error<T>(
+ function,
+ "The Legendre Polynomial is defined for"
+ " -1 <= x <= 1, but got x = %1%.", x, pol);
+
+ T p0, p1;
+ if(second)
+ {
+ // A solution of the second kind (Q):
+ p0 = (boost::math::log1p(x, pol) - boost::math::log1p(-x, pol)) / 2;
+ p1 = x * p0 - 1;
+ }
+ else
+ {
+ // A solution of the first kind (P):
+ p0 = 1;
+ p1 = x;
+ }
+ if(l == 0)
+ return p0;
+
+ unsigned n = 1;
+
+ while(n < l)
+ {
+ std::swap(p0, p1);
+ p1 = boost::math::legendre_next(n, x, p0, p1);
+ ++n;
+ }
+ return p1;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ legendre_p(int l, T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ static const char* function = "boost::math::legendre_p<%1%>(unsigned, %1%)";
+ if(l < 0)
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(-l-1, static_cast<value_type>(x), pol, false), function);
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(l, static_cast<value_type>(x), pol, false), function);
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ legendre_p(int l, T x)
+{
+ return boost::math::legendre_p(l, x, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ legendre_q(unsigned l, T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(l, static_cast<value_type>(x), pol, true), "boost::math::legendre_q<%1%>(unsigned, %1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ legendre_q(unsigned l, T x)
+{
+ return boost::math::legendre_q(l, x, policies::policy<>());
+}
+
+// Recurrence for associated polynomials:
+template <class T1, class T2, class T3>
+inline typename tools::promote_args<T1, T2, T3>::type
+ legendre_next(unsigned l, unsigned m, T1 x, T2 Pl, T3 Plm1)
+{
+ typedef typename tools::promote_args<T1, T2, T3>::type result_type;
+ return ((2 * l + 1) * result_type(x) * result_type(Pl) - (l + m) * result_type(Plm1)) / (l + 1 - m);
+}
+
+namespace detail{
+// Legendre P associated polynomial:
+template <class T, class Policy>
+T legendre_p_imp(int l, int m, T x, T sin_theta_power, const Policy& pol)
+{
+ // Error handling:
+ if((x < -1) || (x > 1))
+ return policies::raise_domain_error<T>(
+ "boost::math::legendre_p<%1%>(int, int, %1%)",
+ "The associated Legendre Polynomial is defined for"
+ " -1 <= x <= 1, but got x = %1%.", x, pol);
+ // Handle negative arguments first:
+ if(l < 0)
+ return legendre_p_imp(-l-1, m, x, sin_theta_power, pol);
+ if(m < 0)
+ {
+ int sign = (m&1) ? -1 : 1;
+ return sign * boost::math::tgamma_ratio(static_cast<T>(l+m+1), static_cast<T>(l+1-m), pol) * legendre_p_imp(l, -m, x, sin_theta_power, pol);
+ }
+ // Special cases:
+ if(m > l)
+ return 0;
+ if(m == 0)
+ return boost::math::legendre_p(l, x, pol);
+
+ T p0 = boost::math::double_factorial<T>(2 * m - 1, pol) * sin_theta_power;
+
+ if(m&1)
+ p0 *= -1;
+ if(m == l)
+ return p0;
+
+ T p1 = x * (2 * m + 1) * p0;
+
+ int n = m + 1;
+
+ while(n < l)
+ {
+ std::swap(p0, p1);
+ p1 = boost::math::legendre_next(n, m, x, p0, p1);
+ ++n;
+ }
+ return p1;
+}
+
+template <class T, class Policy>
+inline T legendre_p_imp(int l, int m, T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ // TODO: we really could use that mythical "pow1p" function here:
+ return legendre_p_imp(l, m, x, static_cast<T>(pow(1 - x*x, T(abs(m))/2)), pol);
+}
+
+}
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ legendre_p(int l, int m, T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_p_imp(l, m, static_cast<value_type>(x), pol), "bost::math::legendre_p<%1%>(int, int, %1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ legendre_p(int l, int m, T x)
+{
+ return boost::math::legendre_p(l, m, x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SPECIAL_LEGENDRE_HPP
+
+
+
diff --git a/boost/math/special_functions/log1p.hpp b/boost/math/special_functions/log1p.hpp
new file mode 100644
index 0000000000..9bae7165e4
--- /dev/null
+++ b/boost/math/special_functions/log1p.hpp
@@ -0,0 +1,472 @@
+// (C) Copyright John Maddock 2005-2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_LOG1P_INCLUDED
+#define BOOST_MATH_LOG1P_INCLUDED
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/config/no_tr1/cmath.hpp>
+#include <math.h> // platform's ::log1p
+#include <boost/limits.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/series.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/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)
+ 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),
+ 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;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type log1p(T x, const Policy&)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::precision<result_type, Policy>::type precision_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+
+ typedef typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>, // double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>, // 80-bit long double
+ mpl::int_<0> // too many bits, use generic version.
+ >::type
+ >::type
+ >::type tag_type;
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(
+ detail::log1p_imp(static_cast<value_type>(x), forwarding_policy(), tag_type()), "boost::math::log1p<%1%>(%1%)");
+}
+
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
+// These overloads work around a type deduction bug:
+inline float log1p(float z)
+{
+ return log1p<float>(z);
+}
+inline double log1p(double z)
+{
+ return log1p<double>(z);
+}
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+inline long double log1p(long double z)
+{
+ return log1p<long double>(z);
+}
+#endif
+#endif
+
+#ifdef log1p
+# ifndef BOOST_HAS_LOG1P
+# define BOOST_HAS_LOG1P
+# endif
+# undef log1p
+#endif
+
+#if defined(BOOST_HAS_LOG1P) && !(defined(__osf__) && defined(__DECCXX_VER))
+# ifdef BOOST_MATH_USE_C99
+template <class Policy>
+inline float log1p(float x, const Policy& pol)
+{
+ if(x < -1)
+ return policies::raise_domain_error<float>(
+ "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
+ if(x == -1)
+ return -policies::raise_overflow_error<float>(
+ "log1p<%1%>(%1%)", 0, pol);
+ return ::log1pf(x);
+}
+#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
+template <class Policy>
+inline long double log1p(long double x, const Policy& pol)
+{
+ if(x < -1)
+ return policies::raise_domain_error<long double>(
+ "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
+ if(x == -1)
+ return -policies::raise_overflow_error<long double>(
+ "log1p<%1%>(%1%)", 0, pol);
+ return ::log1pl(x);
+}
+#endif
+#else
+template <class Policy>
+inline float log1p(float x, const Policy& pol)
+{
+ if(x < -1)
+ return policies::raise_domain_error<float>(
+ "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
+ if(x == -1)
+ return -policies::raise_overflow_error<float>(
+ "log1p<%1%>(%1%)", 0, pol);
+ return ::log1p(x);
+}
+#endif
+template <class Policy>
+inline double log1p(double x, const Policy& pol)
+{
+ if(x < -1)
+ return policies::raise_domain_error<double>(
+ "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
+ if(x == -1)
+ return -policies::raise_overflow_error<double>(
+ "log1p<%1%>(%1%)", 0, pol);
+ return ::log1p(x);
+}
+#elif defined(_MSC_VER) && (BOOST_MSVC >= 1400)
+//
+// You should only enable this branch if you are absolutely sure
+// that your compilers optimizer won't mess this code up!!
+// Currently tested with VC8 and Intel 9.1.
+//
+template <class Policy>
+inline double log1p(double x, const Policy& pol)
+{
+ if(x < -1)
+ return policies::raise_domain_error<double>(
+ "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
+ if(x == -1)
+ return -policies::raise_overflow_error<double>(
+ "log1p<%1%>(%1%)", 0, pol);
+ double u = 1+x;
+ if(u == 1.0)
+ return x;
+ else
+ return ::log(u)*(x/(u-1.0));
+}
+template <class Policy>
+inline float log1p(float x, const Policy& pol)
+{
+ return static_cast<float>(boost::math::log1p(static_cast<double>(x), pol));
+}
+#ifndef _WIN32_WCE
+//
+// For some reason this fails to compile under WinCE...
+// Needs more investigation.
+//
+template <class Policy>
+inline long double log1p(long double x, const Policy& pol)
+{
+ if(x < -1)
+ return policies::raise_domain_error<long double>(
+ "log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
+ if(x == -1)
+ return -policies::raise_overflow_error<long double>(
+ "log1p<%1%>(%1%)", 0, pol);
+ long double u = 1+x;
+ if(u == 1.0)
+ return x;
+ else
+ return ::logl(u)*(x/(u-1.0));
+}
+#endif
+#endif
+
+template <class T>
+inline typename tools::promote_args<T>::type log1p(T x)
+{
+ return boost::math::log1p(x, policies::policy<>());
+}
+//
+// Compute log(1+x)-x:
+//
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ log1pmx(T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ BOOST_MATH_STD_USING
+ static const char* function = "boost::math::log1pmx<%1%>(%1%)";
+
+ if(x < -1)
+ return policies::raise_domain_error<T>(
+ function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol);
+ if(x == -1)
+ return -policies::raise_overflow_error<T>(
+ function, 0, pol);
+
+ result_type a = abs(result_type(x));
+ if(a > result_type(0.95f))
+ return log(1 + result_type(x)) - result_type(x);
+ // Note that without numeric_limits specialisation support,
+ // epsilon just returns zero, and our "optimisation" will always fail:
+ if(a < tools::epsilon<result_type>())
+ return -x * x / 2;
+ boost::math::detail::log1p_series<T> s(x);
+ s();
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ T zero = 0;
+ T result = boost::math::tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter, zero);
+#else
+ T result = boost::math::tools::sum_series(s, policies::get_epsilon<T, Policy>(), max_iter);
+#endif
+ policies::check_series_iterations<T>(function, max_iter, pol);
+ return result;
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type log1pmx(T x)
+{
+ return log1pmx(x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_LOG1P_INCLUDED
+
+
+
diff --git a/boost/math/special_functions/math_fwd.hpp b/boost/math/special_functions/math_fwd.hpp
new file mode 100644
index 0000000000..14364a3d5c
--- /dev/null
+++ b/boost/math/special_functions/math_fwd.hpp
@@ -0,0 +1,1070 @@
+// math_fwd.hpp
+
+// TODO revise completely for new distribution classes.
+
+// Copyright Paul A. Bristow 2006.
+// 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)
+
+// Omnibus list of forward declarations of math special functions.
+
+// IT = Integer type.
+// RT = Real type (built-in floating-point types, float, double, long double) & User Defined Types
+// AT = Integer or Real type
+
+#ifndef BOOST_MATH_SPECIAL_MATH_FWD_HPP
+#define BOOST_MATH_SPECIAL_MATH_FWD_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/detail/round_fwd.hpp>
+#include <boost/math/tools/promotion.hpp> // for argument promotion.
+#include <boost/math/policies/policy.hpp>
+#include <boost/mpl/comparison.hpp>
+#include <boost/config/no_tr1/complex.hpp>
+
+#define BOOST_NO_MACRO_EXPAND /**/
+
+namespace boost
+{
+ namespace math
+ { // Math functions (in roughly alphabetic order).
+
+ // Beta functions.
+ template <class RT1, class RT2>
+ typename tools::promote_args<RT1, RT2>::type
+ beta(RT1 a, RT2 b); // Beta function (2 arguments).
+
+ template <class RT1, class RT2, class A>
+ typename tools::promote_args<RT1, RT2, A>::type
+ beta(RT1 a, RT2 b, A x); // Beta function (3 arguments).
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ beta(RT1 a, RT2 b, RT3 x, const Policy& pol); // Beta function (3 arguments).
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ betac(RT1 a, RT2 b, RT3 x);
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ betac(RT1 a, RT2 b, RT3 x, const Policy& pol);
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta(RT1 a, RT2 b, RT3 x); // Incomplete beta function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta(RT1 a, RT2 b, RT3 x, const Policy& pol); // Incomplete beta function.
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac(RT1 a, RT2 b, RT3 x); // Incomplete beta complement function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac(RT1 a, RT2 b, RT3 x, const Policy& pol); // Incomplete beta complement function.
+
+ template <class T1, class T2, class T3, class T4>
+ typename tools::promote_args<T1, T2, T3, T4>::type
+ ibeta_inv(T1 a, T2 b, T3 p, T4* py);
+
+ template <class T1, class T2, class T3, class T4, class Policy>
+ typename tools::promote_args<T1, T2, T3, T4>::type
+ ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol);
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_inv(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_inv(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function.
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_inva(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_inva(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function.
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_invb(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_invb(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function.
+
+ template <class T1, class T2, class T3, class T4>
+ typename tools::promote_args<T1, T2, T3, T4>::type
+ ibetac_inv(T1 a, T2 b, T3 q, T4* py);
+
+ template <class T1, class T2, class T3, class T4, class Policy>
+ typename tools::promote_args<T1, T2, T3, T4>::type
+ ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol);
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inv(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function.
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inva(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_inva(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function.
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_invb(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function.
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibetac_invb(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function.
+
+ template <class RT1, class RT2, class RT3>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_derivative(RT1 a, RT2 b, RT3 x); // derivative of incomplete beta
+
+ template <class RT1, class RT2, class RT3, class Policy>
+ typename tools::promote_args<RT1, RT2, RT3>::type
+ ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy& pol); // derivative of incomplete beta
+
+ // erf & erfc error functions.
+ template <class RT> // Error function.
+ typename tools::promote_args<RT>::type erf(RT z);
+ template <class RT, class Policy> // Error function.
+ typename tools::promote_args<RT>::type erf(RT z, const Policy&);
+
+ template <class RT>// Error function complement.
+ typename tools::promote_args<RT>::type erfc(RT z);
+ template <class RT, class Policy>// Error function complement.
+ typename tools::promote_args<RT>::type erfc(RT z, const Policy&);
+
+ template <class RT>// Error function inverse.
+ typename tools::promote_args<RT>::type erf_inv(RT z);
+ template <class RT, class Policy>// Error function inverse.
+ typename tools::promote_args<RT>::type erf_inv(RT z, const Policy& pol);
+
+ template <class RT>// Error function complement inverse.
+ typename tools::promote_args<RT>::type erfc_inv(RT z);
+ template <class RT, class Policy>// Error function complement inverse.
+ typename tools::promote_args<RT>::type erfc_inv(RT z, const Policy& pol);
+
+ // Polynomials:
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<T1, T2, T3>::type
+ legendre_next(unsigned l, T1 x, T2 Pl, T3 Plm1);
+
+ template <class T>
+ typename tools::promote_args<T>::type
+ legendre_p(int l, T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type
+ legendre_p(int l, T x, const Policy& pol);
+
+ template <class T>
+ typename tools::promote_args<T>::type
+ legendre_q(unsigned l, T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type
+ legendre_q(unsigned l, T x, const Policy& pol);
+
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<T1, T2, T3>::type
+ legendre_next(unsigned l, unsigned m, T1 x, T2 Pl, T3 Plm1);
+
+ template <class T>
+ typename tools::promote_args<T>::type
+ legendre_p(int l, int m, T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type
+ legendre_p(int l, int m, T x, const Policy& pol);
+
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<T1, T2, T3>::type
+ laguerre_next(unsigned n, T1 x, T2 Ln, T3 Lnm1);
+
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<T1, T2, T3>::type
+ laguerre_next(unsigned n, unsigned l, T1 x, T2 Pl, T3 Plm1);
+
+ template <class T>
+ typename tools::promote_args<T>::type
+ laguerre(unsigned n, T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type
+ laguerre(unsigned n, unsigned m, T x, const Policy& pol);
+
+ template <class T1, class T2>
+ struct laguerre_result
+ {
+ typedef typename mpl::if_<
+ policies::is_policy<T2>,
+ typename tools::promote_args<T1>::type,
+ typename tools::promote_args<T2>::type
+ >::type type;
+ };
+
+ template <class T1, class T2>
+ typename laguerre_result<T1, T2>::type
+ laguerre(unsigned n, T1 m, T2 x);
+
+ template <class T>
+ typename tools::promote_args<T>::type
+ hermite(unsigned n, T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type
+ hermite(unsigned n, T x, const Policy& pol);
+
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<T1, T2, T3>::type
+ hermite_next(unsigned n, T1 x, T2 Hn, T3 Hnm1);
+
+ template <class T1, class T2>
+ std::complex<typename tools::promote_args<T1, T2>::type>
+ spherical_harmonic(unsigned n, int m, T1 theta, T2 phi);
+
+ template <class T1, class T2, class Policy>
+ std::complex<typename tools::promote_args<T1, T2>::type>
+ spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);
+
+ // Elliptic integrals:
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<T1, T2, T3>::type
+ ellint_rf(T1 x, T2 y, T3 z);
+
+ template <class T1, class T2, class T3, class Policy>
+ typename tools::promote_args<T1, T2, T3>::type
+ ellint_rf(T1 x, T2 y, T3 z, const Policy& pol);
+
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<T1, T2, T3>::type
+ ellint_rd(T1 x, T2 y, T3 z);
+
+ template <class T1, class T2, class T3, class Policy>
+ typename tools::promote_args<T1, T2, T3>::type
+ ellint_rd(T1 x, T2 y, T3 z, const Policy& pol);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type
+ ellint_rc(T1 x, T2 y);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type
+ ellint_rc(T1 x, T2 y, const Policy& pol);
+
+ template <class T1, class T2, class T3, class T4>
+ typename tools::promote_args<T1, T2, T3, T4>::type
+ ellint_rj(T1 x, T2 y, T3 z, T4 p);
+
+ template <class T1, class T2, class T3, class T4, class Policy>
+ typename tools::promote_args<T1, T2, T3, T4>::type
+ ellint_rj(T1 x, T2 y, T3 z, T4 p, const Policy& pol);
+
+ template <typename T>
+ typename tools::promote_args<T>::type ellint_2(T k);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol);
+
+ template <typename T>
+ typename tools::promote_args<T>::type ellint_1(T k);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi);
+
+ 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 <class T, class U, class V>
+ struct ellint_3_result
+ {
+ typedef typename mpl::if_<
+ policies::is_policy<V>,
+ typename tools::promote_args<T, U>::type,
+ typename tools::promote_args<T, U, V>::type
+ >::type type;
+ };
+
+ } // namespace detail
+
+
+ template <class T1, class T2, class T3>
+ typename detail::ellint_3_result<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi);
+
+ template <class T1, class T2, class T3, class Policy>
+ typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v);
+
+ // Factorial functions.
+ // Note: not for integral types, at present.
+ template <class RT>
+ struct max_factorial;
+ template <class RT>
+ RT factorial(unsigned int);
+ template <class RT, class Policy>
+ RT factorial(unsigned int, const Policy& pol);
+ template <class RT>
+ RT unchecked_factorial(unsigned int BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(RT));
+ template <class RT>
+ RT double_factorial(unsigned i);
+ template <class RT, class Policy>
+ RT double_factorial(unsigned i, const Policy& pol);
+
+ template <class RT>
+ typename tools::promote_args<RT>::type falling_factorial(RT x, unsigned n);
+
+ template <class RT, class Policy>
+ typename tools::promote_args<RT>::type falling_factorial(RT x, unsigned n, const Policy& pol);
+
+ template <class RT>
+ typename tools::promote_args<RT>::type rising_factorial(RT x, int n);
+
+ template <class RT, class Policy>
+ typename tools::promote_args<RT>::type rising_factorial(RT x, int n, const Policy& pol);
+
+ // Gamma functions.
+ template <class RT>
+ typename tools::promote_args<RT>::type tgamma(RT z);
+
+ template <class RT>
+ typename tools::promote_args<RT>::type tgamma1pm1(RT z);
+
+ template <class RT, class Policy>
+ typename tools::promote_args<RT>::type tgamma1pm1(RT z, const Policy& pol);
+
+ template <class RT1, class RT2>
+ typename tools::promote_args<RT1, RT2>::type tgamma(RT1 a, RT2 z);
+
+ template <class RT1, class RT2, class Policy>
+ typename tools::promote_args<RT1, RT2>::type tgamma(RT1 a, RT2 z, const Policy& pol);
+
+ template <class RT>
+ typename tools::promote_args<RT>::type lgamma(RT z, int* sign);
+
+ template <class RT, class Policy>
+ typename tools::promote_args<RT>::type lgamma(RT z, int* sign, const Policy& pol);
+
+ template <class RT>
+ typename tools::promote_args<RT>::type lgamma(RT x);
+
+ template <class RT, class Policy>
+ typename tools::promote_args<RT>::type lgamma(RT x, const Policy& pol);
+
+ template <class RT1, class RT2>
+ typename tools::promote_args<RT1, RT2>::type tgamma_lower(RT1 a, RT2 z);
+
+ template <class RT1, class RT2, class Policy>
+ typename tools::promote_args<RT1, RT2>::type tgamma_lower(RT1 a, RT2 z, const Policy&);
+
+ template <class RT1, class RT2>
+ typename tools::promote_args<RT1, RT2>::type gamma_q(RT1 a, RT2 z);
+
+ template <class RT1, class RT2, class Policy>
+ typename tools::promote_args<RT1, RT2>::type gamma_q(RT1 a, RT2 z, const Policy&);
+
+ template <class RT1, class RT2>
+ typename tools::promote_args<RT1, RT2>::type gamma_p(RT1 a, RT2 z);
+
+ template <class RT1, class RT2, class Policy>
+ typename tools::promote_args<RT1, RT2>::type gamma_p(RT1 a, RT2 z, const Policy&);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type tgamma_delta_ratio(T1 z, T2 delta);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type tgamma_delta_ratio(T1 z, T2 delta, const Policy&);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type tgamma_ratio(T1 a, T2 b);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type tgamma_ratio(T1 a, T2 b, const Policy&);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type gamma_p_derivative(T1 a, T2 x);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type gamma_p_derivative(T1 a, T2 x, const Policy&);
+
+ // gamma inverse.
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type gamma_p_inv(T1 a, T2 p);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type gamma_p_inva(T1 a, T2 p, const Policy&);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type gamma_p_inva(T1 a, T2 p);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type gamma_p_inv(T1 a, T2 p, const Policy&);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type gamma_q_inv(T1 a, T2 q);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type gamma_q_inv(T1 a, T2 q, const Policy&);
+
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type gamma_q_inva(T1 a, T2 q);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type gamma_q_inva(T1 a, T2 q, const Policy&);
+
+ // digamma:
+ template <class T>
+ typename tools::promote_args<T>::type digamma(T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type digamma(T x, const Policy&);
+
+ // Hypotenuse function sqrt(x ^ 2 + y ^ 2).
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type
+ hypot(T1 x, T2 y);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type
+ hypot(T1 x, T2 y, const Policy&);
+
+ // cbrt - cube root.
+ template <class RT>
+ typename tools::promote_args<RT>::type cbrt(RT z);
+
+ template <class RT, class Policy>
+ typename tools::promote_args<RT>::type cbrt(RT z, const Policy&);
+
+ // log1p is log(x + 1)
+ template <class T>
+ typename tools::promote_args<T>::type log1p(T);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type log1p(T, const Policy&);
+
+ // log1pmx is log(x + 1) - x
+ template <class T>
+ typename tools::promote_args<T>::type log1pmx(T);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type log1pmx(T, const Policy&);
+
+ // Exp (x) minus 1 functions.
+ template <class T>
+ typename tools::promote_args<T>::type expm1(T);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type expm1(T, const Policy&);
+
+ // Power - 1
+ template <class T1, class T2>
+ typename tools::promote_args<T1, T2>::type
+ powm1(const T1 a, const T2 z);
+
+ template <class T1, class T2, class Policy>
+ typename tools::promote_args<T1, T2>::type
+ powm1(const T1 a, const T2 z, const Policy&);
+
+ // sqrt(1+x) - 1
+ template <class T>
+ typename tools::promote_args<T>::type sqrt1pm1(const T& val);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type sqrt1pm1(const T& val, const Policy&);
+
+ // sinus cardinals:
+ template <class T>
+ typename tools::promote_args<T>::type sinc_pi(T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type sinc_pi(T x, const Policy&);
+
+ template <class T>
+ typename tools::promote_args<T>::type sinhc_pi(T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type sinhc_pi(T x, const Policy&);
+
+ // inverse hyperbolics:
+ template<typename T>
+ typename tools::promote_args<T>::type asinh(T x);
+
+ template<typename T, class Policy>
+ typename tools::promote_args<T>::type asinh(T x, const Policy&);
+
+ template<typename T>
+ typename tools::promote_args<T>::type acosh(T x);
+
+ template<typename T, class Policy>
+ typename tools::promote_args<T>::type acosh(T x, const Policy&);
+
+ template<typename T>
+ typename tools::promote_args<T>::type atanh(T x);
+
+ template<typename T, class Policy>
+ typename tools::promote_args<T>::type atanh(T x, const Policy&);
+
+ namespace detail{
+
+ typedef mpl::int_<0> bessel_no_int_tag; // No integer optimisation possible.
+ typedef mpl::int_<1> bessel_maybe_int_tag; // Maybe integer optimisation.
+ typedef mpl::int_<2> bessel_int_tag; // Definite integer optimistaion.
+
+ template <class T1, class T2, class Policy>
+ struct bessel_traits
+ {
+ typedef typename tools::promote_args<
+ T1, T2
+ >::type result_type;
+
+ 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> > >,
+ bessel_no_int_tag,
+ typename mpl::if_<
+ is_integral<T1>,
+ bessel_int_tag,
+ bessel_maybe_int_tag
+ >::type
+ >::type optimisation_tag;
+ };
+ } // detail
+
+ // Bessel functions:
+ template <class T1, class T2, class Policy>
+ typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_j(T1 v, T2 x, const Policy& pol);
+
+ template <class T1, class T2>
+ typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_j(T1 v, T2 x);
+
+ template <class T, class Policy>
+ typename detail::bessel_traits<T, T, Policy>::result_type sph_bessel(unsigned v, T x, const Policy& pol);
+
+ template <class T>
+ typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_bessel(unsigned v, T x);
+
+ template <class T1, class T2, class Policy>
+ typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_i(T1 v, T2 x, const Policy& pol);
+
+ template <class T1, class T2>
+ typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_i(T1 v, T2 x);
+
+ template <class T1, class T2, class Policy>
+ typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_k(T1 v, T2 x, const Policy& pol);
+
+ template <class T1, class T2>
+ typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_k(T1 v, T2 x);
+
+ template <class T1, class T2, class Policy>
+ typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_neumann(T1 v, T2 x, const Policy& pol);
+
+ template <class T1, class T2>
+ typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_neumann(T1 v, T2 x);
+
+ template <class T, class Policy>
+ typename detail::bessel_traits<T, T, Policy>::result_type sph_neumann(unsigned v, T x, const Policy& pol);
+
+ template <class T>
+ typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_neumann(unsigned v, T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type sin_pi(T x, const Policy&);
+
+ template <class T>
+ typename tools::promote_args<T>::type sin_pi(T x);
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type cos_pi(T x, const Policy&);
+
+ template <class T>
+ typename tools::promote_args<T>::type cos_pi(T x);
+
+ template <class T>
+ int fpclassify BOOST_NO_MACRO_EXPAND(T t);
+
+ template <class T>
+ bool isfinite BOOST_NO_MACRO_EXPAND(T z);
+
+ template <class T>
+ bool isinf BOOST_NO_MACRO_EXPAND(T t);
+
+ template <class T>
+ bool isnan BOOST_NO_MACRO_EXPAND(T t);
+
+ template <class T>
+ bool isnormal BOOST_NO_MACRO_EXPAND(T t);
+
+ template<class T>
+ int signbit BOOST_NO_MACRO_EXPAND(T x);
+
+ template <class T>
+ int sign BOOST_NO_MACRO_EXPAND(const T& z);
+
+ template <class T>
+ T copysign BOOST_NO_MACRO_EXPAND(const T& x, const T& y);
+
+ template <class T>
+ T changesign BOOST_NO_MACRO_EXPAND(const T& z);
+
+ // Exponential integrals:
+ namespace detail{
+
+ template <class T, class U>
+ struct expint_result
+ {
+ typedef typename mpl::if_<
+ policies::is_policy<U>,
+ typename tools::promote_args<T>::type,
+ typename tools::promote_args<U>::type
+ >::type type;
+ };
+
+ } // namespace detail
+
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type expint(unsigned n, T z, const Policy&);
+
+ template <class T, class U>
+ typename detail::expint_result<T, U>::type expint(T const z, U const u);
+
+ template <class T>
+ typename tools::promote_args<T>::type expint(T z);
+
+ // Zeta:
+ template <class T, class Policy>
+ typename tools::promote_args<T>::type zeta(T s, const Policy&);
+
+ template <class T>
+ typename tools::promote_args<T>::type zeta(T s);
+
+ // pow:
+ template <int N, typename T, class Policy>
+ typename tools::promote_args<T>::type pow(T base, const Policy& policy);
+
+ template <int N, typename T>
+ typename tools::promote_args<T>::type pow(T base);
+
+ // next:
+ template <class T, class Policy>
+ T nextafter(const T&, const T&, const Policy&);
+ template <class T>
+ T nextafter(const T&, const T&);
+ template <class T, class Policy>
+ T float_next(const T&, const Policy&);
+ template <class T>
+ T float_next(const T&);
+ template <class T, class Policy>
+ T float_prior(const T&, const Policy&);
+ template <class T>
+ T float_prior(const T&);
+ template <class T, class Policy>
+ T float_distance(const T&, const T&, const Policy&);
+ template <class T>
+ T float_distance(const T&, const T&);
+
+ } // namespace math
+} // namespace boost
+
+#ifdef BOOST_HAS_LONG_LONG
+#define BOOST_MATH_DETAIL_LL_FUNC(Policy)\
+ \
+ template <class T>\
+ inline T modf(const T& v, boost::long_long_type* ipart){ using boost::math::modf; return modf(v, ipart, Policy()); }\
+ \
+ template <class T>\
+ inline boost::long_long_type lltrunc(const T& v){ using boost::math::lltrunc; return lltrunc(v, Policy()); }\
+ \
+ template <class T>\
+ inline boost::long_long_type llround(const T& v){ using boost::math::llround; return llround(v, Policy()); }\
+
+#else
+#define BOOST_MATH_DETAIL_LL_FUNC(Policy)
+#endif
+
+#define BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(Policy)\
+ \
+ BOOST_MATH_DETAIL_LL_FUNC(Policy)\
+ \
+ template <class RT1, class RT2>\
+ inline typename boost::math::tools::promote_args<RT1, RT2>::type \
+ beta(RT1 a, RT2 b) { return ::boost::math::beta(a, b, Policy()); }\
+\
+ template <class RT1, class RT2, class A>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, A>::type \
+ beta(RT1 a, RT2 b, A x){ return ::boost::math::beta(a, b, x, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ betac(RT1 a, RT2 b, RT3 x) { return ::boost::math::betac(a, b, x, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ ibeta(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibeta(a, b, x, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ ibetac(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibetac(a, b, x, Policy()); }\
+\
+ template <class T1, class T2, class T3, class T4>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3, T4>::type \
+ ibeta_inv(T1 a, T2 b, T3 p, T4* py){ return ::boost::math::ibeta_inv(a, b, p, py, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ ibeta_inv(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_inv(a, b, p, Policy()); }\
+\
+ template <class T1, class T2, class T3, class T4>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3, T4>::type \
+ ibetac_inv(T1 a, T2 b, T3 q, T4* py){ return ::boost::math::ibetac_inv(a, b, q, py, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ ibeta_inva(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_inva(a, b, p, Policy()); }\
+\
+ template <class T1, class T2, class T3>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
+ ibetac_inva(T1 a, T2 b, T3 q){ return ::boost::math::ibetac_inva(a, b, q, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ ibeta_invb(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_invb(a, b, p, Policy()); }\
+\
+ template <class T1, class T2, class T3>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
+ ibetac_invb(T1 a, T2 b, T3 q){ return ::boost::math::ibetac_invb(a, b, q, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ ibetac_inv(RT1 a, RT2 b, RT3 q){ return ::boost::math::ibetac_inv(a, b, q, Policy()); }\
+\
+ template <class RT1, class RT2, class RT3>\
+ inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
+ ibeta_derivative(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibeta_derivative(a, b, x, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type erf(RT z) { return ::boost::math::erf(z, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type erfc(RT z){ return ::boost::math::erfc(z, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type erf_inv(RT z) { return ::boost::math::erf_inv(z, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type erfc_inv(RT z){ return ::boost::math::erfc_inv(z, Policy()); }\
+\
+ using boost::math::legendre_next;\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type \
+ legendre_p(int l, T x){ return ::boost::math::legendre_p(l, x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type \
+ legendre_q(unsigned l, T x){ return ::boost::math::legendre_q(l, x, Policy()); }\
+\
+ using ::boost::math::legendre_next;\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type \
+ legendre_p(int l, int m, T x){ return ::boost::math::legendre_p(l, m, x, Policy()); }\
+\
+ using ::boost::math::laguerre_next;\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type \
+ laguerre(unsigned n, T x){ return ::boost::math::laguerre(n, x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::laguerre_result<T1, T2>::type \
+ laguerre(unsigned n, T1 m, T2 x) { return ::boost::math::laguerre(n, m, x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type \
+ hermite(unsigned n, T x){ return ::boost::math::hermite(n, x, Policy()); }\
+\
+ using boost::math::hermite_next;\
+\
+ template <class T1, class T2>\
+ inline std::complex<typename boost::math::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, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::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, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::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, Policy()); }\
+\
+ template <class T1, class T2, class Policy>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type \
+ spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);\
+\
+ template <class T1, class T2, class T3>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
+ ellint_rf(T1 x, T2 y, T3 z){ return ::boost::math::ellint_rf(x, y, z, Policy()); }\
+\
+ template <class T1, class T2, class T3>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
+ ellint_rd(T1 x, T2 y, T3 z){ return ::boost::math::ellint_rd(x, y, z, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type \
+ ellint_rc(T1 x, T2 y){ return ::boost::math::ellint_rc(x, y, Policy()); }\
+\
+ template <class T1, class T2, class T3, class T4>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3, T4>::type \
+ ellint_rj(T1 x, T2 y, T3 z, T4 p){ return boost::math::ellint_rj(x, y, z, p, Policy()); }\
+\
+ template <typename T>\
+ inline typename boost::math::tools::promote_args<T>::type ellint_2(T k){ return boost::math::ellint_2(k, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi){ return boost::math::ellint_2(k, phi, Policy()); }\
+\
+ template <typename T>\
+ inline typename boost::math::tools::promote_args<T>::type ellint_1(T k){ return boost::math::ellint_1(k, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi){ return boost::math::ellint_1(k, phi, Policy()); }\
+\
+ template <class T1, class T2, class T3>\
+ inline typename boost::math::tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi){ return boost::math::ellint_3(k, v, phi, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v){ return boost::math::ellint_3(k, v, Policy()); }\
+\
+ using boost::math::max_factorial;\
+ template <class RT>\
+ inline RT factorial(unsigned int i) { return boost::math::factorial<RT>(i, Policy()); }\
+ using boost::math::unchecked_factorial;\
+ template <class RT>\
+ inline RT double_factorial(unsigned i){ return boost::math::double_factorial<RT>(i, Policy()); }\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type falling_factorial(RT x, unsigned n){ return boost::math::falling_factorial(x, n, Policy()); }\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type rising_factorial(RT x, unsigned n){ return boost::math::rising_factorial(x, n, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type tgamma(RT z){ return boost::math::tgamma(z, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type tgamma1pm1(RT z){ return boost::math::tgamma1pm1(z, Policy()); }\
+\
+ template <class RT1, class RT2>\
+ inline typename boost::math::tools::promote_args<RT1, RT2>::type tgamma(RT1 a, RT2 z){ return boost::math::tgamma(a, z, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type lgamma(RT z, int* sign){ return boost::math::lgamma(z, sign, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type lgamma(RT x){ return boost::math::lgamma(x, Policy()); }\
+\
+ template <class RT1, class RT2>\
+ inline typename boost::math::tools::promote_args<RT1, RT2>::type tgamma_lower(RT1 a, RT2 z){ return boost::math::tgamma_lower(a, z, Policy()); }\
+\
+ template <class RT1, class RT2>\
+ inline typename boost::math::tools::promote_args<RT1, RT2>::type gamma_q(RT1 a, RT2 z){ return boost::math::gamma_q(a, z, Policy()); }\
+\
+ template <class RT1, class RT2>\
+ inline typename boost::math::tools::promote_args<RT1, RT2>::type gamma_p(RT1 a, RT2 z){ return boost::math::gamma_p(a, z, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type tgamma_delta_ratio(T1 z, T2 delta){ return boost::math::tgamma_delta_ratio(z, delta, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type tgamma_ratio(T1 a, T2 b) { return boost::math::tgamma_ratio(a, b, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type gamma_p_derivative(T1 a, T2 x){ return boost::math::gamma_p_derivative(a, x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type gamma_p_inv(T1 a, T2 p){ return boost::math::gamma_p_inv(a, p, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type gamma_p_inva(T1 a, T2 p){ return boost::math::gamma_p_inva(a, p, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type gamma_q_inv(T1 a, T2 q){ return boost::math::gamma_q_inv(a, q, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type gamma_q_inva(T1 a, T2 q){ return boost::math::gamma_q_inva(a, q, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type digamma(T x){ return boost::math::digamma(x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type \
+ hypot(T1 x, T2 y){ return boost::math::hypot(x, y, Policy()); }\
+\
+ template <class RT>\
+ inline typename boost::math::tools::promote_args<RT>::type cbrt(RT z){ return boost::math::cbrt(z, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type log1p(T x){ return boost::math::log1p(x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type log1pmx(T x){ return boost::math::log1pmx(x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type expm1(T x){ return boost::math::expm1(x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::tools::promote_args<T1, T2>::type \
+ powm1(const T1 a, const T2 z){ return boost::math::powm1(a, z, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type sqrt1pm1(const T& val){ return boost::math::sqrt1pm1(val, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type sinc_pi(T x){ return boost::math::sinc_pi(x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type sinhc_pi(T x){ return boost::math::sinhc_pi(x, Policy()); }\
+\
+ template<typename T>\
+ inline typename boost::math::tools::promote_args<T>::type asinh(const T x){ return boost::math::asinh(x, Policy()); }\
+\
+ template<typename T>\
+ inline typename boost::math::tools::promote_args<T>::type acosh(const T x){ return boost::math::acosh(x, Policy()); }\
+\
+ template<typename T>\
+ inline typename boost::math::tools::promote_args<T>::type atanh(const T x){ return boost::math::atanh(x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type cyl_bessel_j(T1 v, T2 x)\
+ { return boost::math::cyl_bessel_j(v, x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::detail::bessel_traits<T, T, Policy >::result_type sph_bessel(unsigned v, T x)\
+ { return boost::math::sph_bessel(v, x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type \
+ cyl_bessel_i(T1 v, T2 x) { return boost::math::cyl_bessel_i(v, x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type \
+ cyl_bessel_k(T1 v, T2 x) { return boost::math::cyl_bessel_k(v, x, Policy()); }\
+\
+ template <class T1, class T2>\
+ inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type \
+ cyl_neumann(T1 v, T2 x){ return boost::math::cyl_neumann(v, x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::detail::bessel_traits<T, T, Policy >::result_type \
+ sph_neumann(unsigned v, T x){ return boost::math::sph_neumann(v, x, Policy()); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type sin_pi(T x){ return boost::math::sin_pi(x); }\
+\
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type cos_pi(T x){ return boost::math::cos_pi(x); }\
+\
+ using boost::math::fpclassify;\
+ using boost::math::isfinite;\
+ using boost::math::isinf;\
+ using boost::math::isnan;\
+ using boost::math::isnormal;\
+ using boost::math::signbit;\
+ using boost::math::sign;\
+ using boost::math::copysign;\
+ using boost::math::changesign;\
+ \
+ template <class T, class U>\
+ inline typename boost::math::tools::promote_args<T,U>::type expint(T const& z, U const& u)\
+ { return boost::math::expint(z, u, Policy()); }\
+ \
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type expint(T z){ return boost::math::expint(z, Policy()); }\
+ \
+ template <class T>\
+ inline typename boost::math::tools::promote_args<T>::type zeta(T s){ return boost::math::zeta(s, Policy()); }\
+ \
+ template <class T>\
+ inline T round(const T& v){ using boost::math::round; return round(v, Policy()); }\
+ \
+ template <class T>\
+ inline int iround(const T& v){ using boost::math::iround; return iround(v, Policy()); }\
+ \
+ template <class T>\
+ inline long lround(const T& v){ using boost::math::lround; return lround(v, Policy()); }\
+ \
+ template <class T>\
+ inline T trunc(const T& v){ using boost::math::trunc; return trunc(v, Policy()); }\
+ \
+ template <class T>\
+ inline int itrunc(const T& v){ using boost::math::itrunc; return itrunc(v, Policy()); }\
+ \
+ template <class T>\
+ inline long ltrunc(const T& v){ using boost::math::ltrunc; return ltrunc(v, Policy()); }\
+ \
+ template <class T>\
+ inline T modf(const T& v, T* ipart){ using boost::math::modf; return modf(v, ipart, Policy()); }\
+ \
+ template <class T>\
+ inline T modf(const T& v, int* ipart){ using boost::math::modf; return modf(v, ipart, Policy()); }\
+ \
+ template <class T>\
+ inline T modf(const T& v, long* ipart){ using boost::math::modf; return modf(v, ipart, Policy()); }\
+ \
+ template <int N, class T>\
+ inline typename boost::math::tools::promote_args<T>::type pow(T v){ return boost::math::pow<N>(v, Policy()); }\
+ \
+ template <class T> T nextafter(const T& a, const T& b){ return boost::math::nextafter(a, b, Policy()); }\
+ template <class T> T float_next(const T& a){ return boost::math::float_next(a, Policy()); }\
+ template <class T> T float_prior(const T& a){ return boost::math::float_prior(a, Policy()); }\
+ template <class T> T float_distance(const T& a, const T& b){ return boost::math::float_distance(a, b, Policy()); }\
+
+
+#endif // BOOST_MATH_SPECIAL_MATH_FWD_HPP
+
+
diff --git a/boost/math/special_functions/modf.hpp b/boost/math/special_functions/modf.hpp
new file mode 100644
index 0000000000..48b15fe44f
--- /dev/null
+++ b/boost/math/special_functions/modf.hpp
@@ -0,0 +1,70 @@
+// Copyright John Maddock 2007.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_MODF_HPP
+#define BOOST_MATH_MODF_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+
+namespace boost{ namespace math{
+
+template <class T, class Policy>
+inline T modf(const T& v, T* ipart, const Policy& pol)
+{
+ *ipart = trunc(v, pol);
+ return v - *ipart;
+}
+template <class T>
+inline T modf(const T& v, T* ipart)
+{
+ return modf(v, ipart, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline T modf(const T& v, int* ipart, const Policy& pol)
+{
+ *ipart = itrunc(v, pol);
+ return v - *ipart;
+}
+template <class T>
+inline T modf(const T& v, int* ipart)
+{
+ return modf(v, ipart, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline T modf(const T& v, long* ipart, const Policy& pol)
+{
+ *ipart = ltrunc(v, pol);
+ return v - *ipart;
+}
+template <class T>
+inline T modf(const T& v, long* ipart)
+{
+ return modf(v, ipart, policies::policy<>());
+}
+
+#ifdef BOOST_HAS_LONG_LONG
+template <class T, class Policy>
+inline T modf(const T& v, boost::long_long_type* ipart, const Policy& pol)
+{
+ *ipart = lltrunc(v, pol);
+ return v - *ipart;
+}
+template <class T>
+inline T modf(const T& v, boost::long_long_type* ipart)
+{
+ return modf(v, ipart, policies::policy<>());
+}
+#endif
+
+}} // namespaces
+
+#endif // BOOST_MATH_MODF_HPP
diff --git a/boost/math/special_functions/next.hpp b/boost/math/special_functions/next.hpp
new file mode 100644
index 0000000000..6c91cd1e38
--- /dev/null
+++ b/boost/math/special_functions/next.hpp
@@ -0,0 +1,320 @@
+// (C) Copyright John Maddock 2008.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SPECIAL_NEXT_HPP
+#define BOOST_MATH_SPECIAL_NEXT_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+
+#ifdef BOOST_MSVC
+#include <float.h>
+#endif
+
+namespace boost{ namespace math{
+
+namespace detail{
+
+template <class T>
+inline T get_smallest_value(mpl::true_ const&)
+{
+ return std::numeric_limits<T>::denorm_min();
+}
+
+template <class T>
+inline T get_smallest_value(mpl::false_ const&)
+{
+ return tools::min_value<T>();
+}
+
+template <class T>
+inline T get_smallest_value()
+{
+#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)
+ return get_smallest_value<T>(mpl::bool_<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == 1)>());
+#else
+ return get_smallest_value<T>(mpl::bool_<std::numeric_limits<T>::is_specialized && (std::numeric_limits<T>::has_denorm == std::denorm_present)>());
+#endif
+}
+
+}
+
+template <class T, class Policy>
+T float_next(const T& val, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ int expon;
+ static const char* function = "float_next<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val))
+ {
+ if(val < 0)
+ return -tools::max_value<T>();
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+ }
+
+ if(val >= tools::max_value<T>())
+ return policies::raise_overflow_error<T>(function, 0, pol);
+
+ if(val == 0)
+ return detail::get_smallest_value<T>();
+
+ if(-0.5f == frexp(val, &expon))
+ --expon; // reduce exponent when val is a power of two, and negative.
+ T diff = ldexp(T(1), expon - tools::digits<T>());
+ if(diff == 0)
+ diff = detail::get_smallest_value<T>();
+ return val + diff;
+}
+
+#ifdef BOOST_MSVC
+template <class Policy>
+inline double float_next(const double& val, const Policy& pol)
+{
+ static const char* function = "float_next<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val) && (val > 0))
+ return policies::raise_domain_error<double>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+
+ if(val >= tools::max_value<double>())
+ return policies::raise_overflow_error<double>(function, 0, pol);
+
+ return ::_nextafter(val, tools::max_value<double>());
+}
+#endif
+
+template <class T>
+inline T float_next(const T& val)
+{
+ return float_next(val, policies::policy<>());
+}
+
+template <class T, class Policy>
+T float_prior(const T& val, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ int expon;
+ static const char* function = "float_prior<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val))
+ {
+ if(val > 0)
+ return tools::max_value<T>();
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+ }
+
+ if(val <= -tools::max_value<T>())
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+
+ if(val == 0)
+ return -detail::get_smallest_value<T>();
+
+ T remain = frexp(val, &expon);
+ if(remain == 0.5)
+ --expon; // when val is a power of two we must reduce the exponent
+ T diff = ldexp(T(1), expon - tools::digits<T>());
+ if(diff == 0)
+ diff = detail::get_smallest_value<T>();
+ return val - diff;
+}
+
+#ifdef BOOST_MSVC
+template <class Policy>
+inline double float_prior(const double& val, const Policy& pol)
+{
+ static const char* function = "float_prior<%1%>(%1%)";
+
+ if(!(boost::math::isfinite)(val) && (val < 0))
+ return policies::raise_domain_error<double>(
+ function,
+ "Argument must be finite, but got %1%", val, pol);
+
+ if(val <= -tools::max_value<double>())
+ return -policies::raise_overflow_error<double>(function, 0, pol);
+
+ return ::_nextafter(val, -tools::max_value<double>());
+}
+#endif
+
+template <class T>
+inline T float_prior(const T& val)
+{
+ return float_prior(val, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline T nextafter(const T& val, const T& direction, const Policy& pol)
+{
+ return val < direction ? boost::math::float_next(val, pol) : val == direction ? val : boost::math::float_prior(val, pol);
+}
+
+template <class T>
+inline T nextafter(const T& val, const T& direction)
+{
+ return nextafter(val, direction, policies::policy<>());
+}
+
+template <class T, class Policy>
+T float_distance(const T& a, const T& b, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ //
+ // Error handling:
+ //
+ static const char* function = "float_distance<%1%>(%1%, %1%)";
+ if(!(boost::math::isfinite)(a))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument a must be finite, but got %1%", a, pol);
+ if(!(boost::math::isfinite)(b))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument b must be finite, but got %1%", b, pol);
+ //
+ // Special cases:
+ //
+ if(a > b)
+ return -float_distance(b, a);
+ if(a == b)
+ return 0;
+ if(a == 0)
+ return 1 + fabs(float_distance(static_cast<T>(boost::math::sign(b) * detail::get_smallest_value<T>()), b, pol));
+ if(b == 0)
+ return 1 + fabs(float_distance(static_cast<T>(boost::math::sign(a) * detail::get_smallest_value<T>()), a, pol));
+ if(boost::math::sign(a) != boost::math::sign(b))
+ return 2 + fabs(float_distance(static_cast<T>(boost::math::sign(b) * detail::get_smallest_value<T>()), b, pol))
+ + fabs(float_distance(static_cast<T>(boost::math::sign(a) * detail::get_smallest_value<T>()), a, pol));
+ //
+ // By the time we get here, both a and b must have the same sign, we want
+ // b > a and both postive for the following logic:
+ //
+ if(a < 0)
+ return float_distance(static_cast<T>(-b), static_cast<T>(-a));
+
+ BOOST_ASSERT(a >= 0);
+ BOOST_ASSERT(b >= a);
+
+ int expon;
+ //
+ // Note that if a is a denorm then the usual formula fails
+ // because we actually have fewer than tools::digits<T>()
+ // significant bits in the representation:
+ //
+ frexp(((boost::math::fpclassify)(a) == FP_SUBNORMAL) ? tools::min_value<T>() : a, &expon);
+ T upper = ldexp(T(1), expon);
+ T result = 0;
+ expon = tools::digits<T>() - expon;
+ //
+ // If b is greater than upper, then we *must* split the calculation
+ // as the size of the ULP changes with each order of magnitude change:
+ //
+ if(b > upper)
+ {
+ result = float_distance(upper, b);
+ }
+ //
+ // Use compensated double-double addition to avoid rounding
+ // errors in the subtraction:
+ //
+ T mb = -(std::min)(upper, b);
+ T x = a + mb;
+ T z = x - a;
+ T y = (a - (x - z)) + (mb - z);
+ if(x < 0)
+ {
+ x = -x;
+ y = -y;
+ }
+ result += ldexp(x, expon) + ldexp(y, expon);
+ //
+ // Result must be an integer:
+ //
+ BOOST_ASSERT(result == floor(result));
+ return result;
+}
+
+template <class T>
+T float_distance(const T& a, const T& b)
+{
+ return boost::math::float_distance(a, b, policies::policy<>());
+}
+
+template <class T, class Policy>
+T float_advance(T val, int distance, const Policy& pol)
+{
+ //
+ // Error handling:
+ //
+ static const char* function = "float_advance<%1%>(%1%, int)";
+ if(!(boost::math::isfinite)(val))
+ return policies::raise_domain_error<T>(
+ function,
+ "Argument val must be finite, but got %1%", val, pol);
+
+ if(val < 0)
+ return -float_advance(-val, -distance, pol);
+ if(distance == 0)
+ return val;
+ if(distance == 1)
+ return float_next(val, pol);
+ if(distance == -1)
+ return float_prior(val, pol);
+ BOOST_MATH_STD_USING
+ int expon;
+ frexp(val, &expon);
+ T limit = ldexp((distance < 0 ? T(0.5f) : T(1)), expon);
+ if(val <= tools::min_value<T>())
+ {
+ limit = sign(T(distance)) * tools::min_value<T>();
+ }
+ T limit_distance = float_distance(val, limit);
+ while(fabs(limit_distance) < abs(distance))
+ {
+ distance -= itrunc(limit_distance);
+ val = limit;
+ if(distance < 0)
+ {
+ limit /= 2;
+ expon--;
+ }
+ else
+ {
+ limit *= 2;
+ expon++;
+ }
+ limit_distance = float_distance(val, limit);
+ }
+ if((0.5f == frexp(val, &expon)) && (distance < 0))
+ --expon;
+ T diff = 0;
+ if(val != 0)
+ diff = distance * ldexp(T(1), expon - tools::digits<T>());
+ if(diff == 0)
+ diff = distance * detail::get_smallest_value<T>();
+ return val += diff;
+}
+
+template <class T>
+inline T float_advance(const T& val, int distance)
+{
+ return boost::math::float_advance(val, distance, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_SPECIAL_NEXT_HPP
+
diff --git a/boost/math/special_functions/nonfinite_num_facets.hpp b/boost/math/special_functions/nonfinite_num_facets.hpp
new file mode 100644
index 0000000000..9fa61481b5
--- /dev/null
+++ b/boost/math/special_functions/nonfinite_num_facets.hpp
@@ -0,0 +1,543 @@
+#ifndef BOOST_MATH_NONFINITE_NUM_FACETS_HPP
+#define BOOST_MATH_NONFINITE_NUM_FACETS_HPP
+
+// Copyright (c) 2006 Johan Rade
+// Copyright 2011 Paul A. Bristow (comments)
+
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt
+// or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+/*
+\file
+
+\brief non_finite_num facets for C99 standard output of infinity and NaN.
+
+\details See fuller documentation at Boost.Math Facets
+ for Floating-Point Infinities and NaNs.
+*/
+
+#include <cstring>
+#include <ios>
+#include <limits>
+#include <locale>
+
+#include <boost/version.hpp>
+
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/sign.hpp>
+
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable : 4127) // conditional expression is constant.
+# pragma warning(disable : 4706) // assignment within conditional expression.
+# pragma warning(disable : 4224) // formal parameter 'version' was previously defined as a type.
+#endif
+
+namespace boost {
+ namespace math {
+
+ // flags (enums can be ORed together) -----------------------------------
+
+ const int legacy = 0x1; //!< get facet will recognize most string representations of infinity and NaN.
+ const int signed_zero = 0x2; //!< put facet will distinguish between positive and negative zero.
+ const int trap_infinity = 0x4; /*!< put facet will throw an exception of type std::ios_base::failure
+ when an attempt is made to format positive or negative infinity.
+ get will set the fail bit of the stream when an attempt is made
+ to parse a string that represents positive or negative sign infinity.
+ */
+ const int trap_nan = 0x8; /*!< put facet will throw an exception of type std::ios_base::failure
+ when an attempt is made to format positive or negative NaN.
+ get will set the fail bit of the stream when an attempt is made
+ to parse a string that represents positive or negative sign infinity.
+ */
+
+ // class nonfinite_num_put -----------------------------------------------------
+
+ template<
+ class CharType,
+ class OutputIterator = std::ostreambuf_iterator<CharType>
+ >
+ class nonfinite_num_put : public std::num_put<CharType, OutputIterator>
+ {
+ public:
+ explicit nonfinite_num_put(int flags = 0) : flags_(flags) {}
+
+ protected:
+ virtual OutputIterator do_put(
+ OutputIterator it, std::ios_base& iosb,
+ CharType fill, double val) const
+ {
+ put_and_reset_width(it, iosb, fill, val);
+ return it;
+ }
+
+ virtual OutputIterator do_put(
+ OutputIterator it, std::ios_base& iosb,
+ CharType fill, long double val) const
+ {
+ put_and_reset_width(it, iosb, fill, val);
+ return it;
+ }
+
+ private:
+ template<class ValType> void put_and_reset_width(
+ OutputIterator& it, std::ios_base& iosb,
+ CharType fill, ValType val) const
+ {
+ put_impl(it, iosb, fill, val);
+ iosb.width(0);
+ }
+
+ template<class ValType> void put_impl(
+ OutputIterator& it, std::ios_base& iosb,
+ CharType fill, ValType val) const
+ {
+ switch((boost::math::fpclassify)(val)) {
+
+ case FP_INFINITE:
+ if(flags_ & trap_infinity)
+ throw std::ios_base::failure("Infinity");
+ else if((boost::math::signbit)(val))
+ put_num_and_fill(it, iosb, "-", "inf", fill);
+ else if(iosb.flags() & std::ios_base::showpos)
+ put_num_and_fill(it, iosb, "+", "inf", fill);
+ else
+ put_num_and_fill(it, iosb, "", "inf", fill);
+ break;
+
+ case FP_NAN:
+ if(flags_ & trap_nan)
+ throw std::ios_base::failure("NaN");
+ else if((boost::math::signbit)(val))
+ put_num_and_fill(it, iosb, "-", "nan", fill);
+ else if(iosb.flags() & std::ios_base::showpos)
+ put_num_and_fill(it, iosb, "+", "nan", fill);
+ else
+ put_num_and_fill(it, iosb, "", "nan", fill);
+ break;
+
+ case FP_ZERO:
+ if(flags_ & signed_zero) {
+ if((boost::math::signbit)(val))
+ put_num_and_fill(it, iosb, "-", "0", fill);
+ else if(iosb.flags() & std::ios_base::showpos)
+ put_num_and_fill(it, iosb, "+", "0", fill);
+ else
+ put_num_and_fill(it, iosb, "", "0", fill);
+ }
+ else
+ put_num_and_fill(it, iosb, "", "0", fill);
+ break;
+
+ default:
+ it = std::num_put<CharType, OutputIterator>::do_put(
+ it, iosb, fill, val);
+ break;
+ }
+ }
+
+ void put_num_and_fill(
+ OutputIterator& it, std::ios_base& iosb, const char* prefix,
+ const char* body, CharType fill) const
+ {
+ int width = (int)std::strlen(prefix) + (int)std::strlen(body);
+ std::ios_base::fmtflags adjust
+ = iosb.flags() & std::ios_base::adjustfield;
+ const std::ctype<CharType>& ct
+ = std::use_facet<std::ctype<CharType> >(iosb.getloc());
+
+ if(adjust != std::ios_base::internal && adjust != std::ios_base::left)
+ put_fill(it, iosb, fill, width);
+
+ while(*prefix)
+ *it = ct.widen(*(prefix++));
+
+ if(adjust == std::ios_base::internal)
+ put_fill(it, iosb, fill, width);
+
+ if(iosb.flags() & std::ios_base::uppercase) {
+ while(*body)
+ *it = ct.toupper(ct.widen(*(body++)));
+ }
+ else {
+ while(*body)
+ *it = ct.widen(*(body++));
+ }
+
+ if(adjust == std::ios_base::left)
+ put_fill(it, iosb, fill, width);
+ }
+
+ void put_fill(
+ OutputIterator& it, std::ios_base& iosb,
+ CharType fill, int width) const
+ {
+ for(std::streamsize i = iosb.width() - static_cast<std::streamsize>(width); i > 0; --i)
+ *it = fill;
+ }
+
+ private:
+ const int flags_;
+ };
+
+
+ // class nonfinite_num_get ------------------------------------------------------
+
+ template<
+ class CharType,
+ class InputIterator = std::istreambuf_iterator<CharType>
+ >
+ class nonfinite_num_get : public std::num_get<CharType, InputIterator>
+ {
+
+ public:
+ explicit nonfinite_num_get(int flags = 0) : flags_(flags)
+ {}
+
+ protected: // float, double and long double versions of do_get.
+ virtual InputIterator do_get(
+ InputIterator it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, float& val) const
+ {
+ get_and_check_eof(it, end, iosb, state, val);
+ return it;
+ }
+
+ virtual InputIterator do_get(
+ InputIterator it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, double& val) const
+ {
+ get_and_check_eof(it, end, iosb, state, val);
+ return it;
+ }
+
+ virtual InputIterator do_get(
+ InputIterator it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, long double& val) const
+ {
+ get_and_check_eof(it, end, iosb, state, val);
+ return it;
+ }
+
+ //..............................................................................
+
+ private:
+ template<class ValType> static ValType positive_nan()
+ {
+ // On some platforms quiet_NaN() may be negative.
+ return (boost::math::copysign)(
+ std::numeric_limits<ValType>::quiet_NaN(), static_cast<ValType>(1)
+ );
+ // static_cast<ValType>(1) added Paul A. Bristow 5 Apr 11
+ }
+
+ template<class ValType> void get_and_check_eof
+ (
+ InputIterator& it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ get_signed(it, end, iosb, state, val);
+ if(it == end)
+ state |= std::ios_base::eofbit;
+ }
+
+ template<class ValType> void get_signed
+ (
+ InputIterator& it, InputIterator end, std::ios_base& iosb,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ const std::ctype<CharType>& ct
+ = std::use_facet<std::ctype<CharType> >(iosb.getloc());
+
+ char c = peek_char(it, end, ct);
+
+ bool negative = (c == '-');
+
+ if(negative || c == '+')
+ {
+ ++it;
+ c = peek_char(it, end, ct);
+ if(c == '-' || c == '+')
+ { // Without this check, "++5" etc would be accepted.
+ state |= std::ios_base::failbit;
+ return;
+ }
+ }
+
+ get_unsigned(it, end, iosb, ct, state, val);
+
+ if(negative)
+ {
+ val = (boost::math::changesign)(val);
+ }
+ } // void get_signed
+
+ template<class ValType> void get_unsigned
+ ( //! Get an unsigned floating-point value into val,
+ //! but checking for letters indicating non-finites.
+ InputIterator& it, InputIterator end, std::ios_base& iosb,
+ const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ switch(peek_char(it, end, ct))
+ {
+ case 'i':
+ get_i(it, end, ct, state, val);
+ break;
+
+ case 'n':
+ get_n(it, end, ct, state, val);
+ break;
+
+ case 'q':
+ case 's':
+ get_q(it, end, ct, state, val);
+ break;
+
+ default: // Got a normal floating-point value into val.
+ it = std::num_get<CharType, InputIterator>::do_get(
+ it, end, iosb, state, val);
+ if((flags_ & legacy) && val == static_cast<ValType>(1)
+ && peek_char(it, end, ct) == '#')
+ get_one_hash(it, end, ct, state, val);
+ break;
+ }
+ } // get_unsigned
+
+ //..........................................................................
+
+ template<class ValType> void get_i
+ ( // Get the rest of all strings starting with 'i', expect "inf", "infinity".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ if(!std::numeric_limits<ValType>::has_infinity
+ || (flags_ & trap_infinity))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "nf"))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ if(peek_char(it, end, ct) != 'i')
+ {
+ val = std::numeric_limits<ValType>::infinity(); // "inf"
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "nity"))
+ { // Expected "infinity"
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ val = std::numeric_limits<ValType>::infinity(); // "infinity"
+ } // void get_i
+
+ template<class ValType> void get_n
+ ( // Get expected strings after 'n', "nan", "nanq", "nans", "nan(...)"
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ if(!std::numeric_limits<ValType>::has_quiet_NaN
+ || (flags_ & trap_nan)) {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "an"))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ switch(peek_char(it, end, ct)) {
+ case 'q':
+ case 's':
+ if(flags_ && legacy)
+ ++it;
+ break; // "nanq", "nans"
+
+ case '(': // Optional payload field in (...) follows.
+ {
+ ++it;
+ char c;
+ while((c = peek_char(it, end, ct))
+ && c != ')' && c != ' ' && c != '\n' && c != '\t')
+ ++it;
+ if(c != ')')
+ { // Optional payload field terminator missing!
+ state |= std::ios_base::failbit;
+ return;
+ }
+ ++it;
+ break; // "nan(...)"
+ }
+
+ default:
+ break; // "nan"
+ }
+
+ val = positive_nan<ValType>();
+ } // void get_n
+
+ template<class ValType> void get_q
+ ( // Get expected rest of string starting with 'q': "qnan".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ if(!std::numeric_limits<ValType>::has_quiet_NaN
+ || (flags_ & trap_nan) || !(flags_ & legacy))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ ++it;
+ if(!match_string(it, end, ct, "nan"))
+ {
+ state |= std::ios_base::failbit;
+ return;
+ }
+
+ val = positive_nan<ValType>(); // "QNAN"
+ } // void get_q
+
+ template<class ValType> void get_one_hash
+ ( // Get expected string after having read "1.#": "1.#IND", "1.#QNAN", "1.#SNAN".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+
+ ++it;
+ switch(peek_char(it, end, ct))
+ {
+ case 'i': // from IND (indeterminate), considered same a QNAN.
+ get_one_hash_i(it, end, ct, state, val); // "1.#IND"
+ return;
+
+ case 'q': // from QNAN
+ case 's': // from SNAN - treated the same as QNAN.
+ if(std::numeric_limits<ValType>::has_quiet_NaN
+ && !(flags_ & trap_nan))
+ {
+ ++it;
+ if(match_string(it, end, ct, "nan"))
+ { // "1.#QNAN", "1.#SNAN"
+ // ++it; // removed as caused assert() cannot increment iterator).
+// (match_string consumes string, so not needed?).
+// https://svn.boost.org/trac/boost/ticket/5467
+// Change in nonfinite_num_facet.hpp Paul A. Bristow 11 Apr 11 makes legacy_test.cpp work OK.
+ val = positive_nan<ValType>(); // "1.#QNAN"
+ return;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ state |= std::ios_base::failbit;
+ } // void get_one_hash
+
+ template<class ValType> void get_one_hash_i
+ ( // Get expected strings after 'i', "1.#INF", 1.#IND".
+ InputIterator& it, InputIterator end, const std::ctype<CharType>& ct,
+ std::ios_base::iostate& state, ValType& val
+ ) const
+ {
+ ++it;
+
+ if(peek_char(it, end, ct) == 'n')
+ {
+ ++it;
+ switch(peek_char(it, end, ct))
+ {
+ case 'f': // "1.#INF"
+ if(std::numeric_limits<ValType>::has_infinity
+ && !(flags_ & trap_infinity))
+ {
+ ++it;
+ val = std::numeric_limits<ValType>::infinity();
+ return;
+ }
+ break;
+
+ case 'd': // 1.#IND"
+ if(std::numeric_limits<ValType>::has_quiet_NaN
+ && !(flags_ & trap_nan))
+ {
+ ++it;
+ val = positive_nan<ValType>();
+ return;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ state |= std::ios_base::failbit;
+ } // void get_one_hash_i
+
+ //..........................................................................
+
+ char peek_char
+ ( //! \return next char in the input buffer, ensuring lowercase (but do not 'consume' char).
+ InputIterator& it, InputIterator end,
+ const std::ctype<CharType>& ct
+ ) const
+ {
+ if(it == end) return 0;
+ return ct.narrow(ct.tolower(*it), 0); // Always tolower to ensure case insensitive.
+ }
+
+ bool match_string
+ ( //! Match remaining chars to expected string (case insensitive),
+ //! consuming chars that match OK.
+ //! \return true if matched expected string, else false.
+ InputIterator& it, InputIterator end,
+ const std::ctype<CharType>& ct,
+ const char* s
+ ) const
+ {
+ while(it != end && *s && *s == ct.narrow(ct.tolower(*it), 0))
+ {
+ ++s;
+ ++it; //
+ }
+ return !*s;
+ } // bool match_string
+
+ private:
+ const int flags_;
+ }; //
+
+ //------------------------------------------------------------------------------
+
+ } // namespace math
+} // namespace boost
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+#endif
diff --git a/boost/math/special_functions/pow.hpp b/boost/math/special_functions/pow.hpp
new file mode 100644
index 0000000000..5423e9c8e4
--- /dev/null
+++ b/boost/math/special_functions/pow.hpp
@@ -0,0 +1,140 @@
+// Boost pow.hpp header file
+// Computes a power with exponent known at compile-time
+
+// (C) Copyright Bruno Lalande 2008.
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for updates, documentation, and revision history.
+
+
+#ifndef BOOST_MATH_POW_HPP
+#define BOOST_MATH_POW_HPP
+
+
+#include <boost/math/policies/policy.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/mpl/greater_equal.hpp>
+
+
+namespace boost {
+namespace math {
+
+
+namespace detail {
+
+
+template <int N, int M = N%2>
+struct positive_power
+{
+ template <typename T>
+ static T result(T base)
+ {
+ T power = positive_power<N/2>::result(base);
+ return power * power;
+ }
+};
+
+template <int N>
+struct positive_power<N, 1>
+{
+ template <typename T>
+ static T result(T base)
+ {
+ T power = positive_power<N/2>::result(base);
+ return base * power * power;
+ }
+};
+
+template <>
+struct positive_power<1, 1>
+{
+ template <typename T>
+ static T result(T base){ return base; }
+};
+
+
+template <int N, bool>
+struct power_if_positive
+{
+ template <typename T, class Policy>
+ static T result(T base, const Policy&)
+ { return positive_power<N>::result(base); }
+};
+
+template <int N>
+struct power_if_positive<N, false>
+{
+ template <typename T, class Policy>
+ static T result(T base, const Policy& policy)
+ {
+ if (base == 0)
+ {
+ return policies::raise_overflow_error<T>(
+ "boost::math::pow(%1%)",
+ "Attempted to compute a negative power of 0",
+ policy
+ );
+ }
+
+ return T(1) / positive_power<-N>::result(base);
+ }
+};
+
+template <>
+struct power_if_positive<0, true>
+{
+ template <typename T, class Policy>
+ static T result(T base, const Policy& policy)
+ {
+ if (base == 0)
+ {
+ return policies::raise_indeterminate_result_error<T>(
+ "boost::math::pow(%1%)",
+ "The result of pow<0>(%1%) is undetermined",
+ base,
+ T(1),
+ policy
+ );
+ }
+
+ return T(1);
+ }
+};
+
+
+template <int N>
+struct select_power_if_positive
+{
+ typedef typename mpl::greater_equal<
+ mpl::int_<N>,
+ mpl::int_<0>
+ >::type is_positive;
+
+ typedef power_if_positive<N, is_positive::value> type;
+};
+
+
+} // namespace detail
+
+
+template <int N, typename T, class Policy>
+inline typename tools::promote_args<T>::type pow(T base, const Policy& policy)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::select_power_if_positive<N>::type::result(static_cast<result_type>(base), policy);
+}
+
+
+template <int N, typename T>
+inline typename tools::promote_args<T>::type pow(T base)
+{ return pow<N>(base, policies::policy<>()); }
+
+
+} // namespace math
+} // namespace boost
+
+
+#endif
diff --git a/boost/math/special_functions/powm1.hpp b/boost/math/special_functions/powm1.hpp
new file mode 100644
index 0000000000..cb33ae03d0
--- /dev/null
+++ b/boost/math/special_functions/powm1.hpp
@@ -0,0 +1,61 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_POWM1
+#define BOOST_MATH_POWM1
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/log1p.hpp>
+#include <boost/math/special_functions/expm1.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/assert.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+template <class T, class Policy>
+inline T powm1_imp(const T a, const T z, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ if((fabs(a) < 1) || (fabs(z) < 1))
+ {
+ T p = log(a) * z;
+ if(fabs(p) < 2)
+ return boost::math::expm1(p, pol);
+ // otherwise fall though:
+ }
+ return pow(a, z) - 1;
+}
+
+} // detail
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ powm1(const T1 a, const T2 z)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ return detail::powm1_imp(static_cast<result_type>(a), static_cast<result_type>(z), policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ powm1(const T1 a, const T2 z, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ return detail::powm1_imp(static_cast<result_type>(a), static_cast<result_type>(z), pol);
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_POWM1
+
+
+
+
+
diff --git a/boost/math/special_functions/prime.hpp b/boost/math/special_functions/prime.hpp
new file mode 100644
index 0000000000..ee25f991a3
--- /dev/null
+++ b/boost/math/special_functions/prime.hpp
@@ -0,0 +1,1219 @@
+// Copyright 2008 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_SF_PRIME_HPP
+#define BOOST_MATH_SF_PRIME_HPP
+
+#include <boost/array.hpp>
+#include <boost/cstdint.hpp>
+#include <boost/math/policies/error_handling.hpp>
+
+namespace boost{ namespace math{
+
+ template <class Policy>
+ boost::uint32_t prime(unsigned n, const Policy& pol)
+ {
+ //
+ // This is basically three big tables which together
+ // occupy 19946 bytes, we use the smallest type which
+ // will handle each value, and store the final set of
+ // values in a uint16_t with the values offset by 0xffff.
+ // That gives us the first 10000 primes with the largest
+ // being 104729:
+ //
+ static const unsigned b1 = 53;
+ static const unsigned b2 = 6541;
+ static const unsigned b3 = 10000;
+ static const boost::array<unsigned char, 54> a1 = {{
+ 2u, 3u, 5u, 7u, 11u, 13u, 17u, 19u, 23u, 29u, 31u,
+ 37u, 41u, 43u, 47u, 53u, 59u, 61u, 67u, 71u, 73u,
+ 79u, 83u, 89u, 97u, 101u, 103u, 107u, 109u, 113u,
+ 127u, 131u, 137u, 139u, 149u, 151u, 157u, 163u,
+ 167u, 173u, 179u, 181u, 191u, 193u, 197u, 199u,
+ 211u, 223u, 227u, 229u, 233u, 239u, 241u, 251u
+ }};
+ static const boost::array<boost::uint16_t, 6488> a2 = {{
+ 257u, 263u, 269u, 271u, 277u, 281u, 283u, 293u,
+ 307u, 311u, 313u, 317u, 331u, 337u, 347u, 349u, 353u,
+ 359u, 367u, 373u, 379u, 383u, 389u, 397u, 401u, 409u,
+ 419u, 421u, 431u, 433u, 439u, 443u, 449u, 457u, 461u,
+ 463u, 467u, 479u, 487u, 491u, 499u, 503u, 509u, 521u,
+ 523u, 541u, 547u, 557u, 563u, 569u, 571u, 577u, 587u,
+ 593u, 599u, 601u, 607u, 613u, 617u, 619u, 631u, 641u,
+ 643u, 647u, 653u, 659u, 661u, 673u, 677u, 683u, 691u,
+ 701u, 709u, 719u, 727u, 733u, 739u, 743u, 751u, 757u,
+ 761u, 769u, 773u, 787u, 797u, 809u, 811u, 821u, 823u,
+ 827u, 829u, 839u, 853u, 857u, 859u, 863u, 877u, 881u,
+ 883u, 887u, 907u, 911u, 919u, 929u, 937u, 941u, 947u,
+ 953u, 967u, 971u, 977u, 983u, 991u, 997u, 1009u, 1013u,
+ 1019u, 1021u, 1031u, 1033u, 1039u, 1049u, 1051u, 1061u, 1063u,
+ 1069u, 1087u, 1091u, 1093u, 1097u, 1103u, 1109u, 1117u, 1123u,
+ 1129u, 1151u, 1153u, 1163u, 1171u, 1181u, 1187u, 1193u, 1201u,
+ 1213u, 1217u, 1223u, 1229u, 1231u, 1237u, 1249u, 1259u, 1277u,
+ 1279u, 1283u, 1289u, 1291u, 1297u, 1301u, 1303u, 1307u, 1319u,
+ 1321u, 1327u, 1361u, 1367u, 1373u, 1381u, 1399u, 1409u, 1423u,
+ 1427u, 1429u, 1433u, 1439u, 1447u, 1451u, 1453u, 1459u, 1471u,
+ 1481u, 1483u, 1487u, 1489u, 1493u, 1499u, 1511u, 1523u, 1531u,
+ 1543u, 1549u, 1553u, 1559u, 1567u, 1571u, 1579u, 1583u, 1597u,
+ 1601u, 1607u, 1609u, 1613u, 1619u, 1621u, 1627u, 1637u, 1657u,
+ 1663u, 1667u, 1669u, 1693u, 1697u, 1699u, 1709u, 1721u, 1723u,
+ 1733u, 1741u, 1747u, 1753u, 1759u, 1777u, 1783u, 1787u, 1789u,
+ 1801u, 1811u, 1823u, 1831u, 1847u, 1861u, 1867u, 1871u, 1873u,
+ 1877u, 1879u, 1889u, 1901u, 1907u, 1913u, 1931u, 1933u, 1949u,
+ 1951u, 1973u, 1979u, 1987u, 1993u, 1997u, 1999u, 2003u, 2011u,
+ 2017u, 2027u, 2029u, 2039u, 2053u, 2063u, 2069u, 2081u, 2083u,
+ 2087u, 2089u, 2099u, 2111u, 2113u, 2129u, 2131u, 2137u, 2141u,
+ 2143u, 2153u, 2161u, 2179u, 2203u, 2207u, 2213u, 2221u, 2237u,
+ 2239u, 2243u, 2251u, 2267u, 2269u, 2273u, 2281u, 2287u, 2293u,
+ 2297u, 2309u, 2311u, 2333u, 2339u, 2341u, 2347u, 2351u, 2357u,
+ 2371u, 2377u, 2381u, 2383u, 2389u, 2393u, 2399u, 2411u, 2417u,
+ 2423u, 2437u, 2441u, 2447u, 2459u, 2467u, 2473u, 2477u, 2503u,
+ 2521u, 2531u, 2539u, 2543u, 2549u, 2551u, 2557u, 2579u, 2591u,
+ 2593u, 2609u, 2617u, 2621u, 2633u, 2647u, 2657u, 2659u, 2663u,
+ 2671u, 2677u, 2683u, 2687u, 2689u, 2693u, 2699u, 2707u, 2711u,
+ 2713u, 2719u, 2729u, 2731u, 2741u, 2749u, 2753u, 2767u, 2777u,
+ 2789u, 2791u, 2797u, 2801u, 2803u, 2819u, 2833u, 2837u, 2843u,
+ 2851u, 2857u, 2861u, 2879u, 2887u, 2897u, 2903u, 2909u, 2917u,
+ 2927u, 2939u, 2953u, 2957u, 2963u, 2969u, 2971u, 2999u, 3001u,
+ 3011u, 3019u, 3023u, 3037u, 3041u, 3049u, 3061u, 3067u, 3079u,
+ 3083u, 3089u, 3109u, 3119u, 3121u, 3137u, 3163u, 3167u, 3169u,
+ 3181u, 3187u, 3191u, 3203u, 3209u, 3217u, 3221u, 3229u, 3251u,
+ 3253u, 3257u, 3259u, 3271u, 3299u, 3301u, 3307u, 3313u, 3319u,
+ 3323u, 3329u, 3331u, 3343u, 3347u, 3359u, 3361u, 3371u, 3373u,
+ 3389u, 3391u, 3407u, 3413u, 3433u, 3449u, 3457u, 3461u, 3463u,
+ 3467u, 3469u, 3491u, 3499u, 3511u, 3517u, 3527u, 3529u, 3533u,
+ 3539u, 3541u, 3547u, 3557u, 3559u, 3571u, 3581u, 3583u, 3593u,
+ 3607u, 3613u, 3617u, 3623u, 3631u, 3637u, 3643u, 3659u, 3671u,
+ 3673u, 3677u, 3691u, 3697u, 3701u, 3709u, 3719u, 3727u, 3733u,
+ 3739u, 3761u, 3767u, 3769u, 3779u, 3793u, 3797u, 3803u, 3821u,
+ 3823u, 3833u, 3847u, 3851u, 3853u, 3863u, 3877u, 3881u, 3889u,
+ 3907u, 3911u, 3917u, 3919u, 3923u, 3929u, 3931u, 3943u, 3947u,
+ 3967u, 3989u, 4001u, 4003u, 4007u, 4013u, 4019u, 4021u, 4027u,
+ 4049u, 4051u, 4057u, 4073u, 4079u, 4091u, 4093u, 4099u, 4111u,
+ 4127u, 4129u, 4133u, 4139u, 4153u, 4157u, 4159u, 4177u, 4201u,
+ 4211u, 4217u, 4219u, 4229u, 4231u, 4241u, 4243u, 4253u, 4259u,
+ 4261u, 4271u, 4273u, 4283u, 4289u, 4297u, 4327u, 4337u, 4339u,
+ 4349u, 4357u, 4363u, 4373u, 4391u, 4397u, 4409u, 4421u, 4423u,
+ 4441u, 4447u, 4451u, 4457u, 4463u, 4481u, 4483u, 4493u, 4507u,
+ 4513u, 4517u, 4519u, 4523u, 4547u, 4549u, 4561u, 4567u, 4583u,
+ 4591u, 4597u, 4603u, 4621u, 4637u, 4639u, 4643u, 4649u, 4651u,
+ 4657u, 4663u, 4673u, 4679u, 4691u, 4703u, 4721u, 4723u, 4729u,
+ 4733u, 4751u, 4759u, 4783u, 4787u, 4789u, 4793u, 4799u, 4801u,
+ 4813u, 4817u, 4831u, 4861u, 4871u, 4877u, 4889u, 4903u, 4909u,
+ 4919u, 4931u, 4933u, 4937u, 4943u, 4951u, 4957u, 4967u, 4969u,
+ 4973u, 4987u, 4993u, 4999u, 5003u, 5009u, 5011u, 5021u, 5023u,
+ 5039u, 5051u, 5059u, 5077u, 5081u, 5087u, 5099u, 5101u, 5107u,
+ 5113u, 5119u, 5147u, 5153u, 5167u, 5171u, 5179u, 5189u, 5197u,
+ 5209u, 5227u, 5231u, 5233u, 5237u, 5261u, 5273u, 5279u, 5281u,
+ 5297u, 5303u, 5309u, 5323u, 5333u, 5347u, 5351u, 5381u, 5387u,
+ 5393u, 5399u, 5407u, 5413u, 5417u, 5419u, 5431u, 5437u, 5441u,
+ 5443u, 5449u, 5471u, 5477u, 5479u, 5483u, 5501u, 5503u, 5507u,
+ 5519u, 5521u, 5527u, 5531u, 5557u, 5563u, 5569u, 5573u, 5581u,
+ 5591u, 5623u, 5639u, 5641u, 5647u, 5651u, 5653u, 5657u, 5659u,
+ 5669u, 5683u, 5689u, 5693u, 5701u, 5711u, 5717u, 5737u, 5741u,
+ 5743u, 5749u, 5779u, 5783u, 5791u, 5801u, 5807u, 5813u, 5821u,
+ 5827u, 5839u, 5843u, 5849u, 5851u, 5857u, 5861u, 5867u, 5869u,
+ 5879u, 5881u, 5897u, 5903u, 5923u, 5927u, 5939u, 5953u, 5981u,
+ 5987u, 6007u, 6011u, 6029u, 6037u, 6043u, 6047u, 6053u, 6067u,
+ 6073u, 6079u, 6089u, 6091u, 6101u, 6113u, 6121u, 6131u, 6133u,
+ 6143u, 6151u, 6163u, 6173u, 6197u, 6199u, 6203u, 6211u, 6217u,
+ 6221u, 6229u, 6247u, 6257u, 6263u, 6269u, 6271u, 6277u, 6287u,
+ 6299u, 6301u, 6311u, 6317u, 6323u, 6329u, 6337u, 6343u, 6353u,
+ 6359u, 6361u, 6367u, 6373u, 6379u, 6389u, 6397u, 6421u, 6427u,
+ 6449u, 6451u, 6469u, 6473u, 6481u, 6491u, 6521u, 6529u, 6547u,
+ 6551u, 6553u, 6563u, 6569u, 6571u, 6577u, 6581u, 6599u, 6607u,
+ 6619u, 6637u, 6653u, 6659u, 6661u, 6673u, 6679u, 6689u, 6691u,
+ 6701u, 6703u, 6709u, 6719u, 6733u, 6737u, 6761u, 6763u, 6779u,
+ 6781u, 6791u, 6793u, 6803u, 6823u, 6827u, 6829u, 6833u, 6841u,
+ 6857u, 6863u, 6869u, 6871u, 6883u, 6899u, 6907u, 6911u, 6917u,
+ 6947u, 6949u, 6959u, 6961u, 6967u, 6971u, 6977u, 6983u, 6991u,
+ 6997u, 7001u, 7013u, 7019u, 7027u, 7039u, 7043u, 7057u, 7069u,
+ 7079u, 7103u, 7109u, 7121u, 7127u, 7129u, 7151u, 7159u, 7177u,
+ 7187u, 7193u, 7207u, 7211u, 7213u, 7219u, 7229u, 7237u, 7243u,
+ 7247u, 7253u, 7283u, 7297u, 7307u, 7309u, 7321u, 7331u, 7333u,
+ 7349u, 7351u, 7369u, 7393u, 7411u, 7417u, 7433u, 7451u, 7457u,
+ 7459u, 7477u, 7481u, 7487u, 7489u, 7499u, 7507u, 7517u, 7523u,
+ 7529u, 7537u, 7541u, 7547u, 7549u, 7559u, 7561u, 7573u, 7577u,
+ 7583u, 7589u, 7591u, 7603u, 7607u, 7621u, 7639u, 7643u, 7649u,
+ 7669u, 7673u, 7681u, 7687u, 7691u, 7699u, 7703u, 7717u, 7723u,
+ 7727u, 7741u, 7753u, 7757u, 7759u, 7789u, 7793u, 7817u, 7823u,
+ 7829u, 7841u, 7853u, 7867u, 7873u, 7877u, 7879u, 7883u, 7901u,
+ 7907u, 7919u, 7927u, 7933u, 7937u, 7949u, 7951u, 7963u, 7993u,
+ 8009u, 8011u, 8017u, 8039u, 8053u, 8059u, 8069u, 8081u, 8087u,
+ 8089u, 8093u, 8101u, 8111u, 8117u, 8123u, 8147u, 8161u, 8167u,
+ 8171u, 8179u, 8191u, 8209u, 8219u, 8221u, 8231u, 8233u, 8237u,
+ 8243u, 8263u, 8269u, 8273u, 8287u, 8291u, 8293u, 8297u, 8311u,
+ 8317u, 8329u, 8353u, 8363u, 8369u, 8377u, 8387u, 8389u, 8419u,
+ 8423u, 8429u, 8431u, 8443u, 8447u, 8461u, 8467u, 8501u, 8513u,
+ 8521u, 8527u, 8537u, 8539u, 8543u, 8563u, 8573u, 8581u, 8597u,
+ 8599u, 8609u, 8623u, 8627u, 8629u, 8641u, 8647u, 8663u, 8669u,
+ 8677u, 8681u, 8689u, 8693u, 8699u, 8707u, 8713u, 8719u, 8731u,
+ 8737u, 8741u, 8747u, 8753u, 8761u, 8779u, 8783u, 8803u, 8807u,
+ 8819u, 8821u, 8831u, 8837u, 8839u, 8849u, 8861u, 8863u, 8867u,
+ 8887u, 8893u, 8923u, 8929u, 8933u, 8941u, 8951u, 8963u, 8969u,
+ 8971u, 8999u, 9001u, 9007u, 9011u, 9013u, 9029u, 9041u, 9043u,
+ 9049u, 9059u, 9067u, 9091u, 9103u, 9109u, 9127u, 9133u, 9137u,
+ 9151u, 9157u, 9161u, 9173u, 9181u, 9187u, 9199u, 9203u, 9209u,
+ 9221u, 9227u, 9239u, 9241u, 9257u, 9277u, 9281u, 9283u, 9293u,
+ 9311u, 9319u, 9323u, 9337u, 9341u, 9343u, 9349u, 9371u, 9377u,
+ 9391u, 9397u, 9403u, 9413u, 9419u, 9421u, 9431u, 9433u, 9437u,
+ 9439u, 9461u, 9463u, 9467u, 9473u, 9479u, 9491u, 9497u, 9511u,
+ 9521u, 9533u, 9539u, 9547u, 9551u, 9587u, 9601u, 9613u, 9619u,
+ 9623u, 9629u, 9631u, 9643u, 9649u, 9661u, 9677u, 9679u, 9689u,
+ 9697u, 9719u, 9721u, 9733u, 9739u, 9743u, 9749u, 9767u, 9769u,
+ 9781u, 9787u, 9791u, 9803u, 9811u, 9817u, 9829u, 9833u, 9839u,
+ 9851u, 9857u, 9859u, 9871u, 9883u, 9887u, 9901u, 9907u, 9923u,
+ 9929u, 9931u, 9941u, 9949u, 9967u, 9973u, 10007u, 10009u, 10037u,
+ 10039u, 10061u, 10067u, 10069u, 10079u, 10091u, 10093u, 10099u, 10103u,
+ 10111u, 10133u, 10139u, 10141u, 10151u, 10159u, 10163u, 10169u, 10177u,
+ 10181u, 10193u, 10211u, 10223u, 10243u, 10247u, 10253u, 10259u, 10267u,
+ 10271u, 10273u, 10289u, 10301u, 10303u, 10313u, 10321u, 10331u, 10333u,
+ 10337u, 10343u, 10357u, 10369u, 10391u, 10399u, 10427u, 10429u, 10433u,
+ 10453u, 10457u, 10459u, 10463u, 10477u, 10487u, 10499u, 10501u, 10513u,
+ 10529u, 10531u, 10559u, 10567u, 10589u, 10597u, 10601u, 10607u, 10613u,
+ 10627u, 10631u, 10639u, 10651u, 10657u, 10663u, 10667u, 10687u, 10691u,
+ 10709u, 10711u, 10723u, 10729u, 10733u, 10739u, 10753u, 10771u, 10781u,
+ 10789u, 10799u, 10831u, 10837u, 10847u, 10853u, 10859u, 10861u, 10867u,
+ 10883u, 10889u, 10891u, 10903u, 10909u, 10937u, 10939u, 10949u, 10957u,
+ 10973u, 10979u, 10987u, 10993u, 11003u, 11027u, 11047u, 11057u, 11059u,
+ 11069u, 11071u, 11083u, 11087u, 11093u, 11113u, 11117u, 11119u, 11131u,
+ 11149u, 11159u, 11161u, 11171u, 11173u, 11177u, 11197u, 11213u, 11239u,
+ 11243u, 11251u, 11257u, 11261u, 11273u, 11279u, 11287u, 11299u, 11311u,
+ 11317u, 11321u, 11329u, 11351u, 11353u, 11369u, 11383u, 11393u, 11399u,
+ 11411u, 11423u, 11437u, 11443u, 11447u, 11467u, 11471u, 11483u, 11489u,
+ 11491u, 11497u, 11503u, 11519u, 11527u, 11549u, 11551u, 11579u, 11587u,
+ 11593u, 11597u, 11617u, 11621u, 11633u, 11657u, 11677u, 11681u, 11689u,
+ 11699u, 11701u, 11717u, 11719u, 11731u, 11743u, 11777u, 11779u, 11783u,
+ 11789u, 11801u, 11807u, 11813u, 11821u, 11827u, 11831u, 11833u, 11839u,
+ 11863u, 11867u, 11887u, 11897u, 11903u, 11909u, 11923u, 11927u, 11933u,
+ 11939u, 11941u, 11953u, 11959u, 11969u, 11971u, 11981u, 11987u, 12007u,
+ 12011u, 12037u, 12041u, 12043u, 12049u, 12071u, 12073u, 12097u, 12101u,
+ 12107u, 12109u, 12113u, 12119u, 12143u, 12149u, 12157u, 12161u, 12163u,
+ 12197u, 12203u, 12211u, 12227u, 12239u, 12241u, 12251u, 12253u, 12263u,
+ 12269u, 12277u, 12281u, 12289u, 12301u, 12323u, 12329u, 12343u, 12347u,
+ 12373u, 12377u, 12379u, 12391u, 12401u, 12409u, 12413u, 12421u, 12433u,
+ 12437u, 12451u, 12457u, 12473u, 12479u, 12487u, 12491u, 12497u, 12503u,
+ 12511u, 12517u, 12527u, 12539u, 12541u, 12547u, 12553u, 12569u, 12577u,
+ 12583u, 12589u, 12601u, 12611u, 12613u, 12619u, 12637u, 12641u, 12647u,
+ 12653u, 12659u, 12671u, 12689u, 12697u, 12703u, 12713u, 12721u, 12739u,
+ 12743u, 12757u, 12763u, 12781u, 12791u, 12799u, 12809u, 12821u, 12823u,
+ 12829u, 12841u, 12853u, 12889u, 12893u, 12899u, 12907u, 12911u, 12917u,
+ 12919u, 12923u, 12941u, 12953u, 12959u, 12967u, 12973u, 12979u, 12983u,
+ 13001u, 13003u, 13007u, 13009u, 13033u, 13037u, 13043u, 13049u, 13063u,
+ 13093u, 13099u, 13103u, 13109u, 13121u, 13127u, 13147u, 13151u, 13159u,
+ 13163u, 13171u, 13177u, 13183u, 13187u, 13217u, 13219u, 13229u, 13241u,
+ 13249u, 13259u, 13267u, 13291u, 13297u, 13309u, 13313u, 13327u, 13331u,
+ 13337u, 13339u, 13367u, 13381u, 13397u, 13399u, 13411u, 13417u, 13421u,
+ 13441u, 13451u, 13457u, 13463u, 13469u, 13477u, 13487u, 13499u, 13513u,
+ 13523u, 13537u, 13553u, 13567u, 13577u, 13591u, 13597u, 13613u, 13619u,
+ 13627u, 13633u, 13649u, 13669u, 13679u, 13681u, 13687u, 13691u, 13693u,
+ 13697u, 13709u, 13711u, 13721u, 13723u, 13729u, 13751u, 13757u, 13759u,
+ 13763u, 13781u, 13789u, 13799u, 13807u, 13829u, 13831u, 13841u, 13859u,
+ 13873u, 13877u, 13879u, 13883u, 13901u, 13903u, 13907u, 13913u, 13921u,
+ 13931u, 13933u, 13963u, 13967u, 13997u, 13999u, 14009u, 14011u, 14029u,
+ 14033u, 14051u, 14057u, 14071u, 14081u, 14083u, 14087u, 14107u, 14143u,
+ 14149u, 14153u, 14159u, 14173u, 14177u, 14197u, 14207u, 14221u, 14243u,
+ 14249u, 14251u, 14281u, 14293u, 14303u, 14321u, 14323u, 14327u, 14341u,
+ 14347u, 14369u, 14387u, 14389u, 14401u, 14407u, 14411u, 14419u, 14423u,
+ 14431u, 14437u, 14447u, 14449u, 14461u, 14479u, 14489u, 14503u, 14519u,
+ 14533u, 14537u, 14543u, 14549u, 14551u, 14557u, 14561u, 14563u, 14591u,
+ 14593u, 14621u, 14627u, 14629u, 14633u, 14639u, 14653u, 14657u, 14669u,
+ 14683u, 14699u, 14713u, 14717u, 14723u, 14731u, 14737u, 14741u, 14747u,
+ 14753u, 14759u, 14767u, 14771u, 14779u, 14783u, 14797u, 14813u, 14821u,
+ 14827u, 14831u, 14843u, 14851u, 14867u, 14869u, 14879u, 14887u, 14891u,
+ 14897u, 14923u, 14929u, 14939u, 14947u, 14951u, 14957u, 14969u, 14983u,
+ 15013u, 15017u, 15031u, 15053u, 15061u, 15073u, 15077u, 15083u, 15091u,
+ 15101u, 15107u, 15121u, 15131u, 15137u, 15139u, 15149u, 15161u, 15173u,
+ 15187u, 15193u, 15199u, 15217u, 15227u, 15233u, 15241u, 15259u, 15263u,
+ 15269u, 15271u, 15277u, 15287u, 15289u, 15299u, 15307u, 15313u, 15319u,
+ 15329u, 15331u, 15349u, 15359u, 15361u, 15373u, 15377u, 15383u, 15391u,
+ 15401u, 15413u, 15427u, 15439u, 15443u, 15451u, 15461u, 15467u, 15473u,
+ 15493u, 15497u, 15511u, 15527u, 15541u, 15551u, 15559u, 15569u, 15581u,
+ 15583u, 15601u, 15607u, 15619u, 15629u, 15641u, 15643u, 15647u, 15649u,
+ 15661u, 15667u, 15671u, 15679u, 15683u, 15727u, 15731u, 15733u, 15737u,
+ 15739u, 15749u, 15761u, 15767u, 15773u, 15787u, 15791u, 15797u, 15803u,
+ 15809u, 15817u, 15823u, 15859u, 15877u, 15881u, 15887u, 15889u, 15901u,
+ 15907u, 15913u, 15919u, 15923u, 15937u, 15959u, 15971u, 15973u, 15991u,
+ 16001u, 16007u, 16033u, 16057u, 16061u, 16063u, 16067u, 16069u, 16073u,
+ 16087u, 16091u, 16097u, 16103u, 16111u, 16127u, 16139u, 16141u, 16183u,
+ 16187u, 16189u, 16193u, 16217u, 16223u, 16229u, 16231u, 16249u, 16253u,
+ 16267u, 16273u, 16301u, 16319u, 16333u, 16339u, 16349u, 16361u, 16363u,
+ 16369u, 16381u, 16411u, 16417u, 16421u, 16427u, 16433u, 16447u, 16451u,
+ 16453u, 16477u, 16481u, 16487u, 16493u, 16519u, 16529u, 16547u, 16553u,
+ 16561u, 16567u, 16573u, 16603u, 16607u, 16619u, 16631u, 16633u, 16649u,
+ 16651u, 16657u, 16661u, 16673u, 16691u, 16693u, 16699u, 16703u, 16729u,
+ 16741u, 16747u, 16759u, 16763u, 16787u, 16811u, 16823u, 16829u, 16831u,
+ 16843u, 16871u, 16879u, 16883u, 16889u, 16901u, 16903u, 16921u, 16927u,
+ 16931u, 16937u, 16943u, 16963u, 16979u, 16981u, 16987u, 16993u, 17011u,
+ 17021u, 17027u, 17029u, 17033u, 17041u, 17047u, 17053u, 17077u, 17093u,
+ 17099u, 17107u, 17117u, 17123u, 17137u, 17159u, 17167u, 17183u, 17189u,
+ 17191u, 17203u, 17207u, 17209u, 17231u, 17239u, 17257u, 17291u, 17293u,
+ 17299u, 17317u, 17321u, 17327u, 17333u, 17341u, 17351u, 17359u, 17377u,
+ 17383u, 17387u, 17389u, 17393u, 17401u, 17417u, 17419u, 17431u, 17443u,
+ 17449u, 17467u, 17471u, 17477u, 17483u, 17489u, 17491u, 17497u, 17509u,
+ 17519u, 17539u, 17551u, 17569u, 17573u, 17579u, 17581u, 17597u, 17599u,
+ 17609u, 17623u, 17627u, 17657u, 17659u, 17669u, 17681u, 17683u, 17707u,
+ 17713u, 17729u, 17737u, 17747u, 17749u, 17761u, 17783u, 17789u, 17791u,
+ 17807u, 17827u, 17837u, 17839u, 17851u, 17863u, 17881u, 17891u, 17903u,
+ 17909u, 17911u, 17921u, 17923u, 17929u, 17939u, 17957u, 17959u, 17971u,
+ 17977u, 17981u, 17987u, 17989u, 18013u, 18041u, 18043u, 18047u, 18049u,
+ 18059u, 18061u, 18077u, 18089u, 18097u, 18119u, 18121u, 18127u, 18131u,
+ 18133u, 18143u, 18149u, 18169u, 18181u, 18191u, 18199u, 18211u, 18217u,
+ 18223u, 18229u, 18233u, 18251u, 18253u, 18257u, 18269u, 18287u, 18289u,
+ 18301u, 18307u, 18311u, 18313u, 18329u, 18341u, 18353u, 18367u, 18371u,
+ 18379u, 18397u, 18401u, 18413u, 18427u, 18433u, 18439u, 18443u, 18451u,
+ 18457u, 18461u, 18481u, 18493u, 18503u, 18517u, 18521u, 18523u, 18539u,
+ 18541u, 18553u, 18583u, 18587u, 18593u, 18617u, 18637u, 18661u, 18671u,
+ 18679u, 18691u, 18701u, 18713u, 18719u, 18731u, 18743u, 18749u, 18757u,
+ 18773u, 18787u, 18793u, 18797u, 18803u, 18839u, 18859u, 18869u, 18899u,
+ 18911u, 18913u, 18917u, 18919u, 18947u, 18959u, 18973u, 18979u, 19001u,
+ 19009u, 19013u, 19031u, 19037u, 19051u, 19069u, 19073u, 19079u, 19081u,
+ 19087u, 19121u, 19139u, 19141u, 19157u, 19163u, 19181u, 19183u, 19207u,
+ 19211u, 19213u, 19219u, 19231u, 19237u, 19249u, 19259u, 19267u, 19273u,
+ 19289u, 19301u, 19309u, 19319u, 19333u, 19373u, 19379u, 19381u, 19387u,
+ 19391u, 19403u, 19417u, 19421u, 19423u, 19427u, 19429u, 19433u, 19441u,
+ 19447u, 19457u, 19463u, 19469u, 19471u, 19477u, 19483u, 19489u, 19501u,
+ 19507u, 19531u, 19541u, 19543u, 19553u, 19559u, 19571u, 19577u, 19583u,
+ 19597u, 19603u, 19609u, 19661u, 19681u, 19687u, 19697u, 19699u, 19709u,
+ 19717u, 19727u, 19739u, 19751u, 19753u, 19759u, 19763u, 19777u, 19793u,
+ 19801u, 19813u, 19819u, 19841u, 19843u, 19853u, 19861u, 19867u, 19889u,
+ 19891u, 19913u, 19919u, 19927u, 19937u, 19949u, 19961u, 19963u, 19973u,
+ 19979u, 19991u, 19993u, 19997u, 20011u, 20021u, 20023u, 20029u, 20047u,
+ 20051u, 20063u, 20071u, 20089u, 20101u, 20107u, 20113u, 20117u, 20123u,
+ 20129u, 20143u, 20147u, 20149u, 20161u, 20173u, 20177u, 20183u, 20201u,
+ 20219u, 20231u, 20233u, 20249u, 20261u, 20269u, 20287u, 20297u, 20323u,
+ 20327u, 20333u, 20341u, 20347u, 20353u, 20357u, 20359u, 20369u, 20389u,
+ 20393u, 20399u, 20407u, 20411u, 20431u, 20441u, 20443u, 20477u, 20479u,
+ 20483u, 20507u, 20509u, 20521u, 20533u, 20543u, 20549u, 20551u, 20563u,
+ 20593u, 20599u, 20611u, 20627u, 20639u, 20641u, 20663u, 20681u, 20693u,
+ 20707u, 20717u, 20719u, 20731u, 20743u, 20747u, 20749u, 20753u, 20759u,
+ 20771u, 20773u, 20789u, 20807u, 20809u, 20849u, 20857u, 20873u, 20879u,
+ 20887u, 20897u, 20899u, 20903u, 20921u, 20929u, 20939u, 20947u, 20959u,
+ 20963u, 20981u, 20983u, 21001u, 21011u, 21013u, 21017u, 21019u, 21023u,
+ 21031u, 21059u, 21061u, 21067u, 21089u, 21101u, 21107u, 21121u, 21139u,
+ 21143u, 21149u, 21157u, 21163u, 21169u, 21179u, 21187u, 21191u, 21193u,
+ 21211u, 21221u, 21227u, 21247u, 21269u, 21277u, 21283u, 21313u, 21317u,
+ 21319u, 21323u, 21341u, 21347u, 21377u, 21379u, 21383u, 21391u, 21397u,
+ 21401u, 21407u, 21419u, 21433u, 21467u, 21481u, 21487u, 21491u, 21493u,
+ 21499u, 21503u, 21517u, 21521u, 21523u, 21529u, 21557u, 21559u, 21563u,
+ 21569u, 21577u, 21587u, 21589u, 21599u, 21601u, 21611u, 21613u, 21617u,
+ 21647u, 21649u, 21661u, 21673u, 21683u, 21701u, 21713u, 21727u, 21737u,
+ 21739u, 21751u, 21757u, 21767u, 21773u, 21787u, 21799u, 21803u, 21817u,
+ 21821u, 21839u, 21841u, 21851u, 21859u, 21863u, 21871u, 21881u, 21893u,
+ 21911u, 21929u, 21937u, 21943u, 21961u, 21977u, 21991u, 21997u, 22003u,
+ 22013u, 22027u, 22031u, 22037u, 22039u, 22051u, 22063u, 22067u, 22073u,
+ 22079u, 22091u, 22093u, 22109u, 22111u, 22123u, 22129u, 22133u, 22147u,
+ 22153u, 22157u, 22159u, 22171u, 22189u, 22193u, 22229u, 22247u, 22259u,
+ 22271u, 22273u, 22277u, 22279u, 22283u, 22291u, 22303u, 22307u, 22343u,
+ 22349u, 22367u, 22369u, 22381u, 22391u, 22397u, 22409u, 22433u, 22441u,
+ 22447u, 22453u, 22469u, 22481u, 22483u, 22501u, 22511u, 22531u, 22541u,
+ 22543u, 22549u, 22567u, 22571u, 22573u, 22613u, 22619u, 22621u, 22637u,
+ 22639u, 22643u, 22651u, 22669u, 22679u, 22691u, 22697u, 22699u, 22709u,
+ 22717u, 22721u, 22727u, 22739u, 22741u, 22751u, 22769u, 22777u, 22783u,
+ 22787u, 22807u, 22811u, 22817u, 22853u, 22859u, 22861u, 22871u, 22877u,
+ 22901u, 22907u, 22921u, 22937u, 22943u, 22961u, 22963u, 22973u, 22993u,
+ 23003u, 23011u, 23017u, 23021u, 23027u, 23029u, 23039u, 23041u, 23053u,
+ 23057u, 23059u, 23063u, 23071u, 23081u, 23087u, 23099u, 23117u, 23131u,
+ 23143u, 23159u, 23167u, 23173u, 23189u, 23197u, 23201u, 23203u, 23209u,
+ 23227u, 23251u, 23269u, 23279u, 23291u, 23293u, 23297u, 23311u, 23321u,
+ 23327u, 23333u, 23339u, 23357u, 23369u, 23371u, 23399u, 23417u, 23431u,
+ 23447u, 23459u, 23473u, 23497u, 23509u, 23531u, 23537u, 23539u, 23549u,
+ 23557u, 23561u, 23563u, 23567u, 23581u, 23593u, 23599u, 23603u, 23609u,
+ 23623u, 23627u, 23629u, 23633u, 23663u, 23669u, 23671u, 23677u, 23687u,
+ 23689u, 23719u, 23741u, 23743u, 23747u, 23753u, 23761u, 23767u, 23773u,
+ 23789u, 23801u, 23813u, 23819u, 23827u, 23831u, 23833u, 23857u, 23869u,
+ 23873u, 23879u, 23887u, 23893u, 23899u, 23909u, 23911u, 23917u, 23929u,
+ 23957u, 23971u, 23977u, 23981u, 23993u, 24001u, 24007u, 24019u, 24023u,
+ 24029u, 24043u, 24049u, 24061u, 24071u, 24077u, 24083u, 24091u, 24097u,
+ 24103u, 24107u, 24109u, 24113u, 24121u, 24133u, 24137u, 24151u, 24169u,
+ 24179u, 24181u, 24197u, 24203u, 24223u, 24229u, 24239u, 24247u, 24251u,
+ 24281u, 24317u, 24329u, 24337u, 24359u, 24371u, 24373u, 24379u, 24391u,
+ 24407u, 24413u, 24419u, 24421u, 24439u, 24443u, 24469u, 24473u, 24481u,
+ 24499u, 24509u, 24517u, 24527u, 24533u, 24547u, 24551u, 24571u, 24593u,
+ 24611u, 24623u, 24631u, 24659u, 24671u, 24677u, 24683u, 24691u, 24697u,
+ 24709u, 24733u, 24749u, 24763u, 24767u, 24781u, 24793u, 24799u, 24809u,
+ 24821u, 24841u, 24847u, 24851u, 24859u, 24877u, 24889u, 24907u, 24917u,
+ 24919u, 24923u, 24943u, 24953u, 24967u, 24971u, 24977u, 24979u, 24989u,
+ 25013u, 25031u, 25033u, 25037u, 25057u, 25073u, 25087u, 25097u, 25111u,
+ 25117u, 25121u, 25127u, 25147u, 25153u, 25163u, 25169u, 25171u, 25183u,
+ 25189u, 25219u, 25229u, 25237u, 25243u, 25247u, 25253u, 25261u, 25301u,
+ 25303u, 25307u, 25309u, 25321u, 25339u, 25343u, 25349u, 25357u, 25367u,
+ 25373u, 25391u, 25409u, 25411u, 25423u, 25439u, 25447u, 25453u, 25457u,
+ 25463u, 25469u, 25471u, 25523u, 25537u, 25541u, 25561u, 25577u, 25579u,
+ 25583u, 25589u, 25601u, 25603u, 25609u, 25621u, 25633u, 25639u, 25643u,
+ 25657u, 25667u, 25673u, 25679u, 25693u, 25703u, 25717u, 25733u, 25741u,
+ 25747u, 25759u, 25763u, 25771u, 25793u, 25799u, 25801u, 25819u, 25841u,
+ 25847u, 25849u, 25867u, 25873u, 25889u, 25903u, 25913u, 25919u, 25931u,
+ 25933u, 25939u, 25943u, 25951u, 25969u, 25981u, 25997u, 25999u, 26003u,
+ 26017u, 26021u, 26029u, 26041u, 26053u, 26083u, 26099u, 26107u, 26111u,
+ 26113u, 26119u, 26141u, 26153u, 26161u, 26171u, 26177u, 26183u, 26189u,
+ 26203u, 26209u, 26227u, 26237u, 26249u, 26251u, 26261u, 26263u, 26267u,
+ 26293u, 26297u, 26309u, 26317u, 26321u, 26339u, 26347u, 26357u, 26371u,
+ 26387u, 26393u, 26399u, 26407u, 26417u, 26423u, 26431u, 26437u, 26449u,
+ 26459u, 26479u, 26489u, 26497u, 26501u, 26513u, 26539u, 26557u, 26561u,
+ 26573u, 26591u, 26597u, 26627u, 26633u, 26641u, 26647u, 26669u, 26681u,
+ 26683u, 26687u, 26693u, 26699u, 26701u, 26711u, 26713u, 26717u, 26723u,
+ 26729u, 26731u, 26737u, 26759u, 26777u, 26783u, 26801u, 26813u, 26821u,
+ 26833u, 26839u, 26849u, 26861u, 26863u, 26879u, 26881u, 26891u, 26893u,
+ 26903u, 26921u, 26927u, 26947u, 26951u, 26953u, 26959u, 26981u, 26987u,
+ 26993u, 27011u, 27017u, 27031u, 27043u, 27059u, 27061u, 27067u, 27073u,
+ 27077u, 27091u, 27103u, 27107u, 27109u, 27127u, 27143u, 27179u, 27191u,
+ 27197u, 27211u, 27239u, 27241u, 27253u, 27259u, 27271u, 27277u, 27281u,
+ 27283u, 27299u, 27329u, 27337u, 27361u, 27367u, 27397u, 27407u, 27409u,
+ 27427u, 27431u, 27437u, 27449u, 27457u, 27479u, 27481u, 27487u, 27509u,
+ 27527u, 27529u, 27539u, 27541u, 27551u, 27581u, 27583u, 27611u, 27617u,
+ 27631u, 27647u, 27653u, 27673u, 27689u, 27691u, 27697u, 27701u, 27733u,
+ 27737u, 27739u, 27743u, 27749u, 27751u, 27763u, 27767u, 27773u, 27779u,
+ 27791u, 27793u, 27799u, 27803u, 27809u, 27817u, 27823u, 27827u, 27847u,
+ 27851u, 27883u, 27893u, 27901u, 27917u, 27919u, 27941u, 27943u, 27947u,
+ 27953u, 27961u, 27967u, 27983u, 27997u, 28001u, 28019u, 28027u, 28031u,
+ 28051u, 28057u, 28069u, 28081u, 28087u, 28097u, 28099u, 28109u, 28111u,
+ 28123u, 28151u, 28163u, 28181u, 28183u, 28201u, 28211u, 28219u, 28229u,
+ 28277u, 28279u, 28283u, 28289u, 28297u, 28307u, 28309u, 28319u, 28349u,
+ 28351u, 28387u, 28393u, 28403u, 28409u, 28411u, 28429u, 28433u, 28439u,
+ 28447u, 28463u, 28477u, 28493u, 28499u, 28513u, 28517u, 28537u, 28541u,
+ 28547u, 28549u, 28559u, 28571u, 28573u, 28579u, 28591u, 28597u, 28603u,
+ 28607u, 28619u, 28621u, 28627u, 28631u, 28643u, 28649u, 28657u, 28661u,
+ 28663u, 28669u, 28687u, 28697u, 28703u, 28711u, 28723u, 28729u, 28751u,
+ 28753u, 28759u, 28771u, 28789u, 28793u, 28807u, 28813u, 28817u, 28837u,
+ 28843u, 28859u, 28867u, 28871u, 28879u, 28901u, 28909u, 28921u, 28927u,
+ 28933u, 28949u, 28961u, 28979u, 29009u, 29017u, 29021u, 29023u, 29027u,
+ 29033u, 29059u, 29063u, 29077u, 29101u, 29123u, 29129u, 29131u, 29137u,
+ 29147u, 29153u, 29167u, 29173u, 29179u, 29191u, 29201u, 29207u, 29209u,
+ 29221u, 29231u, 29243u, 29251u, 29269u, 29287u, 29297u, 29303u, 29311u,
+ 29327u, 29333u, 29339u, 29347u, 29363u, 29383u, 29387u, 29389u, 29399u,
+ 29401u, 29411u, 29423u, 29429u, 29437u, 29443u, 29453u, 29473u, 29483u,
+ 29501u, 29527u, 29531u, 29537u, 29567u, 29569u, 29573u, 29581u, 29587u,
+ 29599u, 29611u, 29629u, 29633u, 29641u, 29663u, 29669u, 29671u, 29683u,
+ 29717u, 29723u, 29741u, 29753u, 29759u, 29761u, 29789u, 29803u, 29819u,
+ 29833u, 29837u, 29851u, 29863u, 29867u, 29873u, 29879u, 29881u, 29917u,
+ 29921u, 29927u, 29947u, 29959u, 29983u, 29989u, 30011u, 30013u, 30029u,
+ 30047u, 30059u, 30071u, 30089u, 30091u, 30097u, 30103u, 30109u, 30113u,
+ 30119u, 30133u, 30137u, 30139u, 30161u, 30169u, 30181u, 30187u, 30197u,
+ 30203u, 30211u, 30223u, 30241u, 30253u, 30259u, 30269u, 30271u, 30293u,
+ 30307u, 30313u, 30319u, 30323u, 30341u, 30347u, 30367u, 30389u, 30391u,
+ 30403u, 30427u, 30431u, 30449u, 30467u, 30469u, 30491u, 30493u, 30497u,
+ 30509u, 30517u, 30529u, 30539u, 30553u, 30557u, 30559u, 30577u, 30593u,
+ 30631u, 30637u, 30643u, 30649u, 30661u, 30671u, 30677u, 30689u, 30697u,
+ 30703u, 30707u, 30713u, 30727u, 30757u, 30763u, 30773u, 30781u, 30803u,
+ 30809u, 30817u, 30829u, 30839u, 30841u, 30851u, 30853u, 30859u, 30869u,
+ 30871u, 30881u, 30893u, 30911u, 30931u, 30937u, 30941u, 30949u, 30971u,
+ 30977u, 30983u, 31013u, 31019u, 31033u, 31039u, 31051u, 31063u, 31069u,
+ 31079u, 31081u, 31091u, 31121u, 31123u, 31139u, 31147u, 31151u, 31153u,
+ 31159u, 31177u, 31181u, 31183u, 31189u, 31193u, 31219u, 31223u, 31231u,
+ 31237u, 31247u, 31249u, 31253u, 31259u, 31267u, 31271u, 31277u, 31307u,
+ 31319u, 31321u, 31327u, 31333u, 31337u, 31357u, 31379u, 31387u, 31391u,
+ 31393u, 31397u, 31469u, 31477u, 31481u, 31489u, 31511u, 31513u, 31517u,
+ 31531u, 31541u, 31543u, 31547u, 31567u, 31573u, 31583u, 31601u, 31607u,
+ 31627u, 31643u, 31649u, 31657u, 31663u, 31667u, 31687u, 31699u, 31721u,
+ 31723u, 31727u, 31729u, 31741u, 31751u, 31769u, 31771u, 31793u, 31799u,
+ 31817u, 31847u, 31849u, 31859u, 31873u, 31883u, 31891u, 31907u, 31957u,
+ 31963u, 31973u, 31981u, 31991u, 32003u, 32009u, 32027u, 32029u, 32051u,
+ 32057u, 32059u, 32063u, 32069u, 32077u, 32083u, 32089u, 32099u, 32117u,
+ 32119u, 32141u, 32143u, 32159u, 32173u, 32183u, 32189u, 32191u, 32203u,
+ 32213u, 32233u, 32237u, 32251u, 32257u, 32261u, 32297u, 32299u, 32303u,
+ 32309u, 32321u, 32323u, 32327u, 32341u, 32353u, 32359u, 32363u, 32369u,
+ 32371u, 32377u, 32381u, 32401u, 32411u, 32413u, 32423u, 32429u, 32441u,
+ 32443u, 32467u, 32479u, 32491u, 32497u, 32503u, 32507u, 32531u, 32533u,
+ 32537u, 32561u, 32563u, 32569u, 32573u, 32579u, 32587u, 32603u, 32609u,
+ 32611u, 32621u, 32633u, 32647u, 32653u, 32687u, 32693u, 32707u, 32713u,
+ 32717u, 32719u, 32749u, 32771u, 32779u, 32783u, 32789u, 32797u, 32801u,
+ 32803u, 32831u, 32833u, 32839u, 32843u, 32869u, 32887u, 32909u, 32911u,
+ 32917u, 32933u, 32939u, 32941u, 32957u, 32969u, 32971u, 32983u, 32987u,
+ 32993u, 32999u, 33013u, 33023u, 33029u, 33037u, 33049u, 33053u, 33071u,
+ 33073u, 33083u, 33091u, 33107u, 33113u, 33119u, 33149u, 33151u, 33161u,
+ 33179u, 33181u, 33191u, 33199u, 33203u, 33211u, 33223u, 33247u, 33287u,
+ 33289u, 33301u, 33311u, 33317u, 33329u, 33331u, 33343u, 33347u, 33349u,
+ 33353u, 33359u, 33377u, 33391u, 33403u, 33409u, 33413u, 33427u, 33457u,
+ 33461u, 33469u, 33479u, 33487u, 33493u, 33503u, 33521u, 33529u, 33533u,
+ 33547u, 33563u, 33569u, 33577u, 33581u, 33587u, 33589u, 33599u, 33601u,
+ 33613u, 33617u, 33619u, 33623u, 33629u, 33637u, 33641u, 33647u, 33679u,
+ 33703u, 33713u, 33721u, 33739u, 33749u, 33751u, 33757u, 33767u, 33769u,
+ 33773u, 33791u, 33797u, 33809u, 33811u, 33827u, 33829u, 33851u, 33857u,
+ 33863u, 33871u, 33889u, 33893u, 33911u, 33923u, 33931u, 33937u, 33941u,
+ 33961u, 33967u, 33997u, 34019u, 34031u, 34033u, 34039u, 34057u, 34061u,
+ 34123u, 34127u, 34129u, 34141u, 34147u, 34157u, 34159u, 34171u, 34183u,
+ 34211u, 34213u, 34217u, 34231u, 34253u, 34259u, 34261u, 34267u, 34273u,
+ 34283u, 34297u, 34301u, 34303u, 34313u, 34319u, 34327u, 34337u, 34351u,
+ 34361u, 34367u, 34369u, 34381u, 34403u, 34421u, 34429u, 34439u, 34457u,
+ 34469u, 34471u, 34483u, 34487u, 34499u, 34501u, 34511u, 34513u, 34519u,
+ 34537u, 34543u, 34549u, 34583u, 34589u, 34591u, 34603u, 34607u, 34613u,
+ 34631u, 34649u, 34651u, 34667u, 34673u, 34679u, 34687u, 34693u, 34703u,
+ 34721u, 34729u, 34739u, 34747u, 34757u, 34759u, 34763u, 34781u, 34807u,
+ 34819u, 34841u, 34843u, 34847u, 34849u, 34871u, 34877u, 34883u, 34897u,
+ 34913u, 34919u, 34939u, 34949u, 34961u, 34963u, 34981u, 35023u, 35027u,
+ 35051u, 35053u, 35059u, 35069u, 35081u, 35083u, 35089u, 35099u, 35107u,
+ 35111u, 35117u, 35129u, 35141u, 35149u, 35153u, 35159u, 35171u, 35201u,
+ 35221u, 35227u, 35251u, 35257u, 35267u, 35279u, 35281u, 35291u, 35311u,
+ 35317u, 35323u, 35327u, 35339u, 35353u, 35363u, 35381u, 35393u, 35401u,
+ 35407u, 35419u, 35423u, 35437u, 35447u, 35449u, 35461u, 35491u, 35507u,
+ 35509u, 35521u, 35527u, 35531u, 35533u, 35537u, 35543u, 35569u, 35573u,
+ 35591u, 35593u, 35597u, 35603u, 35617u, 35671u, 35677u, 35729u, 35731u,
+ 35747u, 35753u, 35759u, 35771u, 35797u, 35801u, 35803u, 35809u, 35831u,
+ 35837u, 35839u, 35851u, 35863u, 35869u, 35879u, 35897u, 35899u, 35911u,
+ 35923u, 35933u, 35951u, 35963u, 35969u, 35977u, 35983u, 35993u, 35999u,
+ 36007u, 36011u, 36013u, 36017u, 36037u, 36061u, 36067u, 36073u, 36083u,
+ 36097u, 36107u, 36109u, 36131u, 36137u, 36151u, 36161u, 36187u, 36191u,
+ 36209u, 36217u, 36229u, 36241u, 36251u, 36263u, 36269u, 36277u, 36293u,
+ 36299u, 36307u, 36313u, 36319u, 36341u, 36343u, 36353u, 36373u, 36383u,
+ 36389u, 36433u, 36451u, 36457u, 36467u, 36469u, 36473u, 36479u, 36493u,
+ 36497u, 36523u, 36527u, 36529u, 36541u, 36551u, 36559u, 36563u, 36571u,
+ 36583u, 36587u, 36599u, 36607u, 36629u, 36637u, 36643u, 36653u, 36671u,
+ 36677u, 36683u, 36691u, 36697u, 36709u, 36713u, 36721u, 36739u, 36749u,
+ 36761u, 36767u, 36779u, 36781u, 36787u, 36791u, 36793u, 36809u, 36821u,
+ 36833u, 36847u, 36857u, 36871u, 36877u, 36887u, 36899u, 36901u, 36913u,
+ 36919u, 36923u, 36929u, 36931u, 36943u, 36947u, 36973u, 36979u, 36997u,
+ 37003u, 37013u, 37019u, 37021u, 37039u, 37049u, 37057u, 37061u, 37087u,
+ 37097u, 37117u, 37123u, 37139u, 37159u, 37171u, 37181u, 37189u, 37199u,
+ 37201u, 37217u, 37223u, 37243u, 37253u, 37273u, 37277u, 37307u, 37309u,
+ 37313u, 37321u, 37337u, 37339u, 37357u, 37361u, 37363u, 37369u, 37379u,
+ 37397u, 37409u, 37423u, 37441u, 37447u, 37463u, 37483u, 37489u, 37493u,
+ 37501u, 37507u, 37511u, 37517u, 37529u, 37537u, 37547u, 37549u, 37561u,
+ 37567u, 37571u, 37573u, 37579u, 37589u, 37591u, 37607u, 37619u, 37633u,
+ 37643u, 37649u, 37657u, 37663u, 37691u, 37693u, 37699u, 37717u, 37747u,
+ 37781u, 37783u, 37799u, 37811u, 37813u, 37831u, 37847u, 37853u, 37861u,
+ 37871u, 37879u, 37889u, 37897u, 37907u, 37951u, 37957u, 37963u, 37967u,
+ 37987u, 37991u, 37993u, 37997u, 38011u, 38039u, 38047u, 38053u, 38069u,
+ 38083u, 38113u, 38119u, 38149u, 38153u, 38167u, 38177u, 38183u, 38189u,
+ 38197u, 38201u, 38219u, 38231u, 38237u, 38239u, 38261u, 38273u, 38281u,
+ 38287u, 38299u, 38303u, 38317u, 38321u, 38327u, 38329u, 38333u, 38351u,
+ 38371u, 38377u, 38393u, 38431u, 38447u, 38449u, 38453u, 38459u, 38461u,
+ 38501u, 38543u, 38557u, 38561u, 38567u, 38569u, 38593u, 38603u, 38609u,
+ 38611u, 38629u, 38639u, 38651u, 38653u, 38669u, 38671u, 38677u, 38693u,
+ 38699u, 38707u, 38711u, 38713u, 38723u, 38729u, 38737u, 38747u, 38749u,
+ 38767u, 38783u, 38791u, 38803u, 38821u, 38833u, 38839u, 38851u, 38861u,
+ 38867u, 38873u, 38891u, 38903u, 38917u, 38921u, 38923u, 38933u, 38953u,
+ 38959u, 38971u, 38977u, 38993u, 39019u, 39023u, 39041u, 39043u, 39047u,
+ 39079u, 39089u, 39097u, 39103u, 39107u, 39113u, 39119u, 39133u, 39139u,
+ 39157u, 39161u, 39163u, 39181u, 39191u, 39199u, 39209u, 39217u, 39227u,
+ 39229u, 39233u, 39239u, 39241u, 39251u, 39293u, 39301u, 39313u, 39317u,
+ 39323u, 39341u, 39343u, 39359u, 39367u, 39371u, 39373u, 39383u, 39397u,
+ 39409u, 39419u, 39439u, 39443u, 39451u, 39461u, 39499u, 39503u, 39509u,
+ 39511u, 39521u, 39541u, 39551u, 39563u, 39569u, 39581u, 39607u, 39619u,
+ 39623u, 39631u, 39659u, 39667u, 39671u, 39679u, 39703u, 39709u, 39719u,
+ 39727u, 39733u, 39749u, 39761u, 39769u, 39779u, 39791u, 39799u, 39821u,
+ 39827u, 39829u, 39839u, 39841u, 39847u, 39857u, 39863u, 39869u, 39877u,
+ 39883u, 39887u, 39901u, 39929u, 39937u, 39953u, 39971u, 39979u, 39983u,
+ 39989u, 40009u, 40013u, 40031u, 40037u, 40039u, 40063u, 40087u, 40093u,
+ 40099u, 40111u, 40123u, 40127u, 40129u, 40151u, 40153u, 40163u, 40169u,
+ 40177u, 40189u, 40193u, 40213u, 40231u, 40237u, 40241u, 40253u, 40277u,
+ 40283u, 40289u, 40343u, 40351u, 40357u, 40361u, 40387u, 40423u, 40427u,
+ 40429u, 40433u, 40459u, 40471u, 40483u, 40487u, 40493u, 40499u, 40507u,
+ 40519u, 40529u, 40531u, 40543u, 40559u, 40577u, 40583u, 40591u, 40597u,
+ 40609u, 40627u, 40637u, 40639u, 40693u, 40697u, 40699u, 40709u, 40739u,
+ 40751u, 40759u, 40763u, 40771u, 40787u, 40801u, 40813u, 40819u, 40823u,
+ 40829u, 40841u, 40847u, 40849u, 40853u, 40867u, 40879u, 40883u, 40897u,
+ 40903u, 40927u, 40933u, 40939u, 40949u, 40961u, 40973u, 40993u, 41011u,
+ 41017u, 41023u, 41039u, 41047u, 41051u, 41057u, 41077u, 41081u, 41113u,
+ 41117u, 41131u, 41141u, 41143u, 41149u, 41161u, 41177u, 41179u, 41183u,
+ 41189u, 41201u, 41203u, 41213u, 41221u, 41227u, 41231u, 41233u, 41243u,
+ 41257u, 41263u, 41269u, 41281u, 41299u, 41333u, 41341u, 41351u, 41357u,
+ 41381u, 41387u, 41389u, 41399u, 41411u, 41413u, 41443u, 41453u, 41467u,
+ 41479u, 41491u, 41507u, 41513u, 41519u, 41521u, 41539u, 41543u, 41549u,
+ 41579u, 41593u, 41597u, 41603u, 41609u, 41611u, 41617u, 41621u, 41627u,
+ 41641u, 41647u, 41651u, 41659u, 41669u, 41681u, 41687u, 41719u, 41729u,
+ 41737u, 41759u, 41761u, 41771u, 41777u, 41801u, 41809u, 41813u, 41843u,
+ 41849u, 41851u, 41863u, 41879u, 41887u, 41893u, 41897u, 41903u, 41911u,
+ 41927u, 41941u, 41947u, 41953u, 41957u, 41959u, 41969u, 41981u, 41983u,
+ 41999u, 42013u, 42017u, 42019u, 42023u, 42043u, 42061u, 42071u, 42073u,
+ 42083u, 42089u, 42101u, 42131u, 42139u, 42157u, 42169u, 42179u, 42181u,
+ 42187u, 42193u, 42197u, 42209u, 42221u, 42223u, 42227u, 42239u, 42257u,
+ 42281u, 42283u, 42293u, 42299u, 42307u, 42323u, 42331u, 42337u, 42349u,
+ 42359u, 42373u, 42379u, 42391u, 42397u, 42403u, 42407u, 42409u, 42433u,
+ 42437u, 42443u, 42451u, 42457u, 42461u, 42463u, 42467u, 42473u, 42487u,
+ 42491u, 42499u, 42509u, 42533u, 42557u, 42569u, 42571u, 42577u, 42589u,
+ 42611u, 42641u, 42643u, 42649u, 42667u, 42677u, 42683u, 42689u, 42697u,
+ 42701u, 42703u, 42709u, 42719u, 42727u, 42737u, 42743u, 42751u, 42767u,
+ 42773u, 42787u, 42793u, 42797u, 42821u, 42829u, 42839u, 42841u, 42853u,
+ 42859u, 42863u, 42899u, 42901u, 42923u, 42929u, 42937u, 42943u, 42953u,
+ 42961u, 42967u, 42979u, 42989u, 43003u, 43013u, 43019u, 43037u, 43049u,
+ 43051u, 43063u, 43067u, 43093u, 43103u, 43117u, 43133u, 43151u, 43159u,
+ 43177u, 43189u, 43201u, 43207u, 43223u, 43237u, 43261u, 43271u, 43283u,
+ 43291u, 43313u, 43319u, 43321u, 43331u, 43391u, 43397u, 43399u, 43403u,
+ 43411u, 43427u, 43441u, 43451u, 43457u, 43481u, 43487u, 43499u, 43517u,
+ 43541u, 43543u, 43573u, 43577u, 43579u, 43591u, 43597u, 43607u, 43609u,
+ 43613u, 43627u, 43633u, 43649u, 43651u, 43661u, 43669u, 43691u, 43711u,
+ 43717u, 43721u, 43753u, 43759u, 43777u, 43781u, 43783u, 43787u, 43789u,
+ 43793u, 43801u, 43853u, 43867u, 43889u, 43891u, 43913u, 43933u, 43943u,
+ 43951u, 43961u, 43963u, 43969u, 43973u, 43987u, 43991u, 43997u, 44017u,
+ 44021u, 44027u, 44029u, 44041u, 44053u, 44059u, 44071u, 44087u, 44089u,
+ 44101u, 44111u, 44119u, 44123u, 44129u, 44131u, 44159u, 44171u, 44179u,
+ 44189u, 44201u, 44203u, 44207u, 44221u, 44249u, 44257u, 44263u, 44267u,
+ 44269u, 44273u, 44279u, 44281u, 44293u, 44351u, 44357u, 44371u, 44381u,
+ 44383u, 44389u, 44417u, 44449u, 44453u, 44483u, 44491u, 44497u, 44501u,
+ 44507u, 44519u, 44531u, 44533u, 44537u, 44543u, 44549u, 44563u, 44579u,
+ 44587u, 44617u, 44621u, 44623u, 44633u, 44641u, 44647u, 44651u, 44657u,
+ 44683u, 44687u, 44699u, 44701u, 44711u, 44729u, 44741u, 44753u, 44771u,
+ 44773u, 44777u, 44789u, 44797u, 44809u, 44819u, 44839u, 44843u, 44851u,
+ 44867u, 44879u, 44887u, 44893u, 44909u, 44917u, 44927u, 44939u, 44953u,
+ 44959u, 44963u, 44971u, 44983u, 44987u, 45007u, 45013u, 45053u, 45061u,
+ 45077u, 45083u, 45119u, 45121u, 45127u, 45131u, 45137u, 45139u, 45161u,
+ 45179u, 45181u, 45191u, 45197u, 45233u, 45247u, 45259u, 45263u, 45281u,
+ 45289u, 45293u, 45307u, 45317u, 45319u, 45329u, 45337u, 45341u, 45343u,
+ 45361u, 45377u, 45389u, 45403u, 45413u, 45427u, 45433u, 45439u, 45481u,
+ 45491u, 45497u, 45503u, 45523u, 45533u, 45541u, 45553u, 45557u, 45569u,
+ 45587u, 45589u, 45599u, 45613u, 45631u, 45641u, 45659u, 45667u, 45673u,
+ 45677u, 45691u, 45697u, 45707u, 45737u, 45751u, 45757u, 45763u, 45767u,
+ 45779u, 45817u, 45821u, 45823u, 45827u, 45833u, 45841u, 45853u, 45863u,
+ 45869u, 45887u, 45893u, 45943u, 45949u, 45953u, 45959u, 45971u, 45979u,
+ 45989u, 46021u, 46027u, 46049u, 46051u, 46061u, 46073u, 46091u, 46093u,
+ 46099u, 46103u, 46133u, 46141u, 46147u, 46153u, 46171u, 46181u, 46183u,
+ 46187u, 46199u, 46219u, 46229u, 46237u, 46261u, 46271u, 46273u, 46279u,
+ 46301u, 46307u, 46309u, 46327u, 46337u, 46349u, 46351u, 46381u, 46399u,
+ 46411u, 46439u, 46441u, 46447u, 46451u, 46457u, 46471u, 46477u, 46489u,
+ 46499u, 46507u, 46511u, 46523u, 46549u, 46559u, 46567u, 46573u, 46589u,
+ 46591u, 46601u, 46619u, 46633u, 46639u, 46643u, 46649u, 46663u, 46679u,
+ 46681u, 46687u, 46691u, 46703u, 46723u, 46727u, 46747u, 46751u, 46757u,
+ 46769u, 46771u, 46807u, 46811u, 46817u, 46819u, 46829u, 46831u, 46853u,
+ 46861u, 46867u, 46877u, 46889u, 46901u, 46919u, 46933u, 46957u, 46993u,
+ 46997u, 47017u, 47041u, 47051u, 47057u, 47059u, 47087u, 47093u, 47111u,
+ 47119u, 47123u, 47129u, 47137u, 47143u, 47147u, 47149u, 47161u, 47189u,
+ 47207u, 47221u, 47237u, 47251u, 47269u, 47279u, 47287u, 47293u, 47297u,
+ 47303u, 47309u, 47317u, 47339u, 47351u, 47353u, 47363u, 47381u, 47387u,
+ 47389u, 47407u, 47417u, 47419u, 47431u, 47441u, 47459u, 47491u, 47497u,
+ 47501u, 47507u, 47513u, 47521u, 47527u, 47533u, 47543u, 47563u, 47569u,
+ 47581u, 47591u, 47599u, 47609u, 47623u, 47629u, 47639u, 47653u, 47657u,
+ 47659u, 47681u, 47699u, 47701u, 47711u, 47713u, 47717u, 47737u, 47741u,
+ 47743u, 47777u, 47779u, 47791u, 47797u, 47807u, 47809u, 47819u, 47837u,
+ 47843u, 47857u, 47869u, 47881u, 47903u, 47911u, 47917u, 47933u, 47939u,
+ 47947u, 47951u, 47963u, 47969u, 47977u, 47981u, 48017u, 48023u, 48029u,
+ 48049u, 48073u, 48079u, 48091u, 48109u, 48119u, 48121u, 48131u, 48157u,
+ 48163u, 48179u, 48187u, 48193u, 48197u, 48221u, 48239u, 48247u, 48259u,
+ 48271u, 48281u, 48299u, 48311u, 48313u, 48337u, 48341u, 48353u, 48371u,
+ 48383u, 48397u, 48407u, 48409u, 48413u, 48437u, 48449u, 48463u, 48473u,
+ 48479u, 48481u, 48487u, 48491u, 48497u, 48523u, 48527u, 48533u, 48539u,
+ 48541u, 48563u, 48571u, 48589u, 48593u, 48611u, 48619u, 48623u, 48647u,
+ 48649u, 48661u, 48673u, 48677u, 48679u, 48731u, 48733u, 48751u, 48757u,
+ 48761u, 48767u, 48779u, 48781u, 48787u, 48799u, 48809u, 48817u, 48821u,
+ 48823u, 48847u, 48857u, 48859u, 48869u, 48871u, 48883u, 48889u, 48907u,
+ 48947u, 48953u, 48973u, 48989u, 48991u, 49003u, 49009u, 49019u, 49031u,
+ 49033u, 49037u, 49043u, 49057u, 49069u, 49081u, 49103u, 49109u, 49117u,
+ 49121u, 49123u, 49139u, 49157u, 49169u, 49171u, 49177u, 49193u, 49199u,
+ 49201u, 49207u, 49211u, 49223u, 49253u, 49261u, 49277u, 49279u, 49297u,
+ 49307u, 49331u, 49333u, 49339u, 49363u, 49367u, 49369u, 49391u, 49393u,
+ 49409u, 49411u, 49417u, 49429u, 49433u, 49451u, 49459u, 49463u, 49477u,
+ 49481u, 49499u, 49523u, 49529u, 49531u, 49537u, 49547u, 49549u, 49559u,
+ 49597u, 49603u, 49613u, 49627u, 49633u, 49639u, 49663u, 49667u, 49669u,
+ 49681u, 49697u, 49711u, 49727u, 49739u, 49741u, 49747u, 49757u, 49783u,
+ 49787u, 49789u, 49801u, 49807u, 49811u, 49823u, 49831u, 49843u, 49853u,
+ 49871u, 49877u, 49891u, 49919u, 49921u, 49927u, 49937u, 49939u, 49943u,
+ 49957u, 49991u, 49993u, 49999u, 50021u, 50023u, 50033u, 50047u, 50051u,
+ 50053u, 50069u, 50077u, 50087u, 50093u, 50101u, 50111u, 50119u, 50123u,
+ 50129u, 50131u, 50147u, 50153u, 50159u, 50177u, 50207u, 50221u, 50227u,
+ 50231u, 50261u, 50263u, 50273u, 50287u, 50291u, 50311u, 50321u, 50329u,
+ 50333u, 50341u, 50359u, 50363u, 50377u, 50383u, 50387u, 50411u, 50417u,
+ 50423u, 50441u, 50459u, 50461u, 50497u, 50503u, 50513u, 50527u, 50539u,
+ 50543u, 50549u, 50551u, 50581u, 50587u, 50591u, 50593u, 50599u, 50627u,
+ 50647u, 50651u, 50671u, 50683u, 50707u, 50723u, 50741u, 50753u, 50767u,
+ 50773u, 50777u, 50789u, 50821u, 50833u, 50839u, 50849u, 50857u, 50867u,
+ 50873u, 50891u, 50893u, 50909u, 50923u, 50929u, 50951u, 50957u, 50969u,
+ 50971u, 50989u, 50993u, 51001u, 51031u, 51043u, 51047u, 51059u, 51061u,
+ 51071u, 51109u, 51131u, 51133u, 51137u, 51151u, 51157u, 51169u, 51193u,
+ 51197u, 51199u, 51203u, 51217u, 51229u, 51239u, 51241u, 51257u, 51263u,
+ 51283u, 51287u, 51307u, 51329u, 51341u, 51343u, 51347u, 51349u, 51361u,
+ 51383u, 51407u, 51413u, 51419u, 51421u, 51427u, 51431u, 51437u, 51439u,
+ 51449u, 51461u, 51473u, 51479u, 51481u, 51487u, 51503u, 51511u, 51517u,
+ 51521u, 51539u, 51551u, 51563u, 51577u, 51581u, 51593u, 51599u, 51607u,
+ 51613u, 51631u, 51637u, 51647u, 51659u, 51673u, 51679u, 51683u, 51691u,
+ 51713u, 51719u, 51721u, 51749u, 51767u, 51769u, 51787u, 51797u, 51803u,
+ 51817u, 51827u, 51829u, 51839u, 51853u, 51859u, 51869u, 51871u, 51893u,
+ 51899u, 51907u, 51913u, 51929u, 51941u, 51949u, 51971u, 51973u, 51977u,
+ 51991u, 52009u, 52021u, 52027u, 52051u, 52057u, 52067u, 52069u, 52081u,
+ 52103u, 52121u, 52127u, 52147u, 52153u, 52163u, 52177u, 52181u, 52183u,
+ 52189u, 52201u, 52223u, 52237u, 52249u, 52253u, 52259u, 52267u, 52289u,
+ 52291u, 52301u, 52313u, 52321u, 52361u, 52363u, 52369u, 52379u, 52387u,
+ 52391u, 52433u, 52453u, 52457u, 52489u, 52501u, 52511u, 52517u, 52529u,
+ 52541u, 52543u, 52553u, 52561u, 52567u, 52571u, 52579u, 52583u, 52609u,
+ 52627u, 52631u, 52639u, 52667u, 52673u, 52691u, 52697u, 52709u, 52711u,
+ 52721u, 52727u, 52733u, 52747u, 52757u, 52769u, 52783u, 52807u, 52813u,
+ 52817u, 52837u, 52859u, 52861u, 52879u, 52883u, 52889u, 52901u, 52903u,
+ 52919u, 52937u, 52951u, 52957u, 52963u, 52967u, 52973u, 52981u, 52999u,
+ 53003u, 53017u, 53047u, 53051u, 53069u, 53077u, 53087u, 53089u, 53093u,
+ 53101u, 53113u, 53117u, 53129u, 53147u, 53149u, 53161u, 53171u, 53173u,
+ 53189u, 53197u, 53201u, 53231u, 53233u, 53239u, 53267u, 53269u, 53279u,
+ 53281u, 53299u, 53309u, 53323u, 53327u, 53353u, 53359u, 53377u, 53381u,
+ 53401u, 53407u, 53411u, 53419u, 53437u, 53441u, 53453u, 53479u, 53503u,
+ 53507u, 53527u, 53549u, 53551u, 53569u, 53591u, 53593u, 53597u, 53609u,
+ 53611u, 53617u, 53623u, 53629u, 53633u, 53639u, 53653u, 53657u, 53681u,
+ 53693u, 53699u, 53717u, 53719u, 53731u, 53759u, 53773u, 53777u, 53783u,
+ 53791u, 53813u, 53819u, 53831u, 53849u, 53857u, 53861u, 53881u, 53887u,
+ 53891u, 53897u, 53899u, 53917u, 53923u, 53927u, 53939u, 53951u, 53959u,
+ 53987u, 53993u, 54001u, 54011u, 54013u, 54037u, 54049u, 54059u, 54083u,
+ 54091u, 54101u, 54121u, 54133u, 54139u, 54151u, 54163u, 54167u, 54181u,
+ 54193u, 54217u, 54251u, 54269u, 54277u, 54287u, 54293u, 54311u, 54319u,
+ 54323u, 54331u, 54347u, 54361u, 54367u, 54371u, 54377u, 54401u, 54403u,
+ 54409u, 54413u, 54419u, 54421u, 54437u, 54443u, 54449u, 54469u, 54493u,
+ 54497u, 54499u, 54503u, 54517u, 54521u, 54539u, 54541u, 54547u, 54559u,
+ 54563u, 54577u, 54581u, 54583u, 54601u, 54617u, 54623u, 54629u, 54631u,
+ 54647u, 54667u, 54673u, 54679u, 54709u, 54713u, 54721u, 54727u, 54751u,
+ 54767u, 54773u, 54779u, 54787u, 54799u, 54829u, 54833u, 54851u, 54869u,
+ 54877u, 54881u, 54907u, 54917u, 54919u, 54941u, 54949u, 54959u, 54973u,
+ 54979u, 54983u, 55001u, 55009u, 55021u, 55049u, 55051u, 55057u, 55061u,
+ 55073u, 55079u, 55103u, 55109u, 55117u, 55127u, 55147u, 55163u, 55171u,
+ 55201u, 55207u, 55213u, 55217u, 55219u, 55229u, 55243u, 55249u, 55259u,
+ 55291u, 55313u, 55331u, 55333u, 55337u, 55339u, 55343u, 55351u, 55373u,
+ 55381u, 55399u, 55411u, 55439u, 55441u, 55457u, 55469u, 55487u, 55501u,
+ 55511u, 55529u, 55541u, 55547u, 55579u, 55589u, 55603u, 55609u, 55619u,
+ 55621u, 55631u, 55633u, 55639u, 55661u, 55663u, 55667u, 55673u, 55681u,
+ 55691u, 55697u, 55711u, 55717u, 55721u, 55733u, 55763u, 55787u, 55793u,
+ 55799u, 55807u, 55813u, 55817u, 55819u, 55823u, 55829u, 55837u, 55843u,
+ 55849u, 55871u, 55889u, 55897u, 55901u, 55903u, 55921u, 55927u, 55931u,
+ 55933u, 55949u, 55967u, 55987u, 55997u, 56003u, 56009u, 56039u, 56041u,
+ 56053u, 56081u, 56087u, 56093u, 56099u, 56101u, 56113u, 56123u, 56131u,
+ 56149u, 56167u, 56171u, 56179u, 56197u, 56207u, 56209u, 56237u, 56239u,
+ 56249u, 56263u, 56267u, 56269u, 56299u, 56311u, 56333u, 56359u, 56369u,
+ 56377u, 56383u, 56393u, 56401u, 56417u, 56431u, 56437u, 56443u, 56453u,
+ 56467u, 56473u, 56477u, 56479u, 56489u, 56501u, 56503u, 56509u, 56519u,
+ 56527u, 56531u, 56533u, 56543u, 56569u, 56591u, 56597u, 56599u, 56611u,
+ 56629u, 56633u, 56659u, 56663u, 56671u, 56681u, 56687u, 56701u, 56711u,
+ 56713u, 56731u, 56737u, 56747u, 56767u, 56773u, 56779u, 56783u, 56807u,
+ 56809u, 56813u, 56821u, 56827u, 56843u, 56857u, 56873u, 56891u, 56893u,
+ 56897u, 56909u, 56911u, 56921u, 56923u, 56929u, 56941u, 56951u, 56957u,
+ 56963u, 56983u, 56989u, 56993u, 56999u, 57037u, 57041u, 57047u, 57059u,
+ 57073u, 57077u, 57089u, 57097u, 57107u, 57119u, 57131u, 57139u, 57143u,
+ 57149u, 57163u, 57173u, 57179u, 57191u, 57193u, 57203u, 57221u, 57223u,
+ 57241u, 57251u, 57259u, 57269u, 57271u, 57283u, 57287u, 57301u, 57329u,
+ 57331u, 57347u, 57349u, 57367u, 57373u, 57383u, 57389u, 57397u, 57413u,
+ 57427u, 57457u, 57467u, 57487u, 57493u, 57503u, 57527u, 57529u, 57557u,
+ 57559u, 57571u, 57587u, 57593u, 57601u, 57637u, 57641u, 57649u, 57653u,
+ 57667u, 57679u, 57689u, 57697u, 57709u, 57713u, 57719u, 57727u, 57731u,
+ 57737u, 57751u, 57773u, 57781u, 57787u, 57791u, 57793u, 57803u, 57809u,
+ 57829u, 57839u, 57847u, 57853u, 57859u, 57881u, 57899u, 57901u, 57917u,
+ 57923u, 57943u, 57947u, 57973u, 57977u, 57991u, 58013u, 58027u, 58031u,
+ 58043u, 58049u, 58057u, 58061u, 58067u, 58073u, 58099u, 58109u, 58111u,
+ 58129u, 58147u, 58151u, 58153u, 58169u, 58171u, 58189u, 58193u, 58199u,
+ 58207u, 58211u, 58217u, 58229u, 58231u, 58237u, 58243u, 58271u, 58309u,
+ 58313u, 58321u, 58337u, 58363u, 58367u, 58369u, 58379u, 58391u, 58393u,
+ 58403u, 58411u, 58417u, 58427u, 58439u, 58441u, 58451u, 58453u, 58477u,
+ 58481u, 58511u, 58537u, 58543u, 58549u, 58567u, 58573u, 58579u, 58601u,
+ 58603u, 58613u, 58631u, 58657u, 58661u, 58679u, 58687u, 58693u, 58699u,
+ 58711u, 58727u, 58733u, 58741u, 58757u, 58763u, 58771u, 58787u, 58789u,
+ 58831u, 58889u, 58897u, 58901u, 58907u, 58909u, 58913u, 58921u, 58937u,
+ 58943u, 58963u, 58967u, 58979u, 58991u, 58997u, 59009u, 59011u, 59021u,
+ 59023u, 59029u, 59051u, 59053u, 59063u, 59069u, 59077u, 59083u, 59093u,
+ 59107u, 59113u, 59119u, 59123u, 59141u, 59149u, 59159u, 59167u, 59183u,
+ 59197u, 59207u, 59209u, 59219u, 59221u, 59233u, 59239u, 59243u, 59263u,
+ 59273u, 59281u, 59333u, 59341u, 59351u, 59357u, 59359u, 59369u, 59377u,
+ 59387u, 59393u, 59399u, 59407u, 59417u, 59419u, 59441u, 59443u, 59447u,
+ 59453u, 59467u, 59471u, 59473u, 59497u, 59509u, 59513u, 59539u, 59557u,
+ 59561u, 59567u, 59581u, 59611u, 59617u, 59621u, 59627u, 59629u, 59651u,
+ 59659u, 59663u, 59669u, 59671u, 59693u, 59699u, 59707u, 59723u, 59729u,
+ 59743u, 59747u, 59753u, 59771u, 59779u, 59791u, 59797u, 59809u, 59833u,
+ 59863u, 59879u, 59887u, 59921u, 59929u, 59951u, 59957u, 59971u, 59981u,
+ 59999u, 60013u, 60017u, 60029u, 60037u, 60041u, 60077u, 60083u, 60089u,
+ 60091u, 60101u, 60103u, 60107u, 60127u, 60133u, 60139u, 60149u, 60161u,
+ 60167u, 60169u, 60209u, 60217u, 60223u, 60251u, 60257u, 60259u, 60271u,
+ 60289u, 60293u, 60317u, 60331u, 60337u, 60343u, 60353u, 60373u, 60383u,
+ 60397u, 60413u, 60427u, 60443u, 60449u, 60457u, 60493u, 60497u, 60509u,
+ 60521u, 60527u, 60539u, 60589u, 60601u, 60607u, 60611u, 60617u, 60623u,
+ 60631u, 60637u, 60647u, 60649u, 60659u, 60661u, 60679u, 60689u, 60703u,
+ 60719u, 60727u, 60733u, 60737u, 60757u, 60761u, 60763u, 60773u, 60779u,
+ 60793u, 60811u, 60821u, 60859u, 60869u, 60887u, 60889u, 60899u, 60901u,
+ 60913u, 60917u, 60919u, 60923u, 60937u, 60943u, 60953u, 60961u, 61001u,
+ 61007u, 61027u, 61031u, 61043u, 61051u, 61057u, 61091u, 61099u, 61121u,
+ 61129u, 61141u, 61151u, 61153u, 61169u, 61211u, 61223u, 61231u, 61253u,
+ 61261u, 61283u, 61291u, 61297u, 61331u, 61333u, 61339u, 61343u, 61357u,
+ 61363u, 61379u, 61381u, 61403u, 61409u, 61417u, 61441u, 61463u, 61469u,
+ 61471u, 61483u, 61487u, 61493u, 61507u, 61511u, 61519u, 61543u, 61547u,
+ 61553u, 61559u, 61561u, 61583u, 61603u, 61609u, 61613u, 61627u, 61631u,
+ 61637u, 61643u, 61651u, 61657u, 61667u, 61673u, 61681u, 61687u, 61703u,
+ 61717u, 61723u, 61729u, 61751u, 61757u, 61781u, 61813u, 61819u, 61837u,
+ 61843u, 61861u, 61871u, 61879u, 61909u, 61927u, 61933u, 61949u, 61961u,
+ 61967u, 61979u, 61981u, 61987u, 61991u, 62003u, 62011u, 62017u, 62039u,
+ 62047u, 62053u, 62057u, 62071u, 62081u, 62099u, 62119u, 62129u, 62131u,
+ 62137u, 62141u, 62143u, 62171u, 62189u, 62191u, 62201u, 62207u, 62213u,
+ 62219u, 62233u, 62273u, 62297u, 62299u, 62303u, 62311u, 62323u, 62327u,
+ 62347u, 62351u, 62383u, 62401u, 62417u, 62423u, 62459u, 62467u, 62473u,
+ 62477u, 62483u, 62497u, 62501u, 62507u, 62533u, 62539u, 62549u, 62563u,
+ 62581u, 62591u, 62597u, 62603u, 62617u, 62627u, 62633u, 62639u, 62653u,
+ 62659u, 62683u, 62687u, 62701u, 62723u, 62731u, 62743u, 62753u, 62761u,
+ 62773u, 62791u, 62801u, 62819u, 62827u, 62851u, 62861u, 62869u, 62873u,
+ 62897u, 62903u, 62921u, 62927u, 62929u, 62939u, 62969u, 62971u, 62981u,
+ 62983u, 62987u, 62989u, 63029u, 63031u, 63059u, 63067u, 63073u, 63079u,
+ 63097u, 63103u, 63113u, 63127u, 63131u, 63149u, 63179u, 63197u, 63199u,
+ 63211u, 63241u, 63247u, 63277u, 63281u, 63299u, 63311u, 63313u, 63317u,
+ 63331u, 63337u, 63347u, 63353u, 63361u, 63367u, 63377u, 63389u, 63391u,
+ 63397u, 63409u, 63419u, 63421u, 63439u, 63443u, 63463u, 63467u, 63473u,
+ 63487u, 63493u, 63499u, 63521u, 63527u, 63533u, 63541u, 63559u, 63577u,
+ 63587u, 63589u, 63599u, 63601u, 63607u, 63611u, 63617u, 63629u, 63647u,
+ 63649u, 63659u, 63667u, 63671u, 63689u, 63691u, 63697u, 63703u, 63709u,
+ 63719u, 63727u, 63737u, 63743u, 63761u, 63773u, 63781u, 63793u, 63799u,
+ 63803u, 63809u, 63823u, 63839u, 63841u, 63853u, 63857u, 63863u, 63901u,
+ 63907u, 63913u, 63929u, 63949u, 63977u, 63997u, 64007u, 64013u, 64019u,
+ 64033u, 64037u, 64063u, 64067u, 64081u, 64091u, 64109u, 64123u, 64151u,
+ 64153u, 64157u, 64171u, 64187u, 64189u, 64217u, 64223u, 64231u, 64237u,
+ 64271u, 64279u, 64283u, 64301u, 64303u, 64319u, 64327u, 64333u, 64373u,
+ 64381u, 64399u, 64403u, 64433u, 64439u, 64451u, 64453u, 64483u, 64489u,
+ 64499u, 64513u, 64553u, 64567u, 64577u, 64579u, 64591u, 64601u, 64609u,
+ 64613u, 64621u, 64627u, 64633u, 64661u, 64663u, 64667u, 64679u, 64693u,
+ 64709u, 64717u, 64747u, 64763u, 64781u, 64783u, 64793u, 64811u, 64817u,
+ 64849u, 64853u, 64871u, 64877u, 64879u, 64891u, 64901u, 64919u, 64921u,
+ 64927u, 64937u, 64951u, 64969u, 64997u, 65003u, 65011u, 65027u, 65029u,
+ 65033u, 65053u, 65063u, 65071u, 65089u, 65099u, 65101u, 65111u, 65119u,
+ 65123u, 65129u, 65141u, 65147u, 65167u, 65171u, 65173u, 65179u, 65183u,
+ 65203u, 65213u, 65239u, 65257u, 65267u, 65269u, 65287u, 65293u, 65309u,
+ 65323u, 65327u, 65353u, 65357u, 65371u, 65381u, 65393u, 65407u, 65413u,
+ 65419u, 65423u, 65437u, 65447u, 65449u, 65479u, 65497u, 65519u, 65521u
+ }};
+ static const boost::array<boost::uint16_t, 3458> a3 = {{
+ 2u, 4u, 8u, 16u, 22u, 28u, 44u,
+ 46u, 52u, 64u, 74u, 82u, 94u, 98u, 112u,
+ 116u, 122u, 142u, 152u, 164u, 166u, 172u, 178u,
+ 182u, 184u, 194u, 196u, 226u, 242u, 254u, 274u,
+ 292u, 296u, 302u, 304u, 308u, 316u, 332u, 346u,
+ 364u, 386u, 392u, 394u, 416u, 422u, 428u, 446u,
+ 448u, 458u, 494u, 502u, 506u, 512u, 532u, 536u,
+ 548u, 554u, 568u, 572u, 574u, 602u, 626u, 634u,
+ 638u, 644u, 656u, 686u, 704u, 736u, 758u, 766u,
+ 802u, 808u, 812u, 824u, 826u, 838u, 842u, 848u,
+ 868u, 878u, 896u, 914u, 922u, 928u, 932u, 956u,
+ 964u, 974u, 988u, 994u, 998u, 1006u, 1018u, 1034u,
+ 1036u, 1052u, 1058u, 1066u, 1082u, 1094u, 1108u, 1118u,
+ 1148u, 1162u, 1166u, 1178u, 1186u, 1198u, 1204u, 1214u,
+ 1216u, 1228u, 1256u, 1262u, 1274u, 1286u, 1306u, 1316u,
+ 1318u, 1328u, 1342u, 1348u, 1354u, 1384u, 1388u, 1396u,
+ 1408u, 1412u, 1414u, 1424u, 1438u, 1442u, 1468u, 1486u,
+ 1498u, 1508u, 1514u, 1522u, 1526u, 1538u, 1544u, 1568u,
+ 1586u, 1594u, 1604u, 1606u, 1618u, 1622u, 1634u, 1646u,
+ 1652u, 1654u, 1676u, 1678u, 1682u, 1684u, 1696u, 1712u,
+ 1726u, 1736u, 1738u, 1754u, 1772u, 1804u, 1808u, 1814u,
+ 1834u, 1856u, 1864u, 1874u, 1876u, 1886u, 1892u, 1894u,
+ 1898u, 1912u, 1918u, 1942u, 1946u, 1954u, 1958u, 1964u,
+ 1976u, 1988u, 1996u, 2002u, 2012u, 2024u, 2032u, 2042u,
+ 2044u, 2054u, 2066u, 2072u, 2084u, 2096u, 2116u, 2144u,
+ 2164u, 2174u, 2188u, 2198u, 2206u, 2216u, 2222u, 2224u,
+ 2228u, 2242u, 2248u, 2254u, 2266u, 2272u, 2284u, 2294u,
+ 2308u, 2318u, 2332u, 2348u, 2356u, 2366u, 2392u, 2396u,
+ 2398u, 2404u, 2408u, 2422u, 2426u, 2432u, 2444u, 2452u,
+ 2458u, 2488u, 2506u, 2518u, 2524u, 2536u, 2552u, 2564u,
+ 2576u, 2578u, 2606u, 2612u, 2626u, 2636u, 2672u, 2674u,
+ 2678u, 2684u, 2692u, 2704u, 2726u, 2744u, 2746u, 2776u,
+ 2794u, 2816u, 2836u, 2854u, 2864u, 2902u, 2908u, 2912u,
+ 2914u, 2938u, 2942u, 2948u, 2954u, 2956u, 2966u, 2972u,
+ 2986u, 2996u, 3004u, 3008u, 3032u, 3046u, 3062u, 3076u,
+ 3098u, 3104u, 3124u, 3134u, 3148u, 3152u, 3164u, 3176u,
+ 3178u, 3194u, 3202u, 3208u, 3214u, 3232u, 3236u, 3242u,
+ 3256u, 3278u, 3284u, 3286u, 3328u, 3344u, 3346u, 3356u,
+ 3362u, 3364u, 3368u, 3374u, 3382u, 3392u, 3412u, 3428u,
+ 3458u, 3466u, 3476u, 3484u, 3494u, 3496u, 3526u, 3532u,
+ 3538u, 3574u, 3584u, 3592u, 3608u, 3614u, 3616u, 3628u,
+ 3656u, 3658u, 3662u, 3668u, 3686u, 3698u, 3704u, 3712u,
+ 3722u, 3724u, 3728u, 3778u, 3782u, 3802u, 3806u, 3836u,
+ 3844u, 3848u, 3854u, 3866u, 3868u, 3892u, 3896u, 3904u,
+ 3922u, 3928u, 3932u, 3938u, 3946u, 3956u, 3958u, 3962u,
+ 3964u, 4004u, 4022u, 4058u, 4088u, 4118u, 4126u, 4142u,
+ 4156u, 4162u, 4174u, 4202u, 4204u, 4226u, 4228u, 4232u,
+ 4244u, 4274u, 4286u, 4292u, 4294u, 4298u, 4312u, 4322u,
+ 4324u, 4342u, 4364u, 4376u, 4394u, 4396u, 4406u, 4424u,
+ 4456u, 4462u, 4466u, 4468u, 4474u, 4484u, 4504u, 4516u,
+ 4526u, 4532u, 4544u, 4564u, 4576u, 4582u, 4586u, 4588u,
+ 4604u, 4606u, 4622u, 4628u, 4642u, 4646u, 4648u, 4664u,
+ 4666u, 4672u, 4688u, 4694u, 4702u, 4706u, 4714u, 4736u,
+ 4754u, 4762u, 4774u, 4778u, 4786u, 4792u, 4816u, 4838u,
+ 4844u, 4846u, 4858u, 4888u, 4894u, 4904u, 4916u, 4922u,
+ 4924u, 4946u, 4952u, 4954u, 4966u, 4972u, 4994u, 5002u,
+ 5014u, 5036u, 5038u, 5048u, 5054u, 5072u, 5084u, 5086u,
+ 5092u, 5104u, 5122u, 5128u, 5132u, 5152u, 5174u, 5182u,
+ 5194u, 5218u, 5234u, 5248u, 5258u, 5288u, 5306u, 5308u,
+ 5314u, 5318u, 5332u, 5342u, 5344u, 5356u, 5366u, 5378u,
+ 5384u, 5386u, 5402u, 5414u, 5416u, 5422u, 5434u, 5444u,
+ 5446u, 5456u, 5462u, 5464u, 5476u, 5488u, 5504u, 5524u,
+ 5534u, 5546u, 5554u, 5584u, 5594u, 5608u, 5612u, 5618u,
+ 5626u, 5632u, 5636u, 5656u, 5674u, 5698u, 5702u, 5714u,
+ 5722u, 5726u, 5728u, 5752u, 5758u, 5782u, 5792u, 5794u,
+ 5798u, 5804u, 5806u, 5812u, 5818u, 5824u, 5828u, 5852u,
+ 5854u, 5864u, 5876u, 5878u, 5884u, 5894u, 5902u, 5908u,
+ 5918u, 5936u, 5938u, 5944u, 5948u, 5968u, 5992u, 6002u,
+ 6014u, 6016u, 6028u, 6034u, 6058u, 6062u, 6098u, 6112u,
+ 6128u, 6136u, 6158u, 6164u, 6172u, 6176u, 6178u, 6184u,
+ 6206u, 6226u, 6242u, 6254u, 6272u, 6274u, 6286u, 6302u,
+ 6308u, 6314u, 6326u, 6332u, 6344u, 6346u, 6352u, 6364u,
+ 6374u, 6382u, 6398u, 6406u, 6412u, 6428u, 6436u, 6448u,
+ 6452u, 6458u, 6464u, 6484u, 6496u, 6508u, 6512u, 6518u,
+ 6538u, 6542u, 6554u, 6556u, 6566u, 6568u, 6574u, 6604u,
+ 6626u, 6632u, 6634u, 6638u, 6676u, 6686u, 6688u, 6692u,
+ 6694u, 6716u, 6718u, 6734u, 6736u, 6742u, 6752u, 6772u,
+ 6778u, 6802u, 6806u, 6818u, 6832u, 6844u, 6848u, 6886u,
+ 6896u, 6926u, 6932u, 6934u, 6946u, 6958u, 6962u, 6968u,
+ 6998u, 7012u, 7016u, 7024u, 7042u, 7078u, 7082u, 7088u,
+ 7108u, 7112u, 7114u, 7126u, 7136u, 7138u, 7144u, 7154u,
+ 7166u, 7172u, 7184u, 7192u, 7198u, 7204u, 7228u, 7232u,
+ 7262u, 7282u, 7288u, 7324u, 7334u, 7336u, 7348u, 7354u,
+ 7358u, 7366u, 7372u, 7376u, 7388u, 7396u, 7402u, 7414u,
+ 7418u, 7424u, 7438u, 7442u, 7462u, 7474u, 7478u, 7484u,
+ 7502u, 7504u, 7508u, 7526u, 7528u, 7544u, 7556u, 7586u,
+ 7592u, 7598u, 7606u, 7646u, 7654u, 7702u, 7708u, 7724u,
+ 7742u, 7756u, 7768u, 7774u, 7792u, 7796u, 7816u, 7826u,
+ 7828u, 7834u, 7844u, 7852u, 7882u, 7886u, 7898u, 7918u,
+ 7924u, 7936u, 7942u, 7948u, 7982u, 7988u, 7994u, 8012u,
+ 8018u, 8026u, 8036u, 8048u, 8054u, 8062u, 8072u, 8074u,
+ 8078u, 8102u, 8108u, 8116u, 8138u, 8144u, 8146u, 8158u,
+ 8164u, 8174u, 8186u, 8192u, 8216u, 8222u, 8236u, 8248u,
+ 8284u, 8288u, 8312u, 8314u, 8324u, 8332u, 8342u, 8348u,
+ 8362u, 8372u, 8404u, 8408u, 8416u, 8426u, 8438u, 8464u,
+ 8482u, 8486u, 8492u, 8512u, 8516u, 8536u, 8542u, 8558u,
+ 8564u, 8566u, 8596u, 8608u, 8614u, 8624u, 8626u, 8632u,
+ 8642u, 8654u, 8662u, 8666u, 8668u, 8674u, 8684u, 8696u,
+ 8722u, 8744u, 8752u, 8758u, 8762u, 8776u, 8782u, 8788u,
+ 8818u, 8822u, 8828u, 8842u, 8846u, 8848u, 8876u, 8878u,
+ 8884u, 8906u, 8914u, 8918u, 8936u, 8954u, 8972u, 8974u,
+ 8986u, 8992u, 8996u, 9016u, 9026u, 9032u, 9038u, 9052u,
+ 9062u, 9074u, 9076u, 9088u, 9118u, 9152u, 9164u, 9172u,
+ 9178u, 9182u, 9184u, 9194u, 9196u, 9212u, 9224u, 9226u,
+ 9236u, 9244u, 9262u, 9286u, 9292u, 9296u, 9308u, 9322u,
+ 9326u, 9334u, 9338u, 9352u, 9356u, 9362u, 9368u, 9388u,
+ 9394u, 9398u, 9406u, 9424u, 9476u, 9478u, 9482u, 9494u,
+ 9502u, 9506u, 9544u, 9548u, 9574u, 9598u, 9614u, 9626u,
+ 9632u, 9634u, 9646u, 9658u, 9674u, 9676u, 9682u, 9688u,
+ 9692u, 9704u, 9718u, 9734u, 9742u, 9754u, 9772u, 9788u,
+ 9794u, 9802u, 9812u, 9818u, 9832u, 9842u, 9854u, 9856u,
+ 9866u, 9868u, 9872u, 9896u, 9902u, 9944u, 9968u, 9976u,
+ 9986u, 9992u, 9998u, 10004u, 10006u, 10018u, 10022u, 10036u,
+ 10042u, 10048u, 10076u, 10082u, 10084u, 10094u, 10106u, 10118u,
+ 10124u, 10144u, 10148u, 10154u, 10168u, 10172u, 10174u, 10186u,
+ 10196u, 10208u, 10232u, 10238u, 10246u, 10252u, 10258u, 10262u,
+ 10286u, 10298u, 10318u, 10334u, 10348u, 10378u, 10396u, 10402u,
+ 10406u, 10432u, 10444u, 10448u, 10454u, 10456u, 10462u, 10466u,
+ 10468u, 10496u, 10504u, 10544u, 10546u, 10556u, 10564u, 10568u,
+ 10588u, 10594u, 10612u, 10622u, 10624u, 10628u, 10672u, 10678u,
+ 10696u, 10708u, 10714u, 10718u, 10724u, 10726u, 10748u, 10754u,
+ 10768u, 10798u, 10808u, 10832u, 10834u, 10844u, 10852u, 10868u,
+ 10886u, 10888u, 10906u, 10928u, 10936u, 10946u, 10952u, 10958u,
+ 10972u, 10976u, 10984u, 11002u, 11006u, 11008u, 11026u, 11044u,
+ 11062u, 11068u, 11072u, 11096u, 11114u, 11116u, 11132u, 11138u,
+ 11144u, 11162u, 11182u, 11198u, 11218u, 11222u, 11236u, 11242u,
+ 11246u, 11266u, 11284u, 11294u, 11296u, 11302u, 11312u, 11336u,
+ 11338u, 11348u, 11372u, 11378u, 11384u, 11408u, 11414u, 11426u,
+ 11428u, 11456u, 11468u, 11482u, 11488u, 11494u, 11506u, 11512u,
+ 11534u, 11546u, 11558u, 11566u, 11602u, 11606u, 11618u, 11632u,
+ 11636u, 11656u, 11666u, 11678u, 11702u, 11704u, 11708u, 11714u,
+ 11726u, 11728u, 11732u, 11734u, 11744u, 11756u, 11782u, 11788u,
+ 11804u, 11812u, 11816u, 11824u, 11834u, 11842u, 11848u, 11882u,
+ 11884u, 11896u, 11912u, 11936u, 11942u, 11944u, 11954u, 11956u,
+ 11974u, 11978u, 11986u, 11992u, 12008u, 12014u, 12016u, 12022u,
+ 12028u, 12034u, 12038u, 12052u, 12056u, 12076u, 12082u, 12086u,
+ 12106u, 12112u, 12124u, 12146u, 12152u, 12154u, 12164u, 12176u,
+ 12178u, 12184u, 12188u, 12196u, 12208u, 12212u, 12226u, 12238u,
+ 12248u, 12262u, 12266u, 12278u, 12304u, 12314u, 12328u, 12332u,
+ 12358u, 12364u, 12394u, 12398u, 12416u, 12434u, 12442u, 12448u,
+ 12464u, 12472u, 12482u, 12496u, 12506u, 12514u, 12524u, 12544u,
+ 12566u, 12586u, 12602u, 12604u, 12622u, 12628u, 12632u, 12638u,
+ 12644u, 12656u, 12658u, 12668u, 12694u, 12698u, 12706u, 12724u,
+ 12742u, 12748u, 12766u, 12772u, 12776u, 12782u, 12806u, 12812u,
+ 12832u, 12866u, 12892u, 12902u, 12904u, 12932u, 12944u, 12952u,
+ 12962u, 12974u, 12976u, 12982u, 13004u, 13006u, 13018u, 13034u,
+ 13036u, 13042u, 13048u, 13058u, 13072u, 13088u, 13108u, 13114u,
+ 13118u, 13156u, 13162u, 13172u, 13178u, 13186u, 13202u, 13244u,
+ 13246u, 13252u, 13256u, 13262u, 13268u, 13274u, 13288u, 13304u,
+ 13318u, 13322u, 13342u, 13352u, 13354u, 13358u, 13366u, 13384u,
+ 13394u, 13406u, 13442u, 13444u, 13454u, 13496u, 13504u, 13508u,
+ 13528u, 13552u, 13568u, 13576u, 13598u, 13604u, 13612u, 13616u,
+ 13618u, 13624u, 13646u, 13652u, 13658u, 13666u, 13694u, 13696u,
+ 13706u, 13724u, 13738u, 13744u, 13748u, 13766u, 13774u, 13784u,
+ 13798u, 13802u, 13814u, 13822u, 13832u, 13844u, 13858u, 13862u,
+ 13864u, 13876u, 13888u, 13892u, 13898u, 13916u, 13946u, 13958u,
+ 13996u, 14002u, 14014u, 14024u, 14026u, 14044u, 14054u, 14066u,
+ 14074u, 14078u, 14086u, 14092u, 14096u, 14098u, 14122u, 14134u,
+ 14152u, 14156u, 14158u, 14162u, 14164u, 14222u, 14234u, 14242u,
+ 14266u, 14276u, 14278u, 14282u, 14288u, 14294u, 14306u, 14308u,
+ 14312u, 14326u, 14332u, 14338u, 14354u, 14366u, 14368u, 14372u,
+ 14404u, 14408u, 14432u, 14438u, 14444u, 14452u, 14462u, 14464u,
+ 14486u, 14504u, 14516u, 14536u, 14542u, 14572u, 14576u, 14606u,
+ 14612u, 14614u, 14618u, 14632u, 14638u, 14642u, 14656u, 14672u,
+ 14674u, 14686u, 14696u, 14698u, 14704u, 14716u, 14728u, 14738u,
+ 14744u, 14752u, 14774u, 14782u, 14794u, 14806u, 14812u, 14828u,
+ 14834u, 14852u, 14872u, 14894u, 14912u, 14914u, 14936u, 14938u,
+ 14954u, 14956u, 14978u, 14992u, 15002u, 15022u, 15032u, 15064u,
+ 15068u, 15076u, 15086u, 15092u, 15094u, 15116u, 15122u, 15134u,
+ 15136u, 15142u, 15146u, 15148u, 15152u, 15166u, 15178u, 15202u,
+ 15212u, 15214u, 15226u, 15242u, 15244u, 15248u, 15254u, 15268u,
+ 15274u, 15284u, 15296u, 15298u, 15314u, 15328u, 15362u, 15374u,
+ 15376u, 15382u, 15388u, 15394u, 15398u, 15418u, 15428u, 15454u,
+ 15466u, 15478u, 15482u, 15484u, 15488u, 15496u, 15506u, 15508u,
+ 15512u, 15514u, 15536u, 15542u, 15548u, 15562u, 15566u, 15584u,
+ 15596u, 15622u, 15628u, 15638u, 15646u, 15662u, 15664u, 15668u,
+ 15688u, 15698u, 15704u, 15746u, 15748u, 15758u, 15764u, 15772u,
+ 15796u, 15808u, 15814u, 15818u, 15824u, 15836u, 15838u, 15866u,
+ 15874u, 15886u, 15904u, 15922u, 15928u, 15974u, 15982u, 15992u,
+ 15998u, 16012u, 16016u, 16018u, 16024u, 16028u, 16034u, 16076u,
+ 16084u, 16094u, 16102u, 16112u, 16114u, 16132u, 16136u, 16142u,
+ 16154u, 16166u, 16168u, 16172u, 16192u, 16202u, 16214u, 16226u,
+ 16234u, 16238u, 16264u, 16282u, 16304u, 16312u, 16318u, 16334u,
+ 16348u, 16364u, 16366u, 16384u, 16394u, 16396u, 16402u, 16408u,
+ 16418u, 16432u, 16436u, 16438u, 16468u, 16472u, 16474u, 16478u,
+ 16486u, 16496u, 16502u, 16504u, 16516u, 16532u, 16538u, 16594u,
+ 16604u, 16606u, 16618u, 16628u, 16636u, 16648u, 16654u, 16658u,
+ 16672u, 16682u, 16684u, 16688u, 16696u, 16702u, 16706u, 16726u,
+ 16732u, 16744u, 16766u, 16772u, 16804u, 16814u, 16816u, 16826u,
+ 16838u, 16852u, 16858u, 16886u, 16922u, 16928u, 16934u, 16936u,
+ 16948u, 16952u, 16958u, 16964u, 16972u, 16994u, 16996u, 17014u,
+ 17024u, 17026u, 17032u, 17036u, 17056u, 17066u, 17074u, 17078u,
+ 17084u, 17098u, 17116u, 17122u, 17164u, 17186u, 17188u, 17192u,
+ 17194u, 17222u, 17224u, 17228u, 17246u, 17252u, 17258u, 17264u,
+ 17276u, 17278u, 17302u, 17312u, 17348u, 17354u, 17356u, 17368u,
+ 17378u, 17404u, 17428u, 17446u, 17462u, 17468u, 17474u, 17488u,
+ 17512u, 17524u, 17528u, 17536u, 17542u, 17554u, 17558u, 17566u,
+ 17582u, 17602u, 17642u, 17668u, 17672u, 17684u, 17686u, 17692u,
+ 17696u, 17698u, 17708u, 17722u, 17732u, 17734u, 17738u, 17764u,
+ 17776u, 17804u, 17806u, 17822u, 17848u, 17854u, 17864u, 17866u,
+ 17872u, 17882u, 17888u, 17896u, 17902u, 17908u, 17914u, 17924u,
+ 17936u, 17942u, 17962u, 18002u, 18022u, 18026u, 18028u, 18044u,
+ 18056u, 18062u, 18074u, 18082u, 18086u, 18104u, 18106u, 18118u,
+ 18128u, 18154u, 18166u, 18182u, 18184u, 18202u, 18226u, 18238u,
+ 18242u, 18256u, 18278u, 18298u, 18308u, 18322u, 18334u, 18338u,
+ 18356u, 18368u, 18376u, 18386u, 18398u, 18404u, 18434u, 18448u,
+ 18452u, 18476u, 18482u, 18512u, 18518u, 18524u, 18526u, 18532u,
+ 18554u, 18586u, 18592u, 18596u, 18602u, 18608u, 18628u, 18644u,
+ 18646u, 18656u, 18664u, 18676u, 18686u, 18688u, 18694u, 18704u,
+ 18712u, 18728u, 18764u, 18772u, 18778u, 18782u, 18784u, 18812u,
+ 18814u, 18842u, 18854u, 18856u, 18866u, 18872u, 18886u, 18896u,
+ 18902u, 18908u, 18914u, 18922u, 18928u, 18932u, 18946u, 18964u,
+ 18968u, 18974u, 18986u, 18988u, 18998u, 19016u, 19024u, 19054u,
+ 19094u, 19096u, 19114u, 19118u, 19124u, 19138u, 19156u, 19162u,
+ 19166u, 19178u, 19184u, 19196u, 19202u, 19216u, 19226u, 19252u,
+ 19258u, 19274u, 19276u, 19292u, 19322u, 19324u, 19334u, 19336u,
+ 19378u, 19384u, 19412u, 19426u, 19432u, 19442u, 19444u, 19456u,
+ 19474u, 19486u, 19492u, 19502u, 19514u, 19526u, 19546u, 19552u,
+ 19556u, 19558u, 19568u, 19574u, 19586u, 19598u, 19612u, 19624u,
+ 19658u, 19664u, 19666u, 19678u, 19688u, 19694u, 19702u, 19708u,
+ 19712u, 19724u, 19762u, 19768u, 19778u, 19796u, 19798u, 19826u,
+ 19828u, 19834u, 19846u, 19876u, 19892u, 19894u, 19904u, 19912u,
+ 19916u, 19918u, 19934u, 19952u, 19978u, 19982u, 19988u, 19996u,
+ 20014u, 20036u, 20042u, 20062u, 20066u, 20072u, 20084u, 20086u,
+ 20092u, 20104u, 20108u, 20126u, 20132u, 20134u, 20156u, 20168u,
+ 20176u, 20182u, 20198u, 20216u, 20246u, 20258u, 20282u, 20284u,
+ 20294u, 20296u, 20302u, 20308u, 20312u, 20318u, 20354u, 20368u,
+ 20374u, 20396u, 20398u, 20456u, 20464u, 20476u, 20482u, 20492u,
+ 20494u, 20534u, 20542u, 20548u, 20576u, 20578u, 20582u, 20596u,
+ 20602u, 20608u, 20626u, 20636u, 20644u, 20648u, 20662u, 20666u,
+ 20674u, 20704u, 20708u, 20714u, 20722u, 20728u, 20734u, 20752u,
+ 20756u, 20758u, 20762u, 20776u, 20788u, 20806u, 20816u, 20818u,
+ 20822u, 20834u, 20836u, 20846u, 20854u, 20864u, 20878u, 20888u,
+ 20906u, 20918u, 20926u, 20932u, 20942u, 20956u, 20966u, 20974u,
+ 20996u, 20998u, 21004u, 21026u, 21038u, 21044u, 21052u, 21064u,
+ 21092u, 21094u, 21142u, 21154u, 21158u, 21176u, 21184u, 21194u,
+ 21208u, 21218u, 21232u, 21236u, 21248u, 21278u, 21302u, 21308u,
+ 21316u, 21322u, 21326u, 21334u, 21388u, 21392u, 21394u, 21404u,
+ 21416u, 21424u, 21434u, 21446u, 21458u, 21476u, 21478u, 21502u,
+ 21506u, 21514u, 21536u, 21548u, 21568u, 21572u, 21584u, 21586u,
+ 21598u, 21614u, 21616u, 21644u, 21646u, 21652u, 21676u, 21686u,
+ 21688u, 21716u, 21718u, 21722u, 21742u, 21746u, 21758u, 21764u,
+ 21778u, 21782u, 21788u, 21802u, 21824u, 21848u, 21868u, 21872u,
+ 21886u, 21892u, 21898u, 21908u, 21938u, 21946u, 21956u, 21974u,
+ 21976u, 21982u, 21988u, 22004u, 22006u, 22012u, 22018u, 22022u,
+ 22024u, 22048u, 22052u, 22054u, 22078u, 22088u, 22094u, 22096u,
+ 22106u, 22108u, 22114u, 22136u, 22144u, 22148u, 22156u, 22162u,
+ 22166u, 22184u, 22186u, 22204u, 22208u, 22216u, 22232u, 22258u,
+ 22262u, 22268u, 22276u, 22298u, 22318u, 22334u, 22342u, 22346u,
+ 22352u, 22376u, 22382u, 22396u, 22408u, 22424u, 22426u, 22438u,
+ 22442u, 22456u, 22466u, 22468u, 22472u, 22484u, 22502u, 22534u,
+ 22544u, 22558u, 22582u, 22594u, 22634u, 22642u, 22676u, 22688u,
+ 22702u, 22706u, 22724u, 22726u, 22754u, 22766u, 22786u, 22792u,
+ 22802u, 22804u, 22844u, 22862u, 22876u, 22888u, 22892u, 22928u,
+ 22934u, 22936u, 22958u, 22964u, 22978u, 22988u, 23012u, 23054u,
+ 23056u, 23072u, 23074u, 23108u, 23116u, 23122u, 23126u, 23128u,
+ 23132u, 23146u, 23186u, 23194u, 23206u, 23212u, 23236u, 23254u,
+ 23258u, 23264u, 23266u, 23272u, 23276u, 23278u, 23282u, 23284u,
+ 23308u, 23318u, 23326u, 23332u, 23338u, 23348u, 23362u, 23368u,
+ 23384u, 23402u, 23416u, 23434u, 23458u, 23462u, 23468u, 23474u,
+ 23482u, 23486u, 23506u, 23516u, 23522u, 23534u, 23536u, 23548u,
+ 23552u, 23566u, 23572u, 23578u, 23584u, 23588u, 23602u, 23618u,
+ 23654u, 23668u, 23674u, 23678u, 23692u, 23696u, 23702u, 23726u,
+ 23734u, 23738u, 23758u, 23768u, 23782u, 23794u, 23828u, 23836u,
+ 23846u, 23852u, 23858u, 23864u, 23878u, 23882u, 23896u, 23908u,
+ 23914u, 23924u, 23942u, 23956u, 23966u, 23978u, 23984u, 23986u,
+ 23992u, 23998u, 24026u, 24028u, 24032u, 24056u, 24062u, 24064u,
+ 24068u, 24076u, 24092u, 24098u, 24118u, 24122u, 24124u, 24134u,
+ 24136u, 24146u, 24154u, 24218u, 24224u, 24232u, 24244u, 24248u,
+ 24262u, 24274u, 24284u, 24286u, 24298u, 24304u, 24314u, 24332u,
+ 24356u, 24362u, 24364u, 24374u, 24382u, 24388u, 24404u, 24424u,
+ 24428u, 24442u, 24448u, 24454u, 24466u, 24472u, 24476u, 24482u,
+ 24484u, 24488u, 24496u, 24518u, 24524u, 24532u, 24536u, 24538u,
+ 24554u, 24572u, 24586u, 24592u, 24614u, 24628u, 24638u, 24652u,
+ 24656u, 24662u, 24664u, 24668u, 24682u, 24692u, 24704u, 24712u,
+ 24728u, 24736u, 24746u, 24754u, 24778u, 24818u, 24824u, 24836u,
+ 24838u, 24844u, 24862u, 24866u, 24868u, 24872u, 24902u, 24904u,
+ 24934u, 24938u, 24946u, 24964u, 24976u, 24988u, 24992u, 24994u,
+ 24998u, 25012u, 25048u, 25064u, 25082u, 25084u, 25096u, 25106u,
+ 25112u, 25124u, 25142u, 25144u, 25162u, 25168u, 25174u, 25196u,
+ 25214u, 25252u, 25258u, 25268u, 25286u, 25288u, 25298u, 25306u,
+ 25312u, 25328u, 25352u, 25366u, 25372u, 25376u, 25382u, 25396u,
+ 25412u, 25436u, 25442u, 25454u, 25462u, 25474u, 25484u, 25498u,
+ 25544u, 25546u, 25562u, 25564u, 25586u, 25592u, 25594u, 25604u,
+ 25606u, 25616u, 25618u, 25624u, 25628u, 25648u, 25658u, 25664u,
+ 25694u, 25702u, 25708u, 25714u, 25718u, 25748u, 25756u, 25762u,
+ 25768u, 25774u, 25796u, 25832u, 25834u, 25838u, 25846u, 25852u,
+ 25858u, 25862u, 25876u, 25888u, 25898u, 25918u, 25922u, 25924u,
+ 25928u, 25958u, 25964u, 25978u, 25994u, 26006u, 26036u, 26038u,
+ 26042u, 26048u, 26056u, 26086u, 26096u, 26104u, 26138u, 26156u,
+ 26168u, 26176u, 26198u, 26218u, 26222u, 26236u, 26246u, 26266u,
+ 26272u, 26276u, 26278u, 26288u, 26302u, 26306u, 26332u, 26338u,
+ 26374u, 26386u, 26404u, 26408u, 26416u, 26422u, 26426u, 26432u,
+ 26434u, 26462u, 26468u, 26474u, 26498u, 26506u, 26516u, 26542u,
+ 26548u, 26572u, 26576u, 26584u, 26608u, 26618u, 26638u, 26642u,
+ 26644u, 26654u, 26668u, 26684u, 26686u, 26692u, 26698u, 26702u,
+ 26708u, 26716u, 26734u, 26762u, 26776u, 26782u, 26798u, 26812u,
+ 26818u, 26822u, 26828u, 26834u, 26842u, 26846u, 26848u, 26852u,
+ 26864u, 26866u, 26878u, 26884u, 26896u, 26924u, 26926u, 26932u,
+ 26944u, 26954u, 26968u, 26972u, 27016u, 27022u, 27032u, 27034u,
+ 27046u, 27058u, 27088u, 27092u, 27104u, 27106u, 27112u, 27122u,
+ 27134u, 27136u, 27146u, 27148u, 27158u, 27164u, 27172u, 27182u,
+ 27188u, 27202u, 27218u, 27226u, 27232u, 27244u, 27254u, 27256u,
+ 27266u, 27274u, 27286u, 27296u, 27314u, 27322u, 27326u, 27328u,
+ 27332u, 27358u, 27364u, 27386u, 27392u, 27406u, 27416u, 27422u,
+ 27424u, 27452u, 27458u, 27466u, 27512u, 27518u, 27524u, 27542u,
+ 27548u, 27554u, 27562u, 27568u, 27578u, 27596u, 27598u, 27604u,
+ 27616u, 27634u, 27644u, 27652u, 27664u, 27694u, 27704u, 27706u,
+ 27716u, 27718u, 27722u, 27728u, 27746u, 27748u, 27752u, 27772u,
+ 27784u, 27788u, 27794u, 27802u, 27836u, 27842u, 27848u, 27872u,
+ 27884u, 27892u, 27928u, 27944u, 27946u, 27952u, 27956u, 27958u,
+ 27962u, 27968u, 27988u, 27994u, 28018u, 28022u, 28024u, 28028u,
+ 28046u, 28066u, 28072u, 28094u, 28102u, 28148u, 28166u, 28168u,
+ 28184u, 28204u, 28226u, 28228u, 28252u, 28274u, 28276u, 28292u,
+ 28316u, 28336u, 28352u, 28354u, 28358u, 28366u, 28376u, 28378u,
+ 28388u, 28402u, 28406u, 28414u, 28432u, 28436u, 28444u, 28448u,
+ 28462u, 28472u, 28474u, 28498u, 28514u, 28522u, 28528u, 28544u,
+ 28564u, 28574u, 28576u, 28582u, 28586u, 28616u, 28618u, 28634u,
+ 28666u, 28672u, 28684u, 28694u, 28718u, 28726u, 28738u, 28756u,
+ 28772u, 28774u, 28786u, 28792u, 28796u, 28808u, 28814u, 28816u,
+ 28844u, 28862u, 28864u, 28886u, 28892u, 28898u, 28904u, 28906u,
+ 28912u, 28928u, 28942u, 28948u, 28978u, 28994u, 28996u, 29006u,
+ 29008u, 29012u, 29024u, 29026u, 29038u, 29048u, 29062u, 29068u,
+ 29078u, 29086u, 29114u, 29116u, 29152u, 29158u, 29174u, 29188u,
+ 29192u, 29212u, 29236u, 29242u, 29246u, 29254u, 29258u, 29276u,
+ 29284u, 29288u, 29302u, 29306u, 29312u, 29314u, 29338u, 29354u,
+ 29368u, 29372u, 29398u, 29414u, 29416u, 29426u, 29458u, 29464u,
+ 29468u, 29474u, 29486u, 29492u, 29528u, 29536u, 29548u, 29552u,
+ 29554u, 29558u, 29566u, 29572u, 29576u, 29596u, 29608u, 29618u,
+ 29642u, 29654u, 29656u, 29668u, 29678u, 29684u, 29696u, 29698u,
+ 29704u, 29722u, 29726u, 29732u, 29738u, 29744u, 29752u, 29776u,
+ 29782u, 29792u, 29804u, 29834u, 29848u, 29858u, 29866u, 29878u,
+ 29884u, 29894u, 29906u, 29908u, 29926u, 29932u, 29936u, 29944u,
+ 29948u, 29972u, 29992u, 29996u, 30004u, 30014u, 30026u, 30034u,
+ 30046u, 30062u, 30068u, 30082u, 30086u, 30094u, 30098u, 30116u,
+ 30166u, 30172u, 30178u, 30182u, 30188u, 30196u, 30202u, 30212u,
+ 30238u, 30248u, 30254u, 30256u, 30266u, 30268u, 30278u, 30284u,
+ 30322u, 30334u, 30338u, 30346u, 30356u, 30376u, 30382u, 30388u,
+ 30394u, 30412u, 30422u, 30424u, 30436u, 30452u, 30454u, 30466u,
+ 30478u, 30482u, 30508u, 30518u, 30524u, 30544u, 30562u, 30602u,
+ 30614u, 30622u, 30632u, 30644u, 30646u, 30664u, 30676u, 30686u,
+ 30688u, 30698u, 30724u, 30728u, 30734u, 30746u, 30754u, 30758u,
+ 30788u, 30794u, 30796u, 30802u, 30818u, 30842u, 30866u, 30884u,
+ 30896u, 30908u, 30916u, 30922u, 30926u, 30934u, 30944u, 30952u,
+ 30958u, 30962u, 30982u, 30992u, 31018u, 31022u, 31046u, 31052u,
+ 31054u, 31066u, 31108u, 31126u, 31132u, 31136u, 31162u, 31168u,
+ 31196u, 31202u, 31204u, 31214u, 31222u, 31228u, 31234u, 31244u,
+ 31252u, 31262u, 31264u, 31286u, 31288u, 31292u, 31312u, 31316u,
+ 31322u, 31358u, 31372u, 31376u, 31396u, 31418u, 31424u, 31438u,
+ 31444u, 31454u, 31462u, 31466u, 31468u, 31472u, 31486u, 31504u,
+ 31538u, 31546u, 31568u, 31582u, 31592u, 31616u, 31622u, 31624u,
+ 31634u, 31636u, 31642u, 31652u, 31678u, 31696u, 31706u, 31724u,
+ 31748u, 31766u, 31768u, 31792u, 31832u, 31834u, 31838u, 31844u,
+ 31846u, 31852u, 31862u, 31888u, 31894u, 31906u, 31918u, 31924u,
+ 31928u, 31964u, 31966u, 31976u, 31988u, 32012u, 32014u, 32018u,
+ 32026u, 32036u, 32042u, 32044u, 32048u, 32072u, 32074u, 32078u,
+ 32114u, 32116u, 32138u, 32152u, 32176u, 32194u, 32236u, 32242u,
+ 32252u, 32254u, 32278u, 32294u, 32306u, 32308u, 32312u, 32314u,
+ 32324u, 32326u, 32336u, 32344u, 32348u, 32384u, 32392u, 32396u,
+ 32408u, 32426u, 32432u, 32438u, 32452u, 32474u, 32476u, 32482u,
+ 32506u, 32512u, 32522u, 32546u, 32566u, 32588u, 32594u, 32608u,
+ 32644u, 32672u, 32678u, 32686u, 32692u, 32716u, 32722u, 32734u,
+ 32762u, 32764u, 32782u, 32786u, 32788u, 32792u, 32812u, 32834u,
+ 32842u, 32852u, 32854u, 32872u, 32876u, 32884u, 32894u, 32908u,
+ 32918u, 32924u, 32932u, 32938u, 32944u, 32956u, 32972u, 32984u,
+ 32998u, 33008u, 33026u, 33028u, 33038u, 33062u, 33086u, 33092u,
+ 33104u, 33106u, 33128u, 33134u, 33154u, 33176u, 33178u, 33182u,
+ 33194u, 33196u, 33202u, 33238u, 33244u, 33266u, 33272u, 33274u,
+ 33302u, 33314u, 33332u, 33334u, 33338u, 33352u, 33358u, 33362u,
+ 33364u, 33374u, 33376u, 33392u, 33394u, 33404u, 33412u, 33418u,
+ 33428u, 33446u, 33458u, 33464u, 33478u, 33482u, 33488u, 33506u,
+ 33518u, 33544u, 33548u, 33554u, 33568u, 33574u, 33584u, 33596u,
+ 33598u, 33602u, 33604u, 33614u, 33638u, 33646u, 33656u, 33688u,
+ 33698u, 33706u, 33716u, 33722u, 33724u, 33742u, 33754u, 33782u,
+ 33812u, 33814u, 33832u, 33836u, 33842u, 33856u, 33862u, 33866u,
+ 33874u, 33896u, 33904u, 33934u, 33952u, 33962u, 33988u, 33992u,
+ 33994u, 34016u, 34024u, 34028u, 34036u, 34042u, 34046u, 34072u,
+ 34076u, 34088u, 34108u, 34126u, 34132u, 34144u, 34154u, 34172u,
+ 34174u, 34178u, 34184u, 34186u, 34198u, 34226u, 34232u, 34252u,
+ 34258u, 34274u, 34282u, 34288u, 34294u, 34298u, 34304u, 34324u,
+ 34336u, 34342u, 34346u, 34366u, 34372u, 34388u, 34394u, 34426u,
+ 34436u, 34454u, 34456u, 34468u, 34484u, 34508u, 34514u, 34522u,
+ 34534u, 34568u, 34574u, 34594u, 34616u, 34618u, 34634u, 34648u,
+ 34654u, 34658u, 34672u, 34678u, 34702u, 34732u, 34736u, 34744u,
+ 34756u, 34762u, 34778u, 34798u, 34808u, 34822u, 34826u, 34828u,
+ 34844u, 34856u, 34858u, 34868u, 34876u, 34882u, 34912u, 34924u,
+ 34934u, 34948u, 34958u, 34966u, 34976u, 34982u, 34984u, 34988u,
+ 35002u, 35012u, 35014u, 35024u, 35056u, 35074u, 35078u, 35086u,
+ 35114u, 35134u, 35138u, 35158u, 35164u, 35168u, 35198u, 35206u,
+ 35212u, 35234u, 35252u, 35264u, 35266u, 35276u, 35288u, 35294u,
+ 35312u, 35318u, 35372u, 35378u, 35392u, 35396u, 35402u, 35408u,
+ 35422u, 35446u, 35452u, 35464u, 35474u, 35486u, 35492u, 35516u,
+ 35528u, 35546u, 35554u, 35572u, 35576u, 35578u, 35582u, 35584u,
+ 35606u, 35614u, 35624u, 35626u, 35638u, 35648u, 35662u, 35668u,
+ 35672u, 35674u, 35686u, 35732u, 35738u, 35744u, 35746u, 35752u,
+ 35758u, 35788u, 35798u, 35806u, 35812u, 35824u, 35828u, 35842u,
+ 35848u, 35864u, 35876u, 35884u, 35894u, 35914u, 35932u, 35942u,
+ 35948u, 35954u, 35966u, 35968u, 35978u, 35992u, 35996u, 35998u,
+ 36002u, 36026u, 36038u, 36046u, 36064u, 36068u, 36076u, 36092u,
+ 36106u, 36118u, 36128u, 36146u, 36158u, 36166u, 36184u, 36188u,
+ 36202u, 36206u, 36212u, 36214u, 36236u, 36254u, 36262u, 36272u,
+ 36298u, 36302u, 36304u, 36328u, 36334u, 36338u, 36344u, 36356u,
+ 36382u, 36386u, 36394u, 36404u, 36422u, 36428u, 36442u, 36452u,
+ 36464u, 36466u, 36478u, 36484u, 36488u, 36496u, 36508u, 36524u,
+ 36526u, 36536u, 36542u, 36544u, 36566u, 36568u, 36572u, 36586u,
+ 36604u, 36614u, 36626u, 36646u, 36656u, 36662u, 36664u, 36668u,
+ 36682u, 36694u, 36698u, 36706u, 36716u, 36718u, 36724u, 36758u,
+ 36764u, 36766u, 36782u, 36794u, 36802u, 36824u, 36832u, 36862u,
+ 36872u, 36874u, 36898u, 36902u, 36916u, 36926u, 36946u, 36962u,
+ 36964u, 36968u, 36988u, 36998u, 37004u, 37012u, 37016u, 37024u,
+ 37028u, 37052u, 37058u, 37072u, 37076u, 37108u, 37112u, 37118u,
+ 37132u, 37138u, 37142u, 37144u, 37166u, 37226u, 37228u, 37234u,
+ 37258u, 37262u, 37276u, 37294u, 37306u, 37324u, 37336u, 37342u,
+ 37346u, 37376u, 37378u, 37394u, 37396u, 37418u, 37432u, 37448u,
+ 37466u, 37472u, 37508u, 37514u, 37532u, 37534u, 37544u, 37552u,
+ 37556u, 37558u, 37564u, 37588u, 37606u, 37636u, 37642u, 37648u,
+ 37682u, 37696u, 37702u, 37754u, 37756u, 37772u, 37784u, 37798u,
+ 37814u, 37822u, 37852u, 37856u, 37858u, 37864u, 37874u, 37886u,
+ 37888u, 37916u, 37922u, 37936u, 37948u, 37976u, 37994u, 38014u,
+ 38018u, 38026u, 38032u, 38038u, 38042u, 38048u, 38056u, 38078u,
+ 38084u, 38108u, 38116u, 38122u, 38134u, 38146u, 38152u, 38164u,
+ 38168u, 38188u, 38234u, 38252u, 38266u, 38276u, 38278u, 38302u,
+ 38306u, 38308u, 38332u, 38354u, 38368u, 38378u, 38384u, 38416u,
+ 38428u, 38432u, 38434u, 38444u, 38446u, 38456u, 38458u, 38462u,
+ 38468u, 38474u, 38486u, 38498u, 38512u, 38518u, 38524u, 38552u,
+ 38554u, 38572u, 38578u, 38584u, 38588u, 38612u, 38614u, 38626u,
+ 38638u, 38644u, 38648u, 38672u, 38696u, 38698u, 38704u, 38708u,
+ 38746u, 38752u, 38762u, 38774u, 38776u, 38788u, 38792u, 38812u,
+ 38834u, 38846u, 38848u, 38858u, 38864u, 38882u, 38924u, 38936u,
+ 38938u, 38944u, 38956u, 38978u, 38992u, 39002u, 39008u, 39014u,
+ 39016u, 39026u, 39044u, 39058u, 39062u, 39088u, 39104u, 39116u,
+ 39124u, 39142u, 39146u, 39148u, 39158u, 39166u, 39172u, 39176u,
+ 39182u, 39188u, 39194u
+ }};
+
+ if(n <= b1)
+ return a1[n];
+ if(n <= b2)
+ return a2[n - b1 - 1];
+ if(n >= b3)
+ {
+ return boost::math::policies::raise_domain_error<boost::uint32_t>(
+ "boost::math::prime<%1%>", "Argument n out of range: got %1%", n, pol);
+ }
+ return static_cast<boost::uint32_t>(a3[n - b2 - 1]) + 0xFFFFu;
+ }
+
+ inline boost::uint32_t prime(unsigned n)
+ {
+ return boost::math::prime(n, boost::math::policies::policy<>());
+ }
+
+ static const unsigned max_prime = 10000;
+
+}} // namespace boost and math
+
+#endif // BOOST_MATH_SF_PRIME_HPP
diff --git a/boost/math/special_functions/round.hpp b/boost/math/special_functions/round.hpp
new file mode 100644
index 0000000000..f11c6aeb1d
--- /dev/null
+++ b/boost/math/special_functions/round.hpp
@@ -0,0 +1,92 @@
+// Copyright John Maddock 2007.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_ROUND_HPP
+#define BOOST_MATH_ROUND_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+
+namespace boost{ namespace math{
+
+template <class T, class Policy>
+inline T round(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ if(!(boost::math::isfinite)(v))
+ return policies::raise_rounding_error("boost::math::round<%1%>(%1%)", 0, v, v, pol);
+ return v < 0 ? static_cast<T>(ceil(v - 0.5f)) : static_cast<T>(floor(v + 0.5f));
+}
+template <class T>
+inline T round(const T& v)
+{
+ return round(v, policies::policy<>());
+}
+//
+// The following functions will not compile unless T has an
+// implicit convertion to the integer types. For user-defined
+// number types this will likely not be the case. In that case
+// these functions should either be specialized for the UDT in
+// question, or else overloads should be placed in the same
+// namespace as the UDT: these will then be found via argument
+// dependent lookup. See our concept archetypes for examples.
+//
+template <class T, class Policy>
+inline int iround(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T r = boost::math::round(v, pol);
+ if((r > (std::numeric_limits<int>::max)()) || (r < (std::numeric_limits<int>::min)()))
+ return static_cast<int>(policies::raise_rounding_error("boost::math::iround<%1%>(%1%)", 0, v, 0, pol));
+ return static_cast<int>(r);
+}
+template <class T>
+inline int iround(const T& v)
+{
+ return iround(v, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline long lround(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T r = boost::math::round(v, pol);
+ if((r > (std::numeric_limits<long>::max)()) || (r < (std::numeric_limits<long>::min)()))
+ return static_cast<long int>(policies::raise_rounding_error("boost::math::lround<%1%>(%1%)", 0, v, 0L, pol));
+ return static_cast<long int>(r);
+}
+template <class T>
+inline long lround(const T& v)
+{
+ return lround(v, policies::policy<>());
+}
+
+#ifdef BOOST_HAS_LONG_LONG
+
+template <class T, class Policy>
+inline boost::long_long_type llround(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T r = boost::math::round(v, pol);
+ if((r > (std::numeric_limits<boost::long_long_type>::max)()) || (r < (std::numeric_limits<boost::long_long_type>::min)()))
+ return static_cast<boost::long_long_type>(policies::raise_rounding_error("boost::math::llround<%1%>(%1%)", 0, v, 0LL, pol));
+ return static_cast<boost::long_long_type>(r);
+}
+template <class T>
+inline boost::long_long_type llround(const T& v)
+{
+ return llround(v, policies::policy<>());
+}
+
+#endif
+
+}} // namespaces
+
+#endif // BOOST_MATH_ROUND_HPP
diff --git a/boost/math/special_functions/sign.hpp b/boost/math/special_functions/sign.hpp
new file mode 100644
index 0000000000..6de88b29a2
--- /dev/null
+++ b/boost/math/special_functions/sign.hpp
@@ -0,0 +1,145 @@
+// (C) Copyright John Maddock 2006.
+// (C) Copyright Johan Rade 2006.
+// (C) Copyright Paul A. Bristow 2011 (added changesign).
+
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_TOOLS_SIGN_HPP
+#define BOOST_MATH_TOOLS_SIGN_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/detail/fp_traits.hpp>
+
+namespace boost{ namespace math{
+
+namespace detail {
+
+ // signbit
+
+#ifdef BOOST_MATH_USE_STD_FPCLASSIFY
+ template<class T>
+ inline int signbit_impl(T x, native_tag const&)
+ {
+ return (std::signbit)(x);
+ }
+#endif
+
+ template<class T>
+ inline int signbit_impl(T x, generic_tag<true> const&)
+ {
+ return x < 0;
+ }
+
+ template<class T>
+ inline int signbit_impl(T x, generic_tag<false> const&)
+ {
+ return x < 0;
+ }
+
+ template<class T>
+ inline int signbit_impl(T x, ieee_copy_all_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ return a & traits::sign ? 1 : 0;
+ }
+
+ template<class T>
+ inline int signbit_impl(T x, ieee_copy_leading_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+
+ return a & traits::sign ? 1 : 0;
+ }
+
+ // Changesign
+
+ template<class T>
+ inline T (changesign_impl)(T x, generic_tag<true> const&)
+ {
+ return -x;
+ }
+
+ template<class T>
+ inline T (changesign_impl)(T x, generic_tag<false> const&)
+ {
+ return -x;
+ }
+
+
+ template<class T>
+ inline T changesign_impl(T x, ieee_copy_all_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::sign_change_type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a ^= traits::sign;
+ traits::set_bits(x,a);
+ return x;
+ }
+
+ template<class T>
+ inline T (changesign_impl)(T x, ieee_copy_leading_bits_tag const&)
+ {
+ typedef BOOST_DEDUCED_TYPENAME fp_traits<T>::sign_change_type traits;
+
+ BOOST_DEDUCED_TYPENAME traits::bits a;
+ traits::get_bits(x,a);
+ a ^= traits::sign;
+ traits::set_bits(x,a);
+ return x;
+ }
+
+
+} // namespace detail
+
+template<class T> int (signbit)(T x)
+{
+ typedef typename detail::fp_traits<T>::type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+ return detail::signbit_impl(x, method());
+}
+
+template <class T>
+inline int sign BOOST_NO_MACRO_EXPAND(const T& z)
+{
+ return (z == 0) ? 0 : (boost::math::signbit)(z) ? -1 : 1;
+}
+
+template<class T> T (changesign)(const T& x)
+{ //!< \brief return unchanged binary pattern of x, except for change of sign bit.
+ typedef typename detail::fp_traits<T>::sign_change_type traits;
+ typedef typename traits::method method;
+ typedef typename boost::is_floating_point<T>::type fp_tag;
+
+ return detail::changesign_impl(x, method());
+}
+
+template <class T>
+inline T copysign BOOST_NO_MACRO_EXPAND(const T& x, const T& y)
+{
+ BOOST_MATH_STD_USING
+ return (boost::math::signbit)(x) != (boost::math::signbit)(y) ? (boost::math::changesign)(x) : x;
+}
+
+} // namespace math
+} // namespace boost
+
+
+#endif // BOOST_MATH_TOOLS_SIGN_HPP
+
+
diff --git a/boost/math/special_functions/sin_pi.hpp b/boost/math/special_functions/sin_pi.hpp
new file mode 100644
index 0000000000..38c02bc99e
--- /dev/null
+++ b/boost/math/special_functions/sin_pi.hpp
@@ -0,0 +1,70 @@
+// Copyright (c) 2007 John Maddock
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SIN_PI_HPP
+#define BOOST_MATH_SIN_PI_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/special_functions/trunc.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/math/constants/constants.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+template <class T, class Policy>
+T sin_pi_imp(T x, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ if(x < 0)
+ return -sin_pi(-x);
+ // sin of pi*x:
+ bool invert;
+ if(x < 0.5)
+ return sin(constants::pi<T>() * x);
+ if(x < 1)
+ {
+ invert = true;
+ x = -x;
+ }
+ else
+ invert = false;
+
+ T rem = floor(x);
+ if(itrunc(rem, pol) & 1)
+ invert = !invert;
+ rem = x - rem;
+ if(rem > 0.5f)
+ rem = 1 - rem;
+ if(rem == 0.5f)
+ return static_cast<T>(invert ? -1 : 1);
+
+ rem = sin(constants::pi<T>() * rem);
+ return invert ? T(-rem) : rem;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type sin_pi(T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ return boost::math::detail::sin_pi_imp<result_type>(x, pol);
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type sin_pi(T x)
+{
+ return boost::math::sin_pi(x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+#endif
+
diff --git a/boost/math/special_functions/sinc.hpp b/boost/math/special_functions/sinc.hpp
new file mode 100644
index 0000000000..ffb19d8b99
--- /dev/null
+++ b/boost/math/special_functions/sinc.hpp
@@ -0,0 +1,177 @@
+// boost sinc.hpp header file
+
+// (C) Copyright Hubert Holin 2001.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for updates, documentation, and revision history.
+
+#ifndef BOOST_SINC_HPP
+#define BOOST_SINC_HPP
+
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/policies/policy.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/limits.hpp>
+#include <string>
+#include <stdexcept>
+
+
+#include <boost/config.hpp>
+
+
+// These are the the "Sinus Cardinal" functions.
+
+namespace boost
+{
+ namespace math
+ {
+ namespace detail
+ {
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ // gcc 2.x ignores function scope using declarations,
+ // put them in the scope of the enclosing namespace instead:
+
+ using ::std::abs;
+ using ::std::sqrt;
+ using ::std::sin;
+
+ using ::std::numeric_limits;
+#endif /* defined(__GNUC__) && (__GNUC__ < 3) */
+
+ // This is the "Sinus Cardinal" of index Pi.
+
+ template<typename T>
+ inline T sinc_pi_imp(const T x)
+ {
+#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
+ using ::abs;
+ using ::sin;
+ using ::sqrt;
+#else /* BOOST_NO_STDC_NAMESPACE */
+ using ::std::abs;
+ using ::std::sin;
+ using ::std::sqrt;
+#endif /* BOOST_NO_STDC_NAMESPACE */
+
+ // Note: this code is *not* thread safe!
+ static T const taylor_0_bound = tools::epsilon<T>();
+ static T const taylor_2_bound = sqrt(taylor_0_bound);
+ static T const taylor_n_bound = sqrt(taylor_2_bound);
+
+ if (abs(x) >= taylor_n_bound)
+ {
+ return(sin(x)/x);
+ }
+ else
+ {
+ // approximation by taylor series in x at 0 up to order 0
+ T result = static_cast<T>(1);
+
+ if (abs(x) >= taylor_0_bound)
+ {
+ T x2 = x*x;
+
+ // approximation by taylor series in x at 0 up to order 2
+ result -= x2/static_cast<T>(6);
+
+ if (abs(x) >= taylor_2_bound)
+ {
+ // approximation by taylor series in x at 0 up to order 4
+ result += (x2*x2)/static_cast<T>(120);
+ }
+ }
+
+ return(result);
+ }
+ }
+
+ } // namespace detail
+
+ template <class T>
+ inline typename tools::promote_args<T>::type sinc_pi(T x)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::sinc_pi_imp(static_cast<result_type>(x));
+ }
+
+ template <class T, class Policy>
+ inline typename tools::promote_args<T>::type sinc_pi(T x, const Policy&)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::sinc_pi_imp(static_cast<result_type>(x));
+ }
+
+#ifdef BOOST_NO_TEMPLATE_TEMPLATES
+#else /* BOOST_NO_TEMPLATE_TEMPLATES */
+ template<typename T, template<typename> class U>
+ inline U<T> sinc_pi(const U<T> x)
+ {
+#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL) || defined(__GNUC__)
+ using namespace std;
+#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
+ using ::abs;
+ using ::sin;
+ using ::sqrt;
+#else /* BOOST_NO_STDC_NAMESPACE */
+ using ::std::abs;
+ using ::std::sin;
+ using ::std::sqrt;
+#endif /* BOOST_NO_STDC_NAMESPACE */
+
+ using ::std::numeric_limits;
+
+ static T const taylor_0_bound = tools::epsilon<T>();
+ static T const taylor_2_bound = sqrt(taylor_0_bound);
+ static T const taylor_n_bound = sqrt(taylor_2_bound);
+
+ if (abs(x) >= taylor_n_bound)
+ {
+ return(sin(x)/x);
+ }
+ else
+ {
+ // approximation by taylor series in x at 0 up to order 0
+#ifdef __MWERKS__
+ U<T> result = static_cast<U<T> >(1);
+#else
+ U<T> result = U<T>(1);
+#endif
+
+ if (abs(x) >= taylor_0_bound)
+ {
+ U<T> x2 = x*x;
+
+ // approximation by taylor series in x at 0 up to order 2
+ result -= x2/static_cast<T>(6);
+
+ if (abs(x) >= taylor_2_bound)
+ {
+ // approximation by taylor series in x at 0 up to order 4
+ result += (x2*x2)/static_cast<T>(120);
+ }
+ }
+
+ return(result);
+ }
+ }
+
+ template<typename T, template<typename> class U, class Policy>
+ inline U<T> sinc_pi(const U<T> x, const Policy&)
+ {
+ return sinc_pi(x);
+ }
+#endif /* BOOST_NO_TEMPLATE_TEMPLATES */
+ }
+}
+
+#endif /* BOOST_SINC_HPP */
+
diff --git a/boost/math/special_functions/sinhc.hpp b/boost/math/special_functions/sinhc.hpp
new file mode 100644
index 0000000000..d19a4b71c6
--- /dev/null
+++ b/boost/math/special_functions/sinhc.hpp
@@ -0,0 +1,167 @@
+// boost sinhc.hpp header file
+
+// (C) Copyright Hubert Holin 2001.
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// See http://www.boost.org for updates, documentation, and revision history.
+
+#ifndef BOOST_SINHC_HPP
+#define BOOST_SINHC_HPP
+
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/config/no_tr1/cmath.hpp>
+#include <boost/limits.hpp>
+#include <string>
+#include <stdexcept>
+
+#include <boost/config.hpp>
+
+
+// These are the the "Hyperbolic Sinus Cardinal" functions.
+
+namespace boost
+{
+ namespace math
+ {
+ namespace detail
+ {
+#if defined(__GNUC__) && (__GNUC__ < 3)
+ // gcc 2.x ignores function scope using declarations,
+ // put them in the scope of the enclosing namespace instead:
+
+ using ::std::abs;
+ using ::std::sqrt;
+ using ::std::sinh;
+
+ using ::std::numeric_limits;
+#endif /* defined(__GNUC__) && (__GNUC__ < 3) */
+
+ // This is the "Hyperbolic Sinus Cardinal" of index Pi.
+
+ template<typename T>
+ inline T sinhc_pi_imp(const T x)
+ {
+#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
+ using ::abs;
+ using ::sinh;
+ using ::sqrt;
+#else /* BOOST_NO_STDC_NAMESPACE */
+ using ::std::abs;
+ using ::std::sinh;
+ using ::std::sqrt;
+#endif /* BOOST_NO_STDC_NAMESPACE */
+
+ static T const taylor_0_bound = tools::epsilon<T>();
+ static T const taylor_2_bound = sqrt(taylor_0_bound);
+ static T const taylor_n_bound = sqrt(taylor_2_bound);
+
+ if (abs(x) >= taylor_n_bound)
+ {
+ return(sinh(x)/x);
+ }
+ else
+ {
+ // approximation by taylor series in x at 0 up to order 0
+ T result = static_cast<T>(1);
+
+ if (abs(x) >= taylor_0_bound)
+ {
+ T x2 = x*x;
+
+ // approximation by taylor series in x at 0 up to order 2
+ result += x2/static_cast<T>(6);
+
+ if (abs(x) >= taylor_2_bound)
+ {
+ // approximation by taylor series in x at 0 up to order 4
+ result += (x2*x2)/static_cast<T>(120);
+ }
+ }
+
+ return(result);
+ }
+ }
+
+ } // namespace detail
+
+ template <class T>
+ inline typename tools::promote_args<T>::type sinhc_pi(T x)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::sinhc_pi_imp(static_cast<result_type>(x));
+ }
+
+ template <class T, class Policy>
+ inline typename tools::promote_args<T>::type sinhc_pi(T x, const Policy&)
+ {
+ return boost::math::sinhc_pi(x);
+ }
+
+#ifdef BOOST_NO_TEMPLATE_TEMPLATES
+#else /* BOOST_NO_TEMPLATE_TEMPLATES */
+ template<typename T, template<typename> class U>
+ inline U<T> sinhc_pi(const U<T> x)
+ {
+#if defined(BOOST_FUNCTION_SCOPE_USING_DECLARATION_BREAKS_ADL) || defined(__GNUC__)
+ using namespace std;
+#elif defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
+ using ::abs;
+ using ::sinh;
+ using ::sqrt;
+#else /* BOOST_NO_STDC_NAMESPACE */
+ using ::std::abs;
+ using ::std::sinh;
+ using ::std::sqrt;
+#endif /* BOOST_NO_STDC_NAMESPACE */
+
+ using ::std::numeric_limits;
+
+ static T const taylor_0_bound = tools::epsilon<T>();
+ static T const taylor_2_bound = sqrt(taylor_0_bound);
+ static T const taylor_n_bound = sqrt(taylor_2_bound);
+
+ if (abs(x) >= taylor_n_bound)
+ {
+ return(sinh(x)/x);
+ }
+ else
+ {
+ // approximation by taylor series in x at 0 up to order 0
+#ifdef __MWERKS__
+ U<T> result = static_cast<U<T> >(1);
+#else
+ U<T> result = U<T>(1);
+#endif
+
+ if (abs(x) >= taylor_0_bound)
+ {
+ U<T> x2 = x*x;
+
+ // approximation by taylor series in x at 0 up to order 2
+ result += x2/static_cast<T>(6);
+
+ if (abs(x) >= taylor_2_bound)
+ {
+ // approximation by taylor series in x at 0 up to order 4
+ result += (x2*x2)/static_cast<T>(120);
+ }
+ }
+
+ return(result);
+ }
+ }
+#endif /* BOOST_NO_TEMPLATE_TEMPLATES */
+ }
+}
+
+#endif /* BOOST_SINHC_HPP */
+
diff --git a/boost/math/special_functions/spherical_harmonic.hpp b/boost/math/special_functions/spherical_harmonic.hpp
new file mode 100644
index 0000000000..33b2574480
--- /dev/null
+++ b/boost/math/special_functions/spherical_harmonic.hpp
@@ -0,0 +1,204 @@
+
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
+#define BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/legendre.hpp>
+#include <boost/math/tools/workaround.hpp>
+#include <complex>
+
+namespace boost{
+namespace math{
+
+namespace detail{
+
+//
+// Calculates the prefix term that's common to the real
+// and imaginary parts. Does *not* fix up the sign of the result
+// though.
+//
+template <class T, class Policy>
+inline T spherical_harmonic_prefix(unsigned n, unsigned m, T theta, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ if(m > n)
+ return 0;
+
+ T sin_theta = sin(theta);
+ T x = cos(theta);
+
+ T leg = detail::legendre_p_imp(n, m, x, static_cast<T>(pow(fabs(sin_theta), T(m))), pol);
+
+ T prefix = boost::math::tgamma_delta_ratio(static_cast<T>(n - m + 1), static_cast<T>(2 * m), pol);
+ prefix *= (2 * n + 1) / (4 * constants::pi<T>());
+ prefix = sqrt(prefix);
+ return prefix * leg;
+}
+//
+// Real Part:
+//
+template <class T, class Policy>
+T spherical_harmonic_r(unsigned n, int m, T theta, T phi, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std functions
+
+ bool sign = false;
+ if(m < 0)
+ {
+ // Reflect and adjust sign if m < 0:
+ sign = m&1;
+ m = abs(m);
+ }
+ if(m&1)
+ {
+ // Check phase if theta is outside [0, PI]:
+ T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
+ if(mod < 0)
+ mod += 2 * constants::pi<T>();
+ if(mod > constants::pi<T>())
+ sign = !sign;
+ }
+ // Get the value and adjust sign as required:
+ T prefix = spherical_harmonic_prefix(n, m, theta, pol);
+ prefix *= cos(m * phi);
+ return sign ? T(-prefix) : prefix;
+}
+
+template <class T, class Policy>
+T spherical_harmonic_i(unsigned n, int m, T theta, T phi, const Policy& pol)
+{
+ BOOST_MATH_STD_USING // ADL of std functions
+
+ bool sign = false;
+ if(m < 0)
+ {
+ // Reflect and adjust sign if m < 0:
+ sign = !(m&1);
+ m = abs(m);
+ }
+ if(m&1)
+ {
+ // Check phase if theta is outside [0, PI]:
+ T mod = boost::math::tools::fmod_workaround(theta, T(2 * constants::pi<T>()));
+ if(mod < 0)
+ mod += 2 * constants::pi<T>();
+ if(mod > constants::pi<T>())
+ sign = !sign;
+ }
+ // Get the value and adjust sign as required:
+ T prefix = spherical_harmonic_prefix(n, m, theta, pol);
+ prefix *= sin(m * phi);
+ return sign ? T(-prefix) : prefix;
+}
+
+template <class T, class U, class Policy>
+std::complex<T> spherical_harmonic(unsigned n, int m, U theta, U phi, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ //
+ // Sort out the signs:
+ //
+ bool r_sign = false;
+ bool i_sign = false;
+ if(m < 0)
+ {
+ // Reflect and adjust sign if m < 0:
+ r_sign = m&1;
+ i_sign = !(m&1);
+ m = abs(m);
+ }
+ if(m&1)
+ {
+ // Check phase if theta is outside [0, PI]:
+ U mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi<U>());
+ if(mod < 0)
+ mod += 2 * constants::pi<U>();
+ if(mod > constants::pi<U>())
+ {
+ r_sign = !r_sign;
+ i_sign = !i_sign;
+ }
+ }
+ //
+ // Calculate the value:
+ //
+ U prefix = spherical_harmonic_prefix(n, m, theta, pol);
+ U r = prefix * cos(m * phi);
+ U i = prefix * sin(m * phi);
+ //
+ // Add in the signs:
+ //
+ if(r_sign)
+ r = -r;
+ if(i_sign)
+ i = -i;
+ static const char* function = "boost::math::spherical_harmonic<%1%>(int, int, %1%, %1%)";
+ return std::complex<T>(policies::checked_narrowing_cast<T, Policy>(r, function), policies::checked_narrowing_cast<T, Policy>(i, function));
+}
+
+} // namespace detail
+
+template <class T1, class T2, class Policy>
+inline std::complex<typename tools::promote_args<T1, T2>::type>
+ spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return detail::spherical_harmonic<result_type, value_type>(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol);
+}
+
+template <class T1, class T2>
+inline std::complex<typename tools::promote_args<T1, T2>::type>
+ spherical_harmonic(unsigned n, int m, T1 theta, T2 phi)
+{
+ return boost::math::spherical_harmonic(n, m, theta, phi, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_r(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "bost::math::spherical_harmonic_r<%1%>(unsigned, int, %1%, %1%)");
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi)
+{
+ return boost::math::spherical_harmonic_r(n, m, theta, phi, policies::policy<>());
+}
+
+template <class T1, class T2, class Policy>
+inline typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
+{
+ typedef typename tools::promote_args<T1, T2>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_i(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "boost::math::spherical_harmonic_i<%1%>(unsigned, int, %1%, %1%)");
+}
+
+template <class T1, class T2>
+inline typename tools::promote_args<T1, T2>::type
+ spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi)
+{
+ return boost::math::spherical_harmonic_i(n, m, theta, phi, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
+
+
+
diff --git a/boost/math/special_functions/sqrt1pm1.hpp b/boost/math/special_functions/sqrt1pm1.hpp
new file mode 100644
index 0000000000..ad0203e722
--- /dev/null
+++ b/boost/math/special_functions/sqrt1pm1.hpp
@@ -0,0 +1,48 @@
+// (C) Copyright John Maddock 2006.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_SQRT1PM1
+#define BOOST_MATH_SQRT1PM1
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/special_functions/log1p.hpp>
+#include <boost/math/special_functions/expm1.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+
+//
+// This algorithm computes sqrt(1+x)-1 for small x:
+//
+
+namespace boost{ namespace math{
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type sqrt1pm1(const T& val, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ BOOST_MATH_STD_USING
+
+ if(fabs(result_type(val)) > 0.75)
+ return sqrt(1 + result_type(val)) - 1;
+ return boost::math::expm1(boost::math::log1p(val, pol) / 2, pol);
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type sqrt1pm1(const T& val)
+{
+ return sqrt1pm1(val, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SQRT1PM1
+
+
+
+
+
diff --git a/boost/math/special_functions/trunc.hpp b/boost/math/special_functions/trunc.hpp
new file mode 100644
index 0000000000..520ae89f5d
--- /dev/null
+++ b/boost/math/special_functions/trunc.hpp
@@ -0,0 +1,92 @@
+// Copyright John Maddock 2007.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_TRUNC_HPP
+#define BOOST_MATH_TRUNC_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/config.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+
+namespace boost{ namespace math{
+
+template <class T, class Policy>
+inline T trunc(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ if(!(boost::math::isfinite)(v))
+ return policies::raise_rounding_error("boost::math::trunc<%1%>(%1%)", 0, v, v, pol);
+ return (v >= 0) ? static_cast<T>(floor(v)) : static_cast<T>(ceil(v));
+}
+template <class T>
+inline T trunc(const T& v)
+{
+ return trunc(v, policies::policy<>());
+}
+//
+// The following functions will not compile unless T has an
+// implicit convertion to the integer types. For user-defined
+// number types this will likely not be the case. In that case
+// these functions should either be specialized for the UDT in
+// question, or else overloads should be placed in the same
+// namespace as the UDT: these will then be found via argument
+// dependent lookup. See our concept archetypes for examples.
+//
+template <class T, class Policy>
+inline int itrunc(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T r = boost::math::trunc(v, pol);
+ if((r > (std::numeric_limits<int>::max)()) || (r < (std::numeric_limits<int>::min)()))
+ return static_cast<int>(policies::raise_rounding_error("boost::math::itrunc<%1%>(%1%)", 0, v, 0, pol));
+ return static_cast<int>(r);
+}
+template <class T>
+inline int itrunc(const T& v)
+{
+ return itrunc(v, policies::policy<>());
+}
+
+template <class T, class Policy>
+inline long ltrunc(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T r = boost::math::trunc(v, pol);
+ if((r > (std::numeric_limits<long>::max)()) || (r < (std::numeric_limits<long>::min)()))
+ return static_cast<long>(policies::raise_rounding_error("boost::math::ltrunc<%1%>(%1%)", 0, v, 0L, pol));
+ return static_cast<long>(r);
+}
+template <class T>
+inline long ltrunc(const T& v)
+{
+ return ltrunc(v, policies::policy<>());
+}
+
+#ifdef BOOST_HAS_LONG_LONG
+
+template <class T, class Policy>
+inline boost::long_long_type lltrunc(const T& v, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+ T r = boost::math::trunc(v, pol);
+ if((r > (std::numeric_limits<boost::long_long_type>::max)()) || (r < (std::numeric_limits<boost::long_long_type>::min)()))
+ return static_cast<boost::long_long_type>(policies::raise_rounding_error("boost::math::lltrunc<%1%>(%1%)", 0, v, 0LL, pol));
+ return static_cast<boost::long_long_type>(r);
+}
+template <class T>
+inline boost::long_long_type lltrunc(const T& v)
+{
+ return lltrunc(v, policies::policy<>());
+}
+
+#endif
+
+}} // namespaces
+
+#endif // BOOST_MATH_TRUNC_HPP
diff --git a/boost/math/special_functions/zeta.hpp b/boost/math/special_functions/zeta.hpp
new file mode 100644
index 0000000000..4ed5f6a705
--- /dev/null
+++ b/boost/math/special_functions/zeta.hpp
@@ -0,0 +1,950 @@
+// Copyright John Maddock 2007.
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_ZETA_HPP
+#define BOOST_MATH_ZETA_HPP
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/tools/series.hpp>
+#include <boost/math/tools/big_constant.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/special_functions/gamma.hpp>
+#include <boost/math/special_functions/sin_pi.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+#if 0
+//
+// This code is commented out because we have a better more rapidly converging series
+// now. Retained for future reference and in case the new code causes any issues down the line....
+//
+
+template <class T, class Policy>
+struct zeta_series_cache_size
+{
+ //
+ // Work how large to make our cache size when evaluating the series
+ // evaluation: normally this is just large enough for the series
+ // to have converged, but for arbitrary precision types we need a
+ // really large cache to achieve reasonable precision in a reasonable
+ // time. This is important when constructing rational approximations
+ // to zeta for example.
+ //
+ typedef typename boost::math::policies::precision<T,Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<5000>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<70>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<100>,
+ mpl::int_<5000>
+ >::type
+ >::type
+ >::type type;
+};
+
+template <class T, class Policy>
+T zeta_series_imp(T s, T sc, const Policy&)
+{
+ //
+ // Series evaluation from:
+ // Havil, J. Gamma: Exploring Euler's Constant.
+ // Princeton, NJ: Princeton University Press, 2003.
+ //
+ // See also http://mathworld.wolfram.com/RiemannZetaFunction.html
+ //
+ BOOST_MATH_STD_USING
+ T sum = 0;
+ T mult = 0.5;
+ T change;
+ typedef typename zeta_series_cache_size<T,Policy>::type cache_size;
+ T powers[cache_size::value] = { 0, };
+ unsigned n = 0;
+ do{
+ T binom = -static_cast<T>(n);
+ T nested_sum = 1;
+ if(n < sizeof(powers) / sizeof(powers[0]))
+ powers[n] = pow(static_cast<T>(n + 1), -s);
+ for(unsigned k = 1; k <= n; ++k)
+ {
+ T p;
+ if(k < sizeof(powers) / sizeof(powers[0]))
+ {
+ p = powers[k];
+ //p = pow(k + 1, -s);
+ }
+ else
+ p = pow(static_cast<T>(k + 1), -s);
+ nested_sum += binom * p;
+ binom *= (k - static_cast<T>(n)) / (k + 1);
+ }
+ change = mult * nested_sum;
+ sum += change;
+ mult /= 2;
+ ++n;
+ }while(fabs(change / sum) > tools::epsilon<T>());
+
+ return sum * 1 / -boost::math::powm1(T(2), sc);
+}
+
+//
+// Classical p-series:
+//
+template <class T>
+struct zeta_series2
+{
+ typedef T result_type;
+ zeta_series2(T _s) : s(-_s), k(1){}
+ T operator()()
+ {
+ BOOST_MATH_STD_USING
+ return pow(static_cast<T>(k++), s);
+ }
+private:
+ T s;
+ unsigned k;
+};
+
+template <class T, class Policy>
+inline T zeta_series2_imp(T s, const Policy& pol)
+{
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();;
+ zeta_series2<T> f(s);
+ T result = tools::sum_series(
+ f,
+ policies::get_epsilon<T, Policy>(),
+ max_iter);
+ policies::check_series_iterations<T>("boost::math::zeta_series2<%1%>(%1%)", max_iter, pol);
+ return result;
+}
+#endif
+
+template <class T, class Policy>
+T zeta_polynomial_series(T s, T sc, Policy const &)
+{
+ //
+ // This is algorithm 3 from:
+ //
+ // "An Efficient Algorithm for the Riemann Zeta Function", P. Borwein,
+ // Canadian Mathematical Society, Conference Proceedings.
+ // See: http://www.cecm.sfu.ca/personal/pborwein/PAPERS/P155.pdf
+ //
+ BOOST_MATH_STD_USING
+ int n = itrunc(T(log(boost::math::tools::epsilon<T>()) / -2));
+ T sum = 0;
+ T two_n = ldexp(T(1), n);
+ int ej_sign = 1;
+ for(int j = 0; j < n; ++j)
+ {
+ sum += ej_sign * -two_n / pow(T(j + 1), s);
+ ej_sign = -ej_sign;
+ }
+ T ej_sum = 1;
+ T ej_term = 1;
+ for(int j = n; j <= 2 * n - 1; ++j)
+ {
+ sum += ej_sign * (ej_sum - two_n) / pow(T(j + 1), s);
+ ej_sign = -ej_sign;
+ ej_term *= 2 * n - j;
+ ej_term /= j - n + 1;
+ ej_sum += ej_term;
+ }
+ return -sum / (two_n * (-powm1(T(2), sc)));
+}
+
+template <class T, class Policy>
+T zeta_imp_prec(T s, T sc, const Policy& pol, const mpl::int_<0>&)
+{
+ BOOST_MATH_STD_USING
+ T result;
+ result = zeta_polynomial_series(s, sc, pol);
+#if 0
+ // Old code archived for future reference:
+
+ //
+ // Only use power series if it will converge in 100
+ // iterations or less: the more iterations it consumes
+ // the slower convergence becomes so we have to be very
+ // careful in it's usage.
+ //
+ if (s > -log(tools::epsilon<T>()) / 4.5)
+ result = detail::zeta_series2_imp(s, pol);
+ else
+ result = detail::zeta_series_imp(s, sc, pol);
+#endif
+ return result;
+}
+
+template <class T, class Policy>
+inline T zeta_imp_prec(T s, T sc, const Policy&, const mpl::int_<53>&)
+{
+ BOOST_MATH_STD_USING
+ T result;
+ if(s < 1)
+ {
+ // Rational Approximation
+ // Maximum Deviation Found: 2.020e-18
+ // Expected Error Term: -2.020e-18
+ // Max error found at double precision: 3.994987e-17
+ static const T P[6] = {
+ 0.24339294433593750202L,
+ -0.49092470516353571651L,
+ 0.0557616214776046784287L,
+ -0.00320912498879085894856L,
+ 0.000451534528645796438704L,
+ -0.933241270357061460782e-5L,
+ };
+ static const T Q[6] = {
+ 1L,
+ -0.279960334310344432495L,
+ 0.0419676223309986037706L,
+ -0.00413421406552171059003L,
+ 0.00024978985622317935355L,
+ -0.101855788418564031874e-4L,
+ };
+ result = tools::evaluate_polynomial(P, sc) / tools::evaluate_polynomial(Q, sc);
+ result -= 1.2433929443359375F;
+ result += (sc);
+ result /= (sc);
+ }
+ else if(s <= 2)
+ {
+ // Maximum Deviation Found: 9.007e-20
+ // Expected Error Term: 9.007e-20
+ static const T P[6] = {
+ 0.577215664901532860516,
+ 0.243210646940107164097,
+ 0.0417364673988216497593,
+ 0.00390252087072843288378,
+ 0.000249606367151877175456,
+ 0.110108440976732897969e-4,
+ };
+ static const T Q[6] = {
+ 1,
+ 0.295201277126631761737,
+ 0.043460910607305495864,
+ 0.00434930582085826330659,
+ 0.000255784226140488490982,
+ 0.10991819782396112081e-4,
+ };
+ result = tools::evaluate_polynomial(P, T(-sc)) / tools::evaluate_polynomial(Q, T(-sc));
+ result += 1 / (-sc);
+ }
+ else if(s <= 4)
+ {
+ // Maximum Deviation Found: 5.946e-22
+ // Expected Error Term: -5.946e-22
+ static const float Y = 0.6986598968505859375;
+ static const T P[6] = {
+ -0.0537258300023595030676,
+ 0.0445163473292365591906,
+ 0.0128677673534519952905,
+ 0.00097541770457391752726,
+ 0.769875101573654070925e-4,
+ 0.328032510000383084155e-5,
+ };
+ static const T Q[7] = {
+ 1,
+ 0.33383194553034051422,
+ 0.0487798431291407621462,
+ 0.00479039708573558490716,
+ 0.000270776703956336357707,
+ 0.106951867532057341359e-4,
+ 0.236276623974978646399e-7,
+ };
+ result = tools::evaluate_polynomial(P, T(s - 2)) / tools::evaluate_polynomial(Q, T(s - 2));
+ result += Y + 1 / (-sc);
+ }
+ else if(s <= 7)
+ {
+ // Maximum Deviation Found: 2.955e-17
+ // Expected Error Term: 2.955e-17
+ // Max error found at double precision: 2.009135e-16
+
+ static const T P[6] = {
+ -2.49710190602259410021,
+ -2.60013301809475665334,
+ -0.939260435377109939261,
+ -0.138448617995741530935,
+ -0.00701721240549802377623,
+ -0.229257310594893932383e-4,
+ };
+ static const T Q[9] = {
+ 1,
+ 0.706039025937745133628,
+ 0.15739599649558626358,
+ 0.0106117950976845084417,
+ -0.36910273311764618902e-4,
+ 0.493409563927590008943e-5,
+ -0.234055487025287216506e-6,
+ 0.718833729365459760664e-8,
+ -0.1129200113474947419e-9,
+ };
+ result = tools::evaluate_polynomial(P, T(s - 4)) / tools::evaluate_polynomial(Q, T(s - 4));
+ result = 1 + exp(result);
+ }
+ else if(s < 15)
+ {
+ // Maximum Deviation Found: 7.117e-16
+ // Expected Error Term: 7.117e-16
+ // Max error found at double precision: 9.387771e-16
+ static const T P[7] = {
+ -4.78558028495135619286,
+ -1.89197364881972536382,
+ -0.211407134874412820099,
+ -0.000189204758260076688518,
+ 0.00115140923889178742086,
+ 0.639949204213164496988e-4,
+ 0.139348932445324888343e-5,
+ };
+ static const T Q[9] = {
+ 1,
+ 0.244345337378188557777,
+ 0.00873370754492288653669,
+ -0.00117592765334434471562,
+ -0.743743682899933180415e-4,
+ -0.21750464515767984778e-5,
+ 0.471001264003076486547e-8,
+ -0.833378440625385520576e-10,
+ 0.699841545204845636531e-12,
+ };
+ result = tools::evaluate_polynomial(P, T(s - 7)) / tools::evaluate_polynomial(Q, T(s - 7));
+ result = 1 + exp(result);
+ }
+ else if(s < 36)
+ {
+ // Max error in interpolated form: 1.668e-17
+ // Max error found at long double precision: 1.669714e-17
+ static const T P[8] = {
+ -10.3948950573308896825,
+ -2.85827219671106697179,
+ -0.347728266539245787271,
+ -0.0251156064655346341766,
+ -0.00119459173416968685689,
+ -0.382529323507967522614e-4,
+ -0.785523633796723466968e-6,
+ -0.821465709095465524192e-8,
+ };
+ static const T Q[10] = {
+ 1,
+ 0.208196333572671890965,
+ 0.0195687657317205033485,
+ 0.00111079638102485921877,
+ 0.408507746266039256231e-4,
+ 0.955561123065693483991e-6,
+ 0.118507153474022900583e-7,
+ 0.222609483627352615142e-14,
+ };
+ result = tools::evaluate_polynomial(P, T(s - 15)) / tools::evaluate_polynomial(Q, T(s - 15));
+ result = 1 + exp(result);
+ }
+ else if(s < 56)
+ {
+ result = 1 + pow(T(2), -s);
+ }
+ else
+ {
+ result = 1;
+ }
+ return result;
+}
+
+template <class T, class Policy>
+T zeta_imp_prec(T s, T sc, const Policy&, const mpl::int_<64>&)
+{
+ BOOST_MATH_STD_USING
+ T result;
+ if(s < 1)
+ {
+ // Rational Approximation
+ // Maximum Deviation Found: 3.099e-20
+ // Expected Error Term: 3.099e-20
+ // Max error found at long double precision: 5.890498e-20
+ static const T P[6] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.243392944335937499969),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.496837806864865688082),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0680008039723709987107),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00511620413006619942112),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000455369899250053003335),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.279496685273033761927e-4),
+ };
+ static const T Q[7] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.30425480068225790522),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.050052748580371598736),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00519355671064700627862),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000360623385771198350257),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.159600883054550987633e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.339770279812410586032e-6),
+ };
+ result = tools::evaluate_polynomial(P, sc) / tools::evaluate_polynomial(Q, sc);
+ result -= 1.2433929443359375F;
+ result += (sc);
+ result /= (sc);
+ }
+ else if(s <= 2)
+ {
+ // Maximum Deviation Found: 1.059e-21
+ // Expected Error Term: 1.059e-21
+ // Max error found at long double precision: 1.626303e-19
+
+ static const T P[6] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.577215664901532860605),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.222537368917162139445),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0356286324033215682729),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00304465292366350081446),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000178102511649069421904),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.700867470265983665042e-5),
+ };
+ static const T Q[7] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.259385759149531030085),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0373974962106091316854),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00332735159183332820617),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000188690420706998606469),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.635994377921861930071e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.226583954978371199405e-7),
+ };
+ result = tools::evaluate_polynomial(P, T(-sc)) / tools::evaluate_polynomial(Q, T(-sc));
+ result += 1 / (-sc);
+ }
+ else if(s <= 4)
+ {
+ // Maximum Deviation Found: 5.946e-22
+ // Expected Error Term: -5.946e-22
+ static const float Y = 0.6986598968505859375;
+ static const T P[7] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.053725830002359501027),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0470551187571475844778),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0101339410415759517471),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00100240326666092854528),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.685027119098122814867e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.390972820219765942117e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.540319769113543934483e-7),
+ };
+ static const T Q[8] = {
+ 1,
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.286577739726542730421),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0447355811517733225843),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00430125107610252363302),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000284956969089786662045),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.116188101609848411329e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.278090318191657278204e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.19683620233222028478e-8),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 2)) / tools::evaluate_polynomial(Q, T(s - 2));
+ result += Y + 1 / (-sc);
+ }
+ else if(s <= 7)
+ {
+ // Max error found at long double precision: 8.132216e-19
+ static const T P[8] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -2.49710190602259407065),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -3.36664913245960625334),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -1.77180020623777595452),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.464717885249654313933),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0643694921293579472583),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00464265386202805715487),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.000165556579779704340166),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.252884970740994069582e-5),
+ };
+ static const T Q[9] = {
+ 1,
+ BOOST_MATH_BIG_CONSTANT(T, 64, 1.01300131390690459085),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.387898115758643503827),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0695071490045701135188),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00586908595251442839291),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000217752974064612188616),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.397626583349419011731e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.927884739284359700764e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.119810501805618894381e-9),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 4)) / tools::evaluate_polynomial(Q, T(s - 4));
+ result = 1 + exp(result);
+ }
+ else if(s < 15)
+ {
+ // Max error in interpolated form: 1.133e-18
+ // Max error found at long double precision: 2.183198e-18
+ static const T P[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -4.78558028495135548083),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -3.23873322238609358947),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.892338582881021799922),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.131326296217965913809),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0115651591773783712996),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.000657728968362695775205),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.252051328129449973047e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.626503445372641798925e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.815696314790853893484e-8),
+ };
+ static const T Q[9] = {
+ 1,
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.525765665400123515036),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.10852641753657122787),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0115669945375362045249),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.000732896513858274091966),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.30683952282420248448e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.819649214609633126119e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.117957556472335968146e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.193432300973017671137e-12),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 7)) / tools::evaluate_polynomial(Q, T(s - 7));
+ result = 1 + exp(result);
+ }
+ else if(s < 42)
+ {
+ // Max error in interpolated form: 1.668e-17
+ // Max error found at long double precision: 1.669714e-17
+ static const T P[9] = {
+ BOOST_MATH_BIG_CONSTANT(T, 64, -10.3948950573308861781),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -2.82646012777913950108),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.342144362739570333665),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.0249285145498722647472),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.00122493108848097114118),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.423055371192592850196e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.1025215577185967488e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.165096762663509467061e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.145392555873022044329e-9),
+ };
+ static const T Q[10] = {
+ 1,
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.205135978585281988052),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.0192359357875879453602),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.00111496452029715514119),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.434928449016693986857e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.116911068726610725891e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.206704342290235237475e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.209772836100827647474e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 64, -0.939798249922234703384e-16),
+ BOOST_MATH_BIG_CONSTANT(T, 64, 0.264584017421245080294e-18),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 15)) / tools::evaluate_polynomial(Q, T(s - 15));
+ result = 1 + exp(result);
+ }
+ else if(s < 63)
+ {
+ result = 1 + pow(T(2), -s);
+ }
+ else
+ {
+ result = 1;
+ }
+ return result;
+}
+
+template <class T, class Policy>
+T zeta_imp_prec(T s, T sc, const Policy& pol, const mpl::int_<113>&)
+{
+ BOOST_MATH_STD_USING
+ T result;
+ if(s < 1)
+ {
+ // Rational Approximation
+ // Maximum Deviation Found: 9.493e-37
+ // Expected Error Term: 9.492e-37
+ // Max error found at long double precision: 7.281332e-31
+
+ static const T P[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0353008629988648122808504280990313668),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0107795651204927743049369868548706909),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000523961870530500751114866884685172975),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.661805838304910731947595897966487515e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.658932670403818558510656304189164638e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.103437265642266106533814021041010453e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.116818787212666457105375746642927737e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.660690993901506912123512551294239036e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.113103113698388531428914333768142527e-10),
+ };
+ static const T Q[11] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.387483472099602327112637481818565459),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0802265315091063135271497708694776875),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0110727276164171919280036408995078164),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00112552716946286252000434849173787243),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.874554160748626916455655180296834352e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.530097847491828379568636739662278322e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.248461553590496154705565904497247452e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.881834921354014787309644951507523899e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.217062446168217797598596496310953025e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.315823200002384492377987848307151168e-11),
+ };
+ result = tools::evaluate_polynomial(P, sc) / tools::evaluate_polynomial(Q, sc);
+ result += (sc);
+ result /= (sc);
+ }
+ else if(s <= 2)
+ {
+ // Maximum Deviation Found: 1.616e-37
+ // Expected Error Term: -1.615e-37
+
+ static const T P[10] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.577215664901532860606512090082402431),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.255597968739771510415479842335906308),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0494056503552807274142218876983542205),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00551372778611700965268920983472292325),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00043667616723970574871427830895192731),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.268562259154821957743669387915239528e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.109249633923016310141743084480436612e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.273895554345300227466534378753023924e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.583103205551702720149237384027795038e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.835774625259919268768735944711219256e-11),
+ };
+ static const T Q[11] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.316661751179735502065583176348292881),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0540401806533507064453851182728635272),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00598621274107420237785899476374043797),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000474907812321704156213038740142079615),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.272125421722314389581695715835862418e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.112649552156479800925522445229212933e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.301838975502992622733000078063330461e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.422960728687211282539769943184270106e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.377105263588822468076813329270698909e-11),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.581926559304525152432462127383600681e-13),
+ };
+ result = tools::evaluate_polynomial(P, T(-sc)) / tools::evaluate_polynomial(Q, T(-sc));
+ result += 1 / (-sc);
+ }
+ else if(s <= 4)
+ {
+ // Maximum Deviation Found: 1.891e-36
+ // Expected Error Term: -1.891e-36
+ // Max error found: 2.171527e-35
+
+ static const float Y = 0.6986598968505859375;
+ static const T P[11] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0537258300023595010275848333539748089),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0429086930802630159457448174466342553),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0136148228754303412510213395034056857),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00190231601036042925183751238033763915),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000186880390916311438818302549192456581),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.145347370745893262394287982691323657e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.805843276446813106414036600485884885e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.340818159286739137503297172091882574e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.115762357488748996526167305116837246e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.231904754577648077579913403645767214e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.340169592866058506675897646629036044e-12),
+ };
+ static const T Q[12] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.363755247765087100018556983050520554),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0696581979014242539385695131258321598),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00882208914484611029571547753782014817),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000815405623261946661762236085660996718),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.571366167062457197282642344940445452e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.309278269271853502353954062051797838e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.12822982083479010834070516053794262e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.397876357325018976733953479182110033e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.8484432107648683277598472295289279e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.105677416606909614301995218444080615e-11),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.547223964564003701979951154093005354e-15),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 2)) / tools::evaluate_polynomial(Q, T(s - 2));
+ result += Y + 1 / (-sc);
+ }
+ else if(s <= 6)
+ {
+ // Max error in interpolated form: 1.510e-37
+ // Max error found at long double precision: 2.769266e-34
+
+ static const T Y = 3.28348541259765625F;
+
+ static const T P[13] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.786383506575062179339611614117697622),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.495766593395271370974685959652073976),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.409116737851754766422360889037532228),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.57340744006238263817895456842655987),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.280479899797421910694892949057963111),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0753148409447590257157585696212649869),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0122934003684672788499099362823748632),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00126148398446193639247961370266962927),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.828465038179772939844657040917364896e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.361008916706050977143208468690645684e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.109879825497910544424797771195928112e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.214539416789686920918063075528797059e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.15090220092460596872172844424267351e-10),
+ };
+ static const T Q[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.69490865837142338462982225731926485),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1.22697696630994080733321401255942464),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.495409420862526540074366618006341533),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.122368084916843823462872905024259633),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0191412993625268971656513890888208623),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00191401538628980617753082598351559642),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000123318142456272424148930280876444459),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.531945488232526067889835342277595709e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.161843184071894368337068779669116236e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.305796079600152506743828859577462778e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.233582592298450202680170811044408894e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.275363878344548055574209713637734269e-13),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.221564186807357535475441900517843892e-15),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 4)) / tools::evaluate_polynomial(Q, T(s - 4));
+ result -= Y;
+ result = 1 + exp(result);
+ }
+ else if(s < 10)
+ {
+ // Max error in interpolated form: 1.999e-34
+ // Max error found at long double precision: 2.156186e-33
+
+ static const T P[13] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -4.0545627381873738086704293881227365),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -4.70088348734699134347906176097717782),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -2.36921550900925512951976617607678789),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.684322583796369508367726293719322866),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.126026534540165129870721937592996324),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.015636903921778316147260572008619549),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00135442294754728549644376325814460807),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.842793965853572134365031384646117061e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.385602133791111663372015460784978351e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.130458500394692067189883214401478539e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.315861074947230418778143153383660035e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.500334720512030826996373077844707164e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.420204769185233365849253969097184005e-12),
+ };
+ static const T Q[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.97663511666410096104783358493318814),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.40878780231201806504987368939673249),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0963890666609396058945084107597727252),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0142207619090854604824116070866614505),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00139010220902667918476773423995750877),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.940669540194694997889636696089994734e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.458220848507517004399292480807026602e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.16345521617741789012782420625435495e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.414007452533083304371566316901024114e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.68701473543366328016953742622661377e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.603461891080716585087883971886075863e-12),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.294670713571839023181857795866134957e-16),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.147003914536437243143096875069813451e-18),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 6)) / tools::evaluate_polynomial(Q, T(s - 6));
+ result = 1 + exp(result);
+ }
+ else if(s < 17)
+ {
+ // Max error in interpolated form: 1.641e-32
+ // Max error found at long double precision: 1.696121e-32
+ static const T P[13] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -6.91319491921722925920883787894829678),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -3.65491257639481960248690596951049048),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.813557553449954526442644544105257881),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0994317301685870959473658713841138083),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00726896610245676520248617014211734906),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000317253318715075854811266230916762929),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.66851422826636750855184211580127133e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.879464154730985406003332577806849971e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.113838903158254250631678791998294628e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.379184410304927316385211327537817583e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.612992858643904887150527613446403867e-11),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.347873737198164757035457841688594788e-13),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.289187187441625868404494665572279364e-15),
+ };
+ static const T Q[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.427310044448071818775721584949868806),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.074602514873055756201435421385243062),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00688651562174480772901425121653945942),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000360174847635115036351323894321880445),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.973556847713307543918865405758248777e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.853455848314516117964634714780874197e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.118203513654855112421673192194622826e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.462521662511754117095006543363328159e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.834212591919475633107355719369463143e-11),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.5354594751002702935740220218582929e-13),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.406451690742991192964889603000756203e-15),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.887948682401000153828241615760146728e-19),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.34980761098820347103967203948619072e-21),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 10)) / tools::evaluate_polynomial(Q, T(s - 10));
+ result = 1 + exp(result);
+ }
+ else if(s < 30)
+ {
+ // Max error in interpolated form: 1.563e-31
+ // Max error found at long double precision: 1.562725e-31
+
+ static const T P[13] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -11.7824798233959252791987402769438322),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -4.36131215284987731928174218354118102),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.732260980060982349410898496846972204),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0744985185694913074484248803015717388),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.00517228281320594683022294996292250527),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.000260897206152101522569969046299309939),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.989553462123121764865178453128769948e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.286916799741891410827712096608826167e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.637262477796046963617949532211619729e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.106796831465628373325491288787760494e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.129343095511091870860498356205376823e-11),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.102397936697965977221267881716672084e-13),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.402663128248642002351627980255756363e-16),
+ };
+ static const T Q[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.311288325355705609096155335186466508),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0438318468940415543546769437752132748),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.00374396349183199548610264222242269536),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.000218707451200585197339671707189281302),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.927578767487930747532953583797351219e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.294145760625753561951137473484889639e-6),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.704618586690874460082739479535985395e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.126333332872897336219649130062221257e-9),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.16317315713773503718315435769352765e-11),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.137846712823719515148344938160275695e-13),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.580975420554224366450994232723910583e-16),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.291354445847552426900293580511392459e-22),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.73614324724785855925025452085443636e-25),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 17)) / tools::evaluate_polynomial(Q, T(s - 17));
+ result = 1 + exp(result);
+ }
+ else if(s < 74)
+ {
+ // Max error in interpolated form: 2.311e-27
+ // Max error found at long double precision: 2.297544e-27
+ static const T P[14] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, -20.7944102007844314586649688802236072),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -4.95759941987499442499908748130192187),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.563290752832461751889194629200298688),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0406197001137935911912457120706122877),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.0020846534789473022216888863613422293),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.808095978462109173749395599401375667e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.244706022206249301640890603610060959e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.589477682919645930544382616501666572e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.113699573675553496343617442433027672e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.174767860183598149649901223128011828e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.210051620306761367764549971980026474e-12),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.189187969537370950337212675466400599e-14),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.116313253429564048145641663778121898e-16),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.376708747782400769427057630528578187e-19),
+ };
+ static const T Q[16] = {
+ BOOST_MATH_BIG_CONSTANT(T, 113, 1),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.205076752981410805177554569784219717),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.0202526722696670378999575738524540269),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.001278305290005994980069466658219057),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.576404779858501791742255670403304787e-4),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.196477049872253010859712483984252067e-5),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.521863830500876189501054079974475762e-7),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.109524209196868135198775445228552059e-8),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.181698713448644481083966260949267825e-10),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.234793316975091282090312036524695562e-12),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.227490441461460571047545264251399048e-14),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.151500292036937400913870642638520668e-16),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.543475775154780935815530649335936121e-19),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.241647013434111434636554455083309352e-28),
+ BOOST_MATH_BIG_CONSTANT(T, 113, -0.557103423021951053707162364713587374e-31),
+ BOOST_MATH_BIG_CONSTANT(T, 113, 0.618708773442584843384712258199645166e-34),
+ };
+ result = tools::evaluate_polynomial(P, T(s - 30)) / tools::evaluate_polynomial(Q, T(s - 30));
+ result = 1 + exp(result);
+ }
+ else if(s < 117)
+ {
+ result = 1 + pow(T(2), -s);
+ }
+ else
+ {
+ result = 1;
+ }
+ return result;
+}
+
+template <class T, class Policy, class Tag>
+T zeta_imp(T s, T sc, const Policy& pol, const Tag& tag)
+{
+ BOOST_MATH_STD_USING
+ if(s == 1)
+ return policies::raise_pole_error<T>(
+ "boost::math::zeta<%1%>",
+ "Evaluation of zeta function at pole %1%",
+ s, pol);
+ T result;
+ if(s == 0)
+ {
+ result = -0.5;
+ }
+ else if(s < 0)
+ {
+ std::swap(s, sc);
+ if(floor(sc/2) == sc/2)
+ result = 0;
+ else
+ {
+ result = boost::math::sin_pi(0.5f * sc, pol)
+ * 2 * pow(2 * constants::pi<T>(), -s)
+ * boost::math::tgamma(s, pol)
+ * zeta_imp(s, sc, pol, tag);
+ }
+ }
+ else
+ {
+ result = zeta_imp_prec(s, sc, pol, tag);
+ }
+ return result;
+}
+
+} // detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type zeta(T s, const Policy&)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::precision<result_type, Policy>::type precision_type;
+ typedef typename policies::normalise<
+ Policy,
+ policies::promote_float<false>,
+ policies::promote_double<false>,
+ policies::discrete_quantile<>,
+ policies::assert_undefined<> >::type forwarding_policy;
+ typedef typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<53> >,
+ mpl::int_<53>, // double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>, // 80-bit long double
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<113>, // 128-bit long double
+ mpl::int_<0> // too many bits, use generic version.
+ >::type
+ >::type
+ >::type
+ >::type tag_type;
+ //typedef mpl::int_<0> tag_type;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::zeta_imp(
+ static_cast<value_type>(s),
+ static_cast<value_type>(1 - static_cast<value_type>(s)),
+ forwarding_policy(),
+ tag_type()), "boost::math::zeta<%1%>(%1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type zeta(T s)
+{
+ return zeta(s, policies::policy<>());
+}
+
+}} // namespaces
+
+#endif // BOOST_MATH_ZETA_HPP
+
+
+