|
Boost-Commit : |
From: nicola.musatti_at_[hidden]
Date: 2007-10-09 16:49:23
Author: nmusatti
Date: 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
New Revision: 39860
URL: http://svn.boost.org/trac/boost/changeset/39860
Log:
Merge from trunk
Added:
branches/bcbboost/boost/math/bindings/
- copied from r39859, /trunk/boost/math/bindings/
branches/bcbboost/boost/math/concepts/
- copied from r39859, /trunk/boost/math/concepts/
branches/bcbboost/boost/math/constants/
- copied from r39859, /trunk/boost/math/constants/
branches/bcbboost/boost/math/distributions/
- copied from r39859, /trunk/boost/math/distributions/
branches/bcbboost/boost/math/distributions.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/detail/
- copied from r39859, /trunk/boost/math/distributions/detail/
branches/bcbboost/boost/math/policies/
- copied from r39859, /trunk/boost/math/policies/
branches/bcbboost/boost/math/special_functions.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/bessel.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/beta.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/binomial.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/cbrt.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/cos_pi.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_i0.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_i1.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_ik.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_j0.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_j1.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_jn.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_jy.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_jy_asym.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_k0.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_k1.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_kn.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_y0.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_y1.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/bessel_yn.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/erf_inv.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/gamma_inva.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/ibeta_inv_ab.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/ibeta_inverse.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/igamma_inverse.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/igamma_large.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/lgamma_small.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/simple_complex.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/t_distribution_inv.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/detail/unchecked_factorial.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/digamma.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/ellint_1.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/ellint_2.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/ellint_3.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/ellint_rc.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/ellint_rd.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/ellint_rf.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/ellint_rj.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/erf.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/factorials.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/fpclassify.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/gamma.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/hermite.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/laguerre.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/lanczos.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/legendre.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/math_fwd.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/powm1.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/sign.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/sin_pi.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/spherical_harmonic.hpp (contents, props changed)
branches/bcbboost/boost/math/special_functions/sqrt1pm1.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/
- copied from r39859, /trunk/boost/math/tools/
branches/bcbboost/boost/math/tools/detail/
- copied from r39859, /trunk/boost/math/tools/detail/
Removed:
branches/bcbboost/boost/math/special_functions/detail/series.hpp
Properties modified:
branches/bcbboost/boost/math/bindings/rr.hpp (contents, props changed)
branches/bcbboost/boost/math/concepts/distributions.hpp (contents, props changed)
branches/bcbboost/boost/math/concepts/real_concept.hpp (contents, props changed)
branches/bcbboost/boost/math/concepts/std_real_concept.hpp (contents, props changed)
branches/bcbboost/boost/math/constants/constants.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/bernoulli.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/beta.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/binomial.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/cauchy.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/chi_squared.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/complement.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/detail/common_error_handling.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/detail/derived_accessors.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/detail/inv_discrete_quantile.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/exponential.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/extreme_value.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/find_location.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/find_scale.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/fisher_f.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/fwd.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/gamma.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/lognormal.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/negative_binomial.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/normal.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/pareto.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/poisson.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/rayleigh.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/students_t.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/triangular.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/uniform.hpp (contents, props changed)
branches/bcbboost/boost/math/distributions/weibull.hpp (contents, props changed)
branches/bcbboost/boost/math/policies/error_handling.hpp (contents, props changed)
branches/bcbboost/boost/math/policies/policy.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/config.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_10.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_11.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_12.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_13.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_14.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_15.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_16.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_17.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_18.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_19.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_2.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_20.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_3.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_4.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_5.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_6.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_7.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_8.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner1_9.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_10.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_11.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_12.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_13.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_14.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_15.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_16.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_17.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_18.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_19.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_2.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_20.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_3.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_4.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_5.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_6.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_7.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_8.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner2_9.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_10.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_11.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_12.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_13.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_14.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_15.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_16.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_17.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_18.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_19.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_2.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_20.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_3.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_4.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_5.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_6.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_7.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_8.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/polynomial_horner3_9.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_10.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_11.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_12.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_13.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_14.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_15.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_16.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_17.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_18.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_19.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_2.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_20.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_3.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_4.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_5.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_6.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_7.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_8.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner1_9.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_10.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_11.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_12.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_13.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_14.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_15.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_16.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_17.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_18.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_19.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_2.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_20.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_3.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_4.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_5.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_6.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_7.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_8.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner2_9.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_10.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_11.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_12.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_13.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_14.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_15.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_16.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_17.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_18.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_19.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_2.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_20.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_3.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_4.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_5.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_6.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_7.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_8.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/detail/rational_horner3_9.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/fraction.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/minima.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/polynomial.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/precision.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/promotion.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/rational.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/real_cast.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/remez.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/roots.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/series.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/solve.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/stats.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/test.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/test_data.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/toms748_solve.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/traits.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/user.hpp (contents, props changed)
branches/bcbboost/boost/math/tools/workaround.hpp (contents, props changed)
Text files modified:
branches/bcbboost/boost/math/concepts/real_concept.hpp | 2
branches/bcbboost/boost/math/concepts/std_real_concept.hpp | 2
branches/bcbboost/boost/math/distributions/bernoulli.hpp | 4
branches/bcbboost/boost/math/distributions/beta.hpp | 4
branches/bcbboost/boost/math/distributions/binomial.hpp | 4
branches/bcbboost/boost/math/distributions/negative_binomial.hpp | 6
branches/bcbboost/boost/math/distributions/pareto.hpp | 2
branches/bcbboost/boost/math/distributions/poisson.hpp | 4
branches/bcbboost/boost/math/special_functions/acosh.hpp | 138 +++---------------
branches/bcbboost/boost/math/special_functions/asinh.hpp | 33 +++-
branches/bcbboost/boost/math/special_functions/atanh.hpp | 217 +++++-------------------------
branches/bcbboost/boost/math/special_functions/expm1.hpp | 276 +++++++++++++++++++++++++++++---------
branches/bcbboost/boost/math/special_functions/hypot.hpp | 122 +++++++---------
branches/bcbboost/boost/math/special_functions/log1p.hpp | 285 ++++++++++++++++++++++++++++++---------
branches/bcbboost/boost/math/special_functions/sinc.hpp | 36 ++++
branches/bcbboost/boost/math/special_functions/sinhc.hpp | 27 +++
branches/bcbboost/boost/math/tools/config.hpp | 36 ++--
17 files changed, 653 insertions(+), 545 deletions(-)
Modified: branches/bcbboost/boost/math/bindings/rr.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/concepts/distributions.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/concepts/real_concept.hpp
==============================================================================
--- /trunk/boost/math/concepts/real_concept.hpp (original)
+++ branches/bcbboost/boost/math/concepts/real_concept.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -196,7 +196,7 @@
inline real_concept ceil(real_concept a)
{ return std::ceil(a.value()); }
inline real_concept fmod(real_concept a, real_concept b)
-{ return fmodl(a.value(), b.value()); }
+{ return boost::math::tools::fmod_workaround(a.value(), b.value()); }
inline real_concept cosh(real_concept a)
{ return std::cosh(a.value()); }
inline real_concept exp(real_concept a)
Modified: branches/bcbboost/boost/math/concepts/std_real_concept.hpp
==============================================================================
--- /trunk/boost/math/concepts/std_real_concept.hpp (original)
+++ branches/bcbboost/boost/math/concepts/std_real_concept.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -195,7 +195,7 @@
inline boost::math::concepts::std_real_concept ceil(boost::math::concepts::std_real_concept a)
{ return std::ceil(a.value()); }
inline boost::math::concepts::std_real_concept fmod(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b)
-{ return fmodl(a.value(), b.value()); }
+{ return boost::math::tools::fmod_workaround(a.value(), b.value()); }
inline boost::math::concepts::std_real_concept cosh(boost::math::concepts::std_real_concept a)
{ return std::cosh(a.value()); }
inline boost::math::concepts::std_real_concept exp(boost::math::concepts::std_real_concept a)
Modified: branches/bcbboost/boost/math/constants/constants.hpp
==============================================================================
Added: branches/bcbboost/boost/math/distributions.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/distributions.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,42 @@
+// Copyright John Maddock 2006, 2007.
+// Copyright Paul A. Bristow 2006, 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)
+
+// This file includes *all* the distributions.
+// this may be useful if many are used
+// - to avoid including each distribution individually.
+
+#ifndef BOOST_MATH_DISTRIBUTIONS_HPP
+#define BOOST_MATH_DISTRIBUTIONS_HPP
+
+#include <boost/math/distributions/bernoulli.hpp>
+#include <boost/math/distributions/beta.hpp>
+#include <boost/math/distributions/binomial.hpp>
+#include <boost/math/distributions/cauchy.hpp>
+#include <boost/math/distributions/chi_squared.hpp>
+#include <boost/math/distributions/complement.hpp>
+#include <boost/math/distributions/exponential.hpp>
+#include <boost/math/distributions/extreme_value.hpp>
+#include <boost/math/distributions/fisher_f.hpp>
+#include <boost/math/distributions/gamma.hpp>
+#include <boost/math/distributions/lognormal.hpp>
+#include <boost/math/distributions/negative_binomial.hpp>
+#include <boost/math/distributions/normal.hpp>
+#include <boost/math/distributions/pareto.hpp>
+#include <boost/math/distributions/poisson.hpp>
+#include <boost/math/distributions/rayleigh.hpp>
+#include <boost/math/distributions/students_t.hpp>
+#include <boost/math/distributions/triangular.hpp>
+#include <boost/math/distributions/uniform.hpp>
+#include <boost/math/distributions/weibull.hpp>
+// find location and shape for appropriate distributions,
+// normal, cauchy, lognormal, symmetric triangular
+// Disabled for now, these are still work in progress.
+//#include <boost/math/distributions/find_scale.hpp>
+//#include <boost/math/distributions/find_location.hpp>
+
+#endif // BOOST_MATH_DISTRIBUTIONS_HPP
+
Modified: branches/bcbboost/boost/math/distributions/bernoulli.hpp
==============================================================================
--- /trunk/boost/math/distributions/bernoulli.hpp (original)
+++ branches/bcbboost/boost/math/distributions/bernoulli.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -149,7 +149,7 @@
} // variance
template <class RealType, class Policy>
- RealType pdf(const bernoulli_distribution<RealType, Policy>& dist, const RealType& k)
+ RealType pdf(const bernoulli_distribution<RealType, Policy>& dist, const RealType k)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
// Error check:
@@ -174,7 +174,7 @@
} // pdf
template <class RealType, class Policy>
- inline RealType cdf(const bernoulli_distribution<RealType, Policy>& dist, const RealType& k)
+ inline RealType cdf(const bernoulli_distribution<RealType, Policy>& dist, const RealType k)
{ // Cumulative Distribution Function Bernoulli.
RealType p = dist.success_fraction();
// Error check:
Modified: branches/bcbboost/boost/math/distributions/beta.hpp
==============================================================================
--- /trunk/boost/math/distributions/beta.hpp (original)
+++ branches/bcbboost/boost/math/distributions/beta.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -364,7 +364,7 @@
} // kurtosis
template <class RealType, class Policy>
- inline RealType pdf(const beta_distribution<RealType, Policy>& dist, const RealType& x)
+ inline RealType pdf(const beta_distribution<RealType, Policy>& dist, const RealType x)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
@@ -389,7 +389,7 @@
} // pdf
template <class RealType, class Policy>
- inline RealType cdf(const beta_distribution<RealType, Policy>& dist, const RealType& x)
+ inline RealType cdf(const beta_distribution<RealType, Policy>& dist, const RealType x)
{ // Cumulative Distribution Function beta.
BOOST_MATH_STD_USING // for ADL of std functions
Modified: branches/bcbboost/boost/math/distributions/binomial.hpp
==============================================================================
--- /trunk/boost/math/distributions/binomial.hpp (original)
+++ branches/bcbboost/boost/math/distributions/binomial.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -437,7 +437,7 @@
} // variance
template <class RealType, class Policy>
- RealType pdf(const binomial_distribution<RealType, Policy>& dist, const RealType& k)
+ RealType pdf(const binomial_distribution<RealType, Policy>& dist, const RealType k)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
@@ -498,7 +498,7 @@
} // pdf
template <class RealType, class Policy>
- inline RealType cdf(const binomial_distribution<RealType, Policy>& dist, const RealType& k)
+ inline RealType cdf(const binomial_distribution<RealType, Policy>& dist, const RealType k)
{ // Cumulative Distribution Function Binomial.
// The random variate k is the number of successes in n trials.
// k argument may be integral, signed, or unsigned, or floating point.
Modified: branches/bcbboost/boost/math/distributions/cauchy.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/chi_squared.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/complement.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/detail/common_error_handling.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/detail/derived_accessors.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/detail/inv_discrete_quantile.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/exponential.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/extreme_value.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/find_location.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/find_scale.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/fisher_f.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/fwd.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/gamma.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/lognormal.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/negative_binomial.hpp
==============================================================================
--- /trunk/boost/math/distributions/negative_binomial.hpp (original)
+++ branches/bcbboost/boost/math/distributions/negative_binomial.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -335,7 +335,7 @@
// chf of Negative Binomial distribution provided by derived accessors.
template <class RealType, class Policy>
- inline RealType pdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
+ inline RealType pdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType k)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
@@ -361,7 +361,7 @@
} // negative_binomial_pdf
template <class RealType, class Policy>
- inline RealType cdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& k)
+ inline RealType cdf(const negative_binomial_distribution<RealType, Policy>& dist, const RealType k)
{ // Cumulative Distribution Function of Negative Binomial.
static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
using boost::math::ibeta; // Regularized incomplete beta function.
@@ -527,7 +527,7 @@
// since the probability of zero failures may be non-zero,
return 0; // but zero is the best we can do:
}
- if (-Q <= boost::math::powm1(dist.success_fraction(), dist.successes(), Policy()))
+ if (-Q <= powm1(dist.success_fraction(), dist.successes(), Policy()))
{ // q <= cdf(complement(dist, 0)) == pdf(dist, 0)
return 0; //
}
Modified: branches/bcbboost/boost/math/distributions/normal.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/pareto.hpp
==============================================================================
--- /trunk/boost/math/distributions/pareto.hpp (original)
+++ branches/bcbboost/boost/math/distributions/pareto.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -212,7 +212,7 @@
}
// result = RealType(1) - pow((location / x), shape);
- result = -boost::math::powm1(location/x, shape, Policy()); // should be more accurate.
+ result = -powm1(location/x, shape, Policy()); // should be more accurate.
return result;
} // cdf
Modified: branches/bcbboost/boost/math/distributions/poisson.hpp
==============================================================================
--- /trunk/boost/math/distributions/poisson.hpp (original)
+++ branches/bcbboost/boost/math/distributions/poisson.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -306,7 +306,7 @@
} // RealType kurtosis
template <class RealType, class Policy>
- RealType pdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
+ RealType pdf(const poisson_distribution<RealType, Policy>& dist, const RealType k)
{ // Probability Density/Mass Function.
// Probability that there are EXACTLY k occurrences (or arrivals).
BOOST_FPU_EXCEPTION_GUARD
@@ -353,7 +353,7 @@
} // pdf
template <class RealType, class Policy>
- RealType cdf(const poisson_distribution<RealType, Policy>& dist, const RealType& k)
+ RealType cdf(const poisson_distribution<RealType, Policy>& dist, const RealType k)
{ // Cumulative Distribution Function Poisson.
// The random variate k is the number of occurrences(or arrivals)
// k argument may be integral, signed, or unsigned, or floating point.
Modified: branches/bcbboost/boost/math/distributions/rayleigh.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/students_t.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/triangular.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/uniform.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/distributions/weibull.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/policies/error_handling.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/policies/policy.hpp
==============================================================================
Added: branches/bcbboost/boost/math/special_functions.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,51 @@
+// Copyright John Maddock 2006, 2007.
+// Copyright Paul A. Bristow 2006, 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)
+
+// This file includes *all* the special functions.
+// this may be useful if many are used
+// - to avoid including each function individually.
+
+#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_HPP
+#define BOOST_MATH_SPECIAL_FUNCTIONS_HPP
+
+#include <boost/math/special_functions/acosh.hpp>
+#include <boost/math/special_functions/asinh.hpp>
+#include <boost/math/special_functions/atanh.hpp>
+#include <boost/math/special_functions/bessel.hpp>
+#include <boost/math/special_functions/beta.hpp>
+#include <boost/math/special_functions/binomial.hpp>
+#include <boost/math/special_functions/cbrt.hpp>
+#include <boost/math/special_functions/cos_pi.hpp>
+#include <boost/math/special_functions/digamma.hpp>
+#include <boost/math/special_functions/ellint_1.hpp>
+#include <boost/math/special_functions/ellint_2.hpp>
+#include <boost/math/special_functions/ellint_3.hpp>
+#include <boost/math/special_functions/ellint_rc.hpp>
+#include <boost/math/special_functions/ellint_rd.hpp>
+#include <boost/math/special_functions/ellint_rf.hpp>
+#include <boost/math/special_functions/ellint_rj.hpp>
+#include <boost/math/special_functions/erf.hpp>
+#include <boost/math/special_functions/expm1.hpp>
+#include <boost/math/special_functions/factorials.hpp>
+#include <boost/math/special_functions/fpclassify.hpp>
+#include <boost/math/special_functions/gamma.hpp>
+#include <boost/math/special_functions/hermite.hpp>
+#include <boost/math/special_functions/hypot.hpp>
+#include <boost/math/special_functions/laguerre.hpp>
+#include <boost/math/special_functions/lanczos.hpp>
+#include <boost/math/special_functions/legendre.hpp>
+#include <boost/math/special_functions/log1p.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/math/special_functions/powm1.hpp>
+#include <boost/math/special_functions/sign.hpp>
+#include <boost/math/special_functions/sin_pi.hpp>
+#include <boost/math/special_functions/sinc.hpp>
+#include <boost/math/special_functions/sinhc.hpp>
+#include <boost/math/special_functions/spherical_harmonic.hpp>
+#include <boost/math/special_functions/sqrt1pm1.hpp>
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_HPP
Modified: branches/bcbboost/boost/math/special_functions/acosh.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/acosh.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/acosh.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -12,13 +12,10 @@
#include <cmath>
-#include <limits>
-#include <string>
-#include <stdexcept>
-
-
#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>
// This is the inverse of the hyperbolic cosine function.
@@ -26,6 +23,8 @@
{
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:
@@ -37,39 +36,25 @@
using ::std::numeric_limits;
#endif
-#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
- // This is the main fare
-
- template<typename T>
- inline T acosh(const T x)
+ template<typename T, typename Policy>
+ inline T acosh_imp(const T x, const Policy& pol)
{
using ::std::abs;
using ::std::sqrt;
using ::std::log;
- using ::std::numeric_limits;
-
-
T const one = static_cast<T>(1);
T const two = static_cast<T>(2);
- static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
+ static T const taylor_2_bound = sqrt(tools::epsilon<T>());
static T const taylor_n_bound = sqrt(taylor_2_bound);
static T const upper_taylor_2_bound = one/taylor_2_bound;
- if (x < one)
+ if(x < one)
{
- if (numeric_limits<T>::has_quiet_NaN)
- {
- return(numeric_limits<T>::quiet_NaN());
- }
- else
- {
- ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
- ::std::domain_error bad_argument(error_reporting);
-
- throw(bad_argument);
- }
+ return policies::raise_domain_error<T>(
+ "boost::math::acosh<%1%>(%1%)",
+ "acosh requires x >= 1, but got x = %1%.", x, pol);
}
else if (x >= taylor_n_bound)
{
@@ -101,98 +86,27 @@
return(sqrt(static_cast<T>(2))*result);
}
}
-#else
- // These are implementation details (for main fare see below)
-
- namespace detail
+ }
+
+ template<typename T, typename Policy>
+ inline typename tools::promote_args<T>::type acosh(const T x, const Policy& pol)
{
- template <
- typename T,
- bool QuietNanSupported
- >
- struct acosh_helper2_t
- {
- static T get_NaN()
- {
- return(::std::numeric_limits<T>::quiet_NaN());
- }
- }; // boost::detail::acosh_helper2_t
-
-
- template<typename T>
- struct acosh_helper2_t<T, false>
- {
- static T get_NaN()
- {
- ::std::string error_reporting("Argument to acosh is greater than or equal to +1!");
- ::std::domain_error bad_argument(error_reporting);
-
- throw(bad_argument);
- }
- }; // boost::detail::acosh_helper2_t
-
- } // boost::detail
-
-
- // This is the main fare
-
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::acosh_imp(
+ static_cast<result_type>(x), pol);
+ }
template<typename T>
- inline T acosh(const T x)
+ inline typename tools::promote_args<T>::type acosh(const T x)
{
- using ::std::abs;
- using ::std::sqrt;
- using ::std::log;
-
- using ::std::numeric_limits;
-
- typedef detail::acosh_helper2_t<T, std::numeric_limits<T>::has_quiet_NaN> helper2_type;
-
-
- T const one = static_cast<T>(1);
- T const two = static_cast<T>(2);
-
- static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
- static T const taylor_n_bound = sqrt(taylor_2_bound);
- static T const upper_taylor_2_bound = one/taylor_2_bound;
-
- if (x < one)
- {
- return(helper2_type::get_NaN());
- }
- else if (x >= taylor_n_bound)
- {
- if (x > upper_taylor_2_bound)
- {
- // approximation by laurent series in 1/x at 0+ order from -1 to 0
- return( log( x*two) );
- }
- else
- {
- return( log( x + sqrt(x*x-one) ) );
- }
- }
- else
- {
- T y = sqrt(x-one);
-
- // approximation by taylor series in y at 0 up to order 2
- T result = y;
-
- if (y >= taylor_2_bound)
- {
- T y3 = y*y*y;
-
- // approximation by taylor series in y at 0 up to order 4
- result -= y3/static_cast<T>(12);
- }
-
- return(sqrt(static_cast<T>(2))*result);
- }
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::acosh_imp(
+ static_cast<result_type>(x), policies::policy<>());
}
-#endif /* defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) */
+
}
}
#endif /* BOOST_ACOSH_HPP */
+
Modified: branches/bcbboost/boost/math/special_functions/asinh.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/asinh.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/asinh.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -12,13 +12,9 @@
#include <cmath>
-#include <limits>
-#include <string>
-#include <stdexcept>
-
-
#include <boost/config.hpp>
-
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
// This is the inverse of the hyperbolic sine function.
@@ -26,6 +22,7 @@
{
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:
@@ -38,19 +35,16 @@
#endif
template<typename T>
- inline T asinh(const T x)
+ inline T asinh_imp(const T x)
{
using ::std::abs;
using ::std::sqrt;
using ::std::log;
- using ::std::numeric_limits;
-
-
T const one = static_cast<T>(1);
T const two = static_cast<T>(2);
- static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
+ static T const taylor_2_bound = sqrt(tools::epsilon<T>());
static T const taylor_n_bound = sqrt(taylor_2_bound);
static T const upper_taylor_2_bound = one/taylor_2_bound;
static T const upper_taylor_n_bound = one/taylor_n_bound;
@@ -95,6 +89,23 @@
return(result);
}
}
+ }
+
+ template<typename T>
+ inline typename tools::promote_args<T>::type asinh(const T x)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::asinh_imp(
+ static_cast<result_type>(x));
+ }
+ template<typename T, typename Policy>
+ inline typename tools::promote_args<T>::type asinh(const T x, const Policy&)
+ {
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::asinh_imp(
+ static_cast<result_type>(x));
+ }
+
}
}
Modified: branches/bcbboost/boost/math/special_functions/atanh.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/atanh.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/atanh.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -12,13 +12,10 @@
#include <cmath>
-#include <limits>
-#include <string>
-#include <stdexcept>
-
-
#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>
// This is the inverse of the hyperbolic tangent function.
@@ -26,6 +23,8 @@
{
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:
@@ -37,11 +36,10 @@
using ::std::numeric_limits;
#endif
-#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
// This is the main fare
- template<typename T>
- inline T atanh(const T x)
+ template<typename T, typename Policy>
+ inline T atanh_imp(const T x, const Policy& pol)
{
using ::std::abs;
using ::std::sqrt;
@@ -52,64 +50,32 @@
T const one = static_cast<T>(1);
T const two = static_cast<T>(2);
- static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
+ static T const taylor_2_bound = sqrt(tools::epsilon<T>());
static T const taylor_n_bound = sqrt(taylor_2_bound);
+
+ static const char* function = "boost::math::atanh<%1%>(%1%)";
if (x < -one)
{
- if (numeric_limits<T>::has_quiet_NaN)
- {
- return(numeric_limits<T>::quiet_NaN());
- }
- else
- {
- ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
- ::std::domain_error bad_argument(error_reporting);
-
- throw(bad_argument);
- }
+ return policies::raise_domain_error<T>(
+ function,
+ "atanh requires x >= -1, but got x = %1%.", x, pol);
}
- else if (x < -one+numeric_limits<T>::epsilon())
+ else if (x < -one + tools::epsilon<T>())
{
- if (numeric_limits<T>::has_infinity)
- {
- return(-numeric_limits<T>::infinity());
- }
- else
- {
- ::std::string error_reporting("Argument to atanh is -1 (result: -Infinity)!");
- ::std::out_of_range bad_argument(error_reporting);
-
- throw(bad_argument);
- }
+ // -Infinity:
+ return -policies::raise_overflow_error<T>(function, 0, pol);
}
- else if (x > +one-numeric_limits<T>::epsilon())
+ else if (x > one - tools::epsilon<T>())
{
- if (numeric_limits<T>::has_infinity)
- {
- return(+numeric_limits<T>::infinity());
- }
- else
- {
- ::std::string error_reporting("Argument to atanh is +1 (result: +Infinity)!");
- ::std::out_of_range bad_argument(error_reporting);
-
- throw(bad_argument);
- }
+ // Infinity:
+ return -policies::raise_overflow_error<T>(function, 0, pol);
}
else if (x > +one)
{
- if (numeric_limits<T>::has_quiet_NaN)
- {
- return(numeric_limits<T>::quiet_NaN());
- }
- else
- {
- ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
- ::std::domain_error bad_argument(error_reporting);
-
- throw(bad_argument);
- }
+ return policies::raise_domain_error<T>(
+ function,
+ "atanh requires x <= 1, but got x = %1%.", x, pol);
}
else if (abs(x) >= taylor_n_bound)
{
@@ -131,137 +97,26 @@
return(result);
}
}
-#else
- // These are implementation details (for main fare see below)
-
- namespace detail
+ }
+
+ template<typename T, typename Policy>
+ inline typename tools::promote_args<T>::type atanh(const T x, const Policy& pol)
{
- template <
- typename T,
- bool InfinitySupported
- >
- struct atanh_helper1_t
- {
- static T get_pos_infinity()
- {
- return(+::std::numeric_limits<T>::infinity());
- }
-
- static T get_neg_infinity()
- {
- return(-::std::numeric_limits<T>::infinity());
- }
- }; // boost::math::detail::atanh_helper1_t
-
-
- template<typename T>
- struct atanh_helper1_t<T, false>
- {
- static T get_pos_infinity()
- {
- ::std::string error_reporting("Argument to atanh is +1 (result: +Infinity)!");
- ::std::out_of_range bad_argument(error_reporting);
-
- throw(bad_argument);
- }
-
- static T get_neg_infinity()
- {
- ::std::string error_reporting("Argument to atanh is -1 (result: -Infinity)!");
- ::std::out_of_range bad_argument(error_reporting);
-
- throw(bad_argument);
- }
- }; // boost::math::detail::atanh_helper1_t
-
-
- template <
- typename T,
- bool QuietNanSupported
- >
- struct atanh_helper2_t
- {
- static T get_NaN()
- {
- return(::std::numeric_limits<T>::quiet_NaN());
- }
- }; // boost::detail::atanh_helper2_t
-
-
- template<typename T>
- struct atanh_helper2_t<T, false>
- {
- static T get_NaN()
- {
- ::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
- ::std::domain_error bad_argument(error_reporting);
-
- throw(bad_argument);
- }
- }; // boost::detail::atanh_helper2_t
- } // boost::detail
-
-
- // This is the main fare
-
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::atanh_imp(
+ static_cast<result_type>(x), pol);
+ }
template<typename T>
- inline T atanh(const T x)
+ inline typename tools::promote_args<T>::type atanh(const T x)
{
- using ::std::abs;
- using ::std::sqrt;
- using ::std::log;
-
- using ::std::numeric_limits;
-
- typedef detail::atanh_helper1_t<T, ::std::numeric_limits<T>::has_infinity> helper1_type;
- typedef detail::atanh_helper2_t<T, ::std::numeric_limits<T>::has_quiet_NaN> helper2_type;
-
-
- T const one = static_cast<T>(1);
- T const two = static_cast<T>(2);
-
- static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
- static T const taylor_n_bound = sqrt(taylor_2_bound);
-
- if (x < -one)
- {
- return(helper2_type::get_NaN());
- }
- else if (x < -one+numeric_limits<T>::epsilon())
- {
- return(helper1_type::get_neg_infinity());
- }
- else if (x > +one-numeric_limits<T>::epsilon())
- {
- return(helper1_type::get_pos_infinity());
- }
- else if (x > +one)
- {
- return(helper2_type::get_NaN());
- }
- else if (abs(x) >= taylor_n_bound)
- {
- return(log( (one + x) / (one - x) ) / two);
- }
- else
- {
- // approximation by taylor series in x at 0 up to order 2
- T result = x;
-
- if (abs(x) >= taylor_2_bound)
- {
- 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);
- }
+ typedef typename tools::promote_args<T>::type result_type;
+ return detail::atanh_imp(
+ static_cast<result_type>(x), policies::policy<>());
}
-#endif /* defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) */
+
}
}
#endif /* BOOST_ATANH_HPP */
+
Added: branches/bcbboost/boost/math/special_functions/bessel.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/bessel.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,474 @@
+// 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
+
+#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/sin_pi.hpp>
+#include <boost/math/special_functions/cos_pi.hpp>
+#include <boost/math/special_functions/sinc.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/tools/promotion.hpp>
+
+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;
+ term = pow(mult, v) / boost::math::tgamma(v+1, Policy());
+ mult *= -mult;
+ }
+ T operator()()
+ {
+ 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 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 bessel_j_small_z_series(T v, T x, const Policy& pol)
+{
+ bessel_j_small_z_series_term<T, Policy> s(v, x);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+ T result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter);
+ policies::check_series_iterations("boost::math::bessel_j_small_z_series<%1%>(%1%,%1%)", max_iter, pol);
+ return result;
+}
+
+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>();
+ T result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter);
+ policies::check_series_iterations("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, -x, t, pol);
+ if(tools::real_cast<int>(v) & 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)))
+ {
+ 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.
+ typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
+ if((fabs(v) < 200) && (floor(v) == v))
+ {
+ if(fabs(x) > asymptotic_bessel_j_limit<T>(v, tag_type()))
+ return asymptotic_bessel_j_large_x_2(v, x);
+ else
+ return bessel_jn(tools::real_cast<int>(v), 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
+ typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
+ if(fabs(x) > asymptotic_bessel_j_limit<T>(abs(v), tag_type()))
+ {
+ T r = asymptotic_bessel_j_large_x_2(static_cast<T>(abs(v)), x);
+ if((v < 0) && (v & 1))
+ r = -r;
+ return r;
+ }
+ else
+ 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(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, -x, pol);
+ if(tools::real_cast<int>(v) & 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):
+ T e = exp(x / 2);
+ return e * (e / sqrt(2 * x * constants::pi<T>()));
+ }
+ if(policies::digits<T, Policy>() <= 64)
+ {
+ if(v == 0)
+ {
+ return bessel_i0(x);
+ }
+ if(v == 1)
+ {
+ return bessel_i1(x);
+ }
+ }
+ 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(tools::real_cast<int>(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%)";
+ 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;
+ 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) && (tools::real_cast<int>(v) & 1))
+ r = -r;
+ return r;
+ }
+ else
+ return bessel_yn(tools::real_cast<int>(v), x, pol);
+ }
+ return cyl_neumann_imp<T>(v, x, bessel_no_int_tag(), pol);
+}
+
+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;
+ 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(tools::real_cast<int>(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(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
Added: branches/bcbboost/boost/math/special_functions/beta.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/beta.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,1350 @@
+// (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
+
+#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/tools/roots.hpp>
+#include <boost/static_assert.hpp>
+#include <cmath>
+
+namespace boost{ namespace math{
+
+namespace detail{
+
+//
+// Implementation of Beta(a,b) using the Lanczos approximation:
+//
+template <class T, class L, class Policy>
+T beta_imp(T a, T b, const L&, 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 + L::g() - T(0.5);
+ T bgh = b + L::g() - T(0.5);
+ T cgh = c + L::g() - T(0.5);
+ result = L::lanczos_sum_expG_scaled(a) * L::lanczos_sum_expG_scaled(b) / L::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 L> beta_imp(T a, T b, const L&)
+
+//
+// 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), 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::digits<T, Policy>());
+ T sb = detail::lower_gamma_series(b, lb, pol) / b;
+ sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::digits<T, Policy>());
+ T sc = detail::lower_gamma_series(c, lc, pol) / c;
+ sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::digits<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 L, class Policy>
+T ibeta_power_terms(T a,
+ T b,
+ T x,
+ T y,
+ const L&,
+ 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 + L::g() - T(0.5);
+ T bgh = b + L::g() - T(0.5);
+ T cgh = c + L::g() - T(0.5);
+ result = L::lanczos_sum_expG_scaled(c) / (L::lanczos_sum_expG_scaled(a) * L::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));
+ else
+ result *= pow((x * cgh) / agh, a);
+ if(fabs(l2) < 0.1)
+ result *= exp(b * boost::math::log1p(l2, pol));
+ else
+ result *= pow((y * cgh) / bgh, b);
+ }
+ 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);
+ }
+ 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);
+ }
+ }
+ 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);
+ }
+ else
+ {
+ // Second base near 1 only:
+ T l = b * boost::math::log1p(l2, pol)
+ + a * log((x * cgh) / agh);
+ result *= exp(l);
+ }
+ }
+ else
+ {
+ // general case:
+ T b1 = (x * cgh) / agh;
+ T b2 = (y * cgh) / bgh;
+ T l1 = a * log(b1);
+ T l2 = b * log(b2);
+ 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);
+ }
+ else
+ {
+ // finally the normal case:
+ result *= pow(b1, a) * pow(b2, b);
+ }
+ }
+ // combine with the leftover terms from the Lanczos approximation:
+ result *= sqrt(bgh / boost::math::constants::e<T>());
+ result *= sqrt(agh / cgh);
+ result *= prefix;
+
+ 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;
+
+ T prefix = 1;
+ 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::digits<T, Policy>());
+ T sb = detail::lower_gamma_series(b, lb, pol) / b;
+ sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::digits<T, Policy>());
+ T sc = detail::lower_gamma_series(c, lc, pol) / c;
+ sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::digits<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 L, class Policy>
+T ibeta_series(T a, T b, T x, T s0, const L&, 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 + L::g() - T(0.5);
+ T bgh = b + L::g() - T(0.5);
+ T cgh = c + L::g() - T(0.5);
+ result = L::lanczos_sum_expG_scaled(c) / (L::lanczos_sum_expG_scaled(a) * L::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::digits<T, Policy>(), max_iter, s0);
+ policies::check_series_iterations("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 prefix = 1;
+ 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::digits<T, Policy>());
+ T sb = detail::lower_gamma_series(b, lb, pol) / b;
+ sb += detail::upper_gamma_fraction(b, lb, ::boost::math::policies::digits<T, Policy>());
+ T sc = detail::lower_gamma_series(c, lc, pol) / c;
+ sc += detail::upper_gamma_fraction(c, lc, ::boost::math::policies::digits<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::digits<T, Policy>(), max_iter, s0);
+ policies::check_series_iterations("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::digits<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;
+ 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!!!
+ 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 / 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 = 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] / unchecked_factorial<T>(tmp1);
+ tmp1 += 2;
+ }
+ p[n] /= n;
+ p[n] += bm1 / 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 L>T beta_small_b_large_a_series(T a, T b, T x, T y, T s0, T mult, const L& 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 = tools::real_cast<unsigned>(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.
+
+ 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(normalised)
+ {
+ // extend to a few very special cases:
+ if((a == 0) && (b != 0))
+ return inv ? 0 : 1;
+ else if(b == 0)
+ return inv ? 1 : 0;
+ }
+
+ 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);
+
+ if(x == 0)
+ {
+ if(p_derivative)
+ {
+ *p_derivative = (a == 1) ? 1 : (a < 1) ? tools::max_value<T>() / 2 : tools::min_value<T>() * 2;
+ }
+ return (invert ? (normalised ? 1 : boost::math::beta(a, b, pol)) : 0);
+ }
+ if(x == 1)
+ {
+ if(p_derivative)
+ {
+ *p_derivative = (b == 1) ? 1 : (b < 1) ? tools::max_value<T>() / 2 : 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;
+ }
+ 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);
+ 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);
+ }
+ }
+ 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);
+ 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);
+ }
+ }
+ else
+ {
+ // Sidestep on a, and then use the series representation:
+ T prefix;
+ if(!normalised)
+ {
+ prefix = rising_factorial_ratio(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(a + 20, b, x, y, fract, prefix, pol, normalised);
+ else
+ {
+ fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -beta_small_b_large_a_series(a + 20, b, x, y, fract, prefix, pol, normalised);
+ }
+ }
+ }
+ }
+ 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);
+ 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);
+ }
+ }
+ 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);
+ 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);
+ }
+ }
+ else if(a >= 15)
+ {
+ if(!invert)
+ fract = beta_small_b_large_a_series(a, b, x, y, T(0), T(1), pol, normalised);
+ 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);
+ }
+ }
+ else
+ {
+ // Sidestep to improve errors:
+ T prefix;
+ if(!normalised)
+ {
+ prefix = rising_factorial_ratio(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(a + 20, b, x, y, fract, prefix, pol, normalised);
+ else
+ {
+ fract -= (normalised ? 1 : boost::math::beta(a, b, pol));
+ invert = false;
+ fract = -beta_small_b_large_a_series(a + 20, b, x, y, fract, prefix, pol, normalised);
+ }
+ }
+ }
+ }
+ }
+ 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;
+ }
+
+ 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);
+ }
+ else if(b * x <= 0.7)
+ {
+ if(!invert)
+ fract = ibeta_series(a, b, x, T(0), lanczos_type(), normalised, p_derivative, y, pol);
+ 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);
+ }
+ }
+ else if(a > 15)
+ {
+ // sidestep so we can use the series representation:
+ int n = static_cast<int>(boost::math::tools::real_cast<long double>(floor(b)));
+ if(n == b)
+ --n;
+ T bbar = b - n;
+ T prefix;
+ if(!normalised)
+ {
+ prefix = rising_factorial_ratio(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;
+ }
+ 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 = static_cast<int>(boost::math::tools::real_cast<long double>(floor(b)));
+ 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(a+20, bbar, x, y, fract, T(1), pol, normalised);
+ if(invert)
+ {
+ fract = -fract;
+ invert = false;
+ }
+ }
+ else
+ fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
+ }
+ else
+ fract = ibeta_fraction2(a, b, x, y, pol, normalised, p_derivative);
+ }
+ 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 L>T ibeta_imp(T a, T b, T x, const L& 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(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
+
+
+
+
Added: branches/bcbboost/boost/math/special_functions/binomial.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/binomial.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,75 @@
+// 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
+
+#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_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
+
+
Added: branches/bcbboost/boost/math/special_functions/cbrt.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/cbrt.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,72 @@
+// (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
+
+#include <boost/math/tools/roots.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+
+namespace boost{ namespace math{
+
+namespace detail
+{
+
+ template <class T>
+ struct cbrt_functor
+ {
+ cbrt_functor(T const& target) : a(target){}
+ std::tr1::tuple<T, T, T> operator()(T const& z)
+ {
+ T sqr = z * z;
+ return std::tr1::make_tuple(sqr * z - a, 3 * sqr, 6 * z);
+ }
+ private:
+ T a;
+ };
+
+template <class T, class Policy>
+T cbrt_imp(T z, const Policy&)
+{
+ BOOST_MATH_STD_USING
+ int i_exp, sign(1);
+ if(z < 0)
+ {
+ z = -z;
+ sign = -sign;
+ }
+ if(z == 0)
+ return 0;
+
+ frexp(z, &i_exp);
+ T min = static_cast<T>(ldexp(0.5, i_exp/3));
+ T max = static_cast<T>(ldexp(2.0, i_exp/3));
+ T guess = static_cast<T>(ldexp(1.0, i_exp/3));
+ int digits = (policies::digits<T, Policy>()) / 2;
+ return sign * tools::halley_iterate(detail::cbrt_functor<T>(z), guess, min, max, digits);
+}
+
+} // 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;
+ return detail::cbrt_imp(result_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
+
+
+
Added: branches/bcbboost/boost/math/special_functions/cos_pi.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/cos_pi.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,53 @@
+// 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
+
+#include <cmath>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/real_cast.hpp>
+#include <boost/math/constants/constants.hpp>
+
+namespace boost{ namespace math{
+
+template <class T>
+T cos_pi(T x)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ // cos of pi*x:
+ bool invert = false;
+ if(x < 0.5)
+ return cos(constants::pi<T>() * x);
+ if(x < 1)
+ {
+ x = -x;
+ }
+
+ T rem = floor(x);
+ if(tools::real_cast<int>(rem) & 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 ? -rem : rem;
+}
+
+template <class T, class Policy>
+inline T cos_pi(T x, const Policy&)
+{
+ return cos_pi(x);
+}
+
+} // namespace math
+} // namespace boost
+#endif
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_i0.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_i0.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,96 @@
+// 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
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/assert.hpp>
+
+// Modified Bessel function of the first kind of order zero
+// minimax rational approximations on intervals, see
+// Blair and Edwards, Chalk River Report AECL-4928, 1974
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T>
+T bessel_i0(T x)
+{
+ static const T P1[] = {
+ static_cast<T>(-2.2335582639474375249e+15L),
+ static_cast<T>(-5.5050369673018427753e+14L),
+ static_cast<T>(-3.2940087627407749166e+13L),
+ static_cast<T>(-8.4925101247114157499e+11L),
+ static_cast<T>(-1.1912746104985237192e+10L),
+ static_cast<T>(-1.0313066708737980747e+08L),
+ static_cast<T>(-5.9545626019847898221e+05L),
+ static_cast<T>(-2.4125195876041896775e+03L),
+ static_cast<T>(-7.0935347449210549190e+00L),
+ static_cast<T>(-1.5453977791786851041e-02L),
+ static_cast<T>(-2.5172644670688975051e-05L),
+ static_cast<T>(-3.0517226450451067446e-08L),
+ static_cast<T>(-2.6843448573468483278e-11L),
+ static_cast<T>(-1.5982226675653184646e-14L),
+ static_cast<T>(-5.2487866627945699800e-18L),
+ };
+ static const T Q1[] = {
+ static_cast<T>(-2.2335582639474375245e+15L),
+ static_cast<T>(7.8858692566751002988e+12L),
+ static_cast<T>(-1.2207067397808979846e+10L),
+ static_cast<T>(1.0377081058062166144e+07L),
+ static_cast<T>(-4.8527560179962773045e+03L),
+ static_cast<T>(1.0L),
+ };
+ static const T P2[] = {
+ static_cast<T>(-2.2210262233306573296e-04L),
+ static_cast<T>(1.3067392038106924055e-02L),
+ static_cast<T>(-4.4700805721174453923e-01L),
+ static_cast<T>(5.5674518371240761397e+00L),
+ static_cast<T>(-2.3517945679239481621e+01L),
+ static_cast<T>(3.1611322818701131207e+01L),
+ static_cast<T>(-9.6090021968656180000e+00L),
+ };
+ static const T Q2[] = {
+ static_cast<T>(-5.5194330231005480228e-04L),
+ static_cast<T>(3.2547697594819615062e-02L),
+ static_cast<T>(-1.1151759188741312645e+00L),
+ static_cast<T>(1.3982595353892851542e+01L),
+ static_cast<T>(-6.0228002066743340583e+01L),
+ static_cast<T>(8.5539563258012929600e+01L),
+ static_cast<T>(-3.1446690275135491500e+01L),
+ static_cast<T>(1.0L),
+ };
+ T value, factor, r;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ if (x < 0)
+ {
+ x = -x; // even function
+ }
+ if (x == 0)
+ {
+ return static_cast<T>(1);
+ }
+ if (x <= 15) // x in (0, 15]
+ {
+ T y = x * x;
+ value = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ }
+ else // x in (15, \infty)
+ {
+ T y = 1 / x - T(1) / 15;
+ r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = exp(x) / sqrt(x);
+ value = factor * r;
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_I0_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_i1.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_i1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,99 @@
+// 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
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/assert.hpp>
+
+// Modified Bessel function of the first kind of order one
+// minimax rational approximations on intervals, see
+// Blair and Edwards, Chalk River Report AECL-4928, 1974
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T>
+T bessel_i1(T x)
+{
+ static const T P1[] = {
+ static_cast<T>(-1.4577180278143463643e+15L),
+ static_cast<T>(-1.7732037840791591320e+14L),
+ static_cast<T>(-6.9876779648010090070e+12L),
+ static_cast<T>(-1.3357437682275493024e+11L),
+ static_cast<T>(-1.4828267606612366099e+09L),
+ static_cast<T>(-1.0588550724769347106e+07L),
+ static_cast<T>(-5.1894091982308017540e+04L),
+ static_cast<T>(-1.8225946631657315931e+02L),
+ static_cast<T>(-4.7207090827310162436e-01L),
+ static_cast<T>(-9.1746443287817501309e-04L),
+ static_cast<T>(-1.3466829827635152875e-06L),
+ static_cast<T>(-1.4831904935994647675e-09L),
+ static_cast<T>(-1.1928788903603238754e-12L),
+ static_cast<T>(-6.5245515583151902910e-16L),
+ static_cast<T>(-1.9705291802535139930e-19L),
+ };
+ static const T Q1[] = {
+ static_cast<T>(-2.9154360556286927285e+15L),
+ static_cast<T>(9.7887501377547640438e+12L),
+ static_cast<T>(-1.4386907088588283434e+10L),
+ static_cast<T>(1.1594225856856884006e+07L),
+ static_cast<T>(-5.1326864679904189920e+03L),
+ static_cast<T>(1.0L),
+ };
+ static const T P2[] = {
+ static_cast<T>(1.4582087408985668208e-05L),
+ static_cast<T>(-8.9359825138577646443e-04L),
+ static_cast<T>(2.9204895411257790122e-02L),
+ static_cast<T>(-3.4198728018058047439e-01L),
+ static_cast<T>(1.3960118277609544334e+00L),
+ static_cast<T>(-1.9746376087200685843e+00L),
+ static_cast<T>(8.5591872901933459000e-01L),
+ static_cast<T>(-6.0437159056137599999e-02L),
+ };
+ static const T Q2[] = {
+ static_cast<T>(3.7510433111922824643e-05L),
+ static_cast<T>(-2.2835624489492512649e-03L),
+ static_cast<T>(7.4212010813186530069e-02L),
+ static_cast<T>(-8.5017476463217924408e-01L),
+ static_cast<T>(3.2593714889036996297e+00L),
+ static_cast<T>(-3.8806586721556593450e+00L),
+ static_cast<T>(1.0L),
+ };
+ T value, factor, r, w;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ w = abs(x);
+ if (x == 0)
+ {
+ return static_cast<T>(0);
+ }
+ if (w <= 15) // w in (0, 15]
+ {
+ T y = x * x;
+ r = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ factor = w;
+ value = factor * r;
+ }
+ else // w in (15, \infty)
+ {
+ T y = 1 / w - T(1) / 15;
+ r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = exp(w) / sqrt(w);
+ value = factor * r;
+ }
+
+ if (x < 0)
+ {
+ value *= -value; // odd function
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_I1_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_ik.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_ik.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,331 @@
+// 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
+
+#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 {
+
+// 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 = tgamma1pm1(v, pol);
+ T gm = tgamma1pm1(-v, pol);
+
+ a = log(x / 2);
+ b = exp(v * a);
+ sigma = -a * v;
+ c = abs(v) < tools::epsilon<T>() ?
+ 1 : sin_pi(v) / (v * pi<T>());
+ d = abs(sigma) < tools::epsilon<T>() ?
+ 1 : sinh(sigma) / sigma;
+ gamma1 = abs(v) < tools::epsilon<T>() ?
+ -euler<T>() : (0.5f / v) * (gp - gm) * c;
+ gamma2 = (2 + gp + gm) * c / 2;
+
+ // initial values
+ p = (gp + 1) / (2 * b);
+ q = (1 + gm) * b / 2;
+ f = (cosh(sigma) * gamma1 + d * (-a) * gamma2) / c;
+ h = p;
+ coef = 1;
+ sum = coef * f;
+ sum1 = coef * h;
+
+ // series summation
+ tolerance = tools::epsilon<T>();
+ for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
+ {
+ f = (k * f + p + q) / (k*k - v*v);
+ p /= k - v;
+ q /= k + v;
+ h = p - k * f;
+ coef *= x * x / (4 * k);
+ sum += coef * f;
+ sum1 += coef * h;
+ if (abs(coef * f) < abs(sum) * tolerance)
+ {
+ break;
+ }
+ }
+ policies::check_series_iterations("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("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("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;
+ 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 = tools::real_cast<unsigned>(v + 0.5f);
+ 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 = sin_pi(z, pol) == 0 ?
+ Iv :
+ policies::raise_overflow_error<T>(function, 0, pol); // reflection formula
+ }
+
+ *I = Iv;
+ *K = Kv;
+ return 0;
+ }
+
+ // x is positive until reflection
+ W = 1 / x; // Wronskian
+ if (x <= 2) // x in (0, 2]
+ {
+ temme_ik(u, x, &Ku, &Ku1, pol); // Temme series
+ }
+ else // x in (2, \infty)
+ {
+ CF2_ik(u, x, &Ku, &Ku1, pol); // continued fraction CF2_ik
+ }
+ prev = Ku;
+ current = Ku1;
+ for (k = 1; k <= n; k++) // forward recurrence for K
+ {
+ next = 2 * (u + k) * current / x + prev;
+ prev = current;
+ current = next;
+ }
+ Kv = prev;
+ Kv1 = current;
+ if(kind & need_i)
+ {
+ T lim = (4 * v * v + 10) / (8 * x);
+ lim *= lim;
+ lim *= lim;
+ lim /= 24;
+ if((lim < tools::epsilon<T>() * 10) && (x > 100))
+ {
+ // x is huge compared to v, CF1 may be very slow
+ // to converge so use asymptotic expansion for large
+ // x case instead. Note that the asymptotic expansion
+ // isn't very accurate - so it's deliberately very hard
+ // to get here - probably we're going to overflow:
+ Iv = asymptotic_bessel_i_large_x(v, x, pol);
+ }
+ else
+ {
+ CF1_ik(v, x, &fv, pol); // continued fraction CF1_ik
+ Iv = 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);
+ *I = Iv + (2 / pi<T>()) * sin_pi(z) * Kv; // reflection formula
+ *K = Kv;
+ }
+ else
+ {
+ *I = Iv;
+ *K = Kv;
+ }
+ BOOST_MATH_INSTRUMENT_VARIABLE(*I);
+ BOOST_MATH_INSTRUMENT_VARIABLE(*K);
+ return 0;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_IK_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_j0.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_j0.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,147 @@
+// 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
+
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/assert.hpp>
+
+// Bessel function of the first kind of order zero
+// x <= 8, minimax rational approximations on root-bracketing intervals
+// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T>
+T bessel_j0(T x)
+{
+ static const T P1[] = {
+ static_cast<T>(-4.1298668500990866786e+11L),
+ static_cast<T>(2.7282507878605942706e+10L),
+ static_cast<T>(-6.2140700423540120665e+08L),
+ static_cast<T>(6.6302997904833794242e+06L),
+ static_cast<T>(-3.6629814655107086448e+04L),
+ static_cast<T>(1.0344222815443188943e+02L),
+ static_cast<T>(-1.2117036164593528341e-01L)
+ };
+ static const T Q1[] = {
+ static_cast<T>(2.3883787996332290397e+12L),
+ static_cast<T>(2.6328198300859648632e+10L),
+ static_cast<T>(1.3985097372263433271e+08L),
+ static_cast<T>(4.5612696224219938200e+05L),
+ static_cast<T>(9.3614022392337710626e+02L),
+ static_cast<T>(1.0L),
+ static_cast<T>(0.0L)
+ };
+ static const T P2[] = {
+ static_cast<T>(-1.8319397969392084011e+03L),
+ static_cast<T>(-1.2254078161378989535e+04L),
+ static_cast<T>(-7.2879702464464618998e+03L),
+ static_cast<T>(1.0341910641583726701e+04L),
+ static_cast<T>(1.1725046279757103576e+04L),
+ static_cast<T>(4.4176707025325087628e+03L),
+ static_cast<T>(7.4321196680624245801e+02L),
+ static_cast<T>(4.8591703355916499363e+01L)
+ };
+ static const T Q2[] = {
+ static_cast<T>(-3.5783478026152301072e+05L),
+ static_cast<T>(2.4599102262586308984e+05L),
+ static_cast<T>(-8.4055062591169562211e+04L),
+ static_cast<T>(1.8680990008359188352e+04L),
+ static_cast<T>(-2.9458766545509337327e+03L),
+ static_cast<T>(3.3307310774649071172e+02L),
+ static_cast<T>(-2.5258076240801555057e+01L),
+ static_cast<T>(1.0L)
+ };
+ static const T PC[] = {
+ static_cast<T>(2.2779090197304684302e+04L),
+ static_cast<T>(4.1345386639580765797e+04L),
+ static_cast<T>(2.1170523380864944322e+04L),
+ static_cast<T>(3.4806486443249270347e+03L),
+ static_cast<T>(1.5376201909008354296e+02L),
+ static_cast<T>(8.8961548424210455236e-01L)
+ };
+ static const T QC[] = {
+ static_cast<T>(2.2779090197304684318e+04L),
+ static_cast<T>(4.1370412495510416640e+04L),
+ static_cast<T>(2.1215350561880115730e+04L),
+ static_cast<T>(3.5028735138235608207e+03L),
+ static_cast<T>(1.5711159858080893649e+02L),
+ static_cast<T>(1.0L)
+ };
+ static const T PS[] = {
+ static_cast<T>(-8.9226600200800094098e+01L),
+ static_cast<T>(-1.8591953644342993800e+02L),
+ static_cast<T>(-1.1183429920482737611e+02L),
+ static_cast<T>(-2.2300261666214198472e+01L),
+ static_cast<T>(-1.2441026745835638459e+00L),
+ static_cast<T>(-8.8033303048680751817e-03L)
+ };
+ static const T QS[] = {
+ static_cast<T>(5.7105024128512061905e+03L),
+ static_cast<T>(1.1951131543434613647e+04L),
+ static_cast<T>(7.2642780169211018836e+03L),
+ static_cast<T>(1.4887231232283756582e+03L),
+ static_cast<T>(9.0593769594993125859e+01L),
+ static_cast<T>(1.0L)
+ };
+ static const T x1 = static_cast<T>(2.4048255576957727686e+00L),
+ x2 = static_cast<T>(5.5200781102863106496e+00L),
+ x11 = static_cast<T>(6.160e+02L),
+ x12 = static_cast<T>(-1.42444230422723137837e-03L),
+ x21 = static_cast<T>(1.4130e+03L),
+ x22 = static_cast<T>(5.46860286310649596604e-04L);
+
+ T value, factor, r, rc, rs;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ if (x < 0)
+ {
+ x = -x; // even function
+ }
+ if (x == 0)
+ {
+ return static_cast<T>(1);
+ }
+ if (x <= 4) // x in (0, 4]
+ {
+ T y = x * x;
+ BOOST_ASSERT(sizeof(P1) == sizeof(Q1));
+ r = evaluate_rational(P1, Q1, y);
+ factor = (x + x1) * ((x - x11/256) - x12);
+ value = factor * r;
+ }
+ else if (x <= 8.0) // x in (4, 8]
+ {
+ T y = 1 - (x * x)/64;
+ BOOST_ASSERT(sizeof(P2) == sizeof(Q2));
+ r = evaluate_rational(P2, Q2, y);
+ factor = (x + x2) * ((x - x21/256) - x22);
+ value = factor * r;
+ }
+ else // x in (8, \infty)
+ {
+ T y = 8 / x;
+ T y2 = y * y;
+ T z = x - 0.25f * pi<T>();
+ BOOST_ASSERT(sizeof(PC) == sizeof(QC));
+ BOOST_ASSERT(sizeof(PS) == sizeof(QS));
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (x * pi<T>()));
+ value = factor * (rc * cos(z) - y * rs * sin(z));
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_J0_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_j1.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_j1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,152 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_J1_HPP
+#define BOOST_MATH_BESSEL_J1_HPP
+
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/assert.hpp>
+
+// Bessel function of the first kind of order one
+// x <= 8, minimax rational approximations on root-bracketing intervals
+// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
+
+namespace boost { namespace math{ namespace detail{
+
+template <typename T>
+T bessel_j1(T x)
+{
+ static const T P1[] = {
+ static_cast<T>(-1.4258509801366645672e+11L),
+ static_cast<T>(6.6781041261492395835e+09L),
+ static_cast<T>(-1.1548696764841276794e+08L),
+ static_cast<T>(9.8062904098958257677e+05L),
+ static_cast<T>(-4.4615792982775076130e+03L),
+ static_cast<T>(1.0650724020080236441e+01L),
+ static_cast<T>(-1.0767857011487300348e-02L)
+ };
+ static const T Q1[] = {
+ static_cast<T>(4.1868604460820175290e+12L),
+ static_cast<T>(4.2091902282580133541e+10L),
+ static_cast<T>(2.0228375140097033958e+08L),
+ static_cast<T>(5.9117614494174794095e+05L),
+ static_cast<T>(1.0742272239517380498e+03L),
+ static_cast<T>(1.0L),
+ static_cast<T>(0.0L)
+ };
+ static const T P2[] = {
+ static_cast<T>(-1.7527881995806511112e+16L),
+ static_cast<T>(1.6608531731299018674e+15L),
+ static_cast<T>(-3.6658018905416665164e+13L),
+ static_cast<T>(3.5580665670910619166e+11L),
+ static_cast<T>(-1.8113931269860667829e+09L),
+ static_cast<T>(5.0793266148011179143e+06L),
+ static_cast<T>(-7.5023342220781607561e+03L),
+ static_cast<T>(4.6179191852758252278e+00L)
+ };
+ static const T Q2[] = {
+ static_cast<T>(1.7253905888447681194e+18L),
+ static_cast<T>(1.7128800897135812012e+16L),
+ static_cast<T>(8.4899346165481429307e+13L),
+ static_cast<T>(2.7622777286244082666e+11L),
+ static_cast<T>(6.4872502899596389593e+08L),
+ static_cast<T>(1.1267125065029138050e+06L),
+ static_cast<T>(1.3886978985861357615e+03L),
+ static_cast<T>(1.0L)
+ };
+ static const T PC[] = {
+ static_cast<T>(-4.4357578167941278571e+06L),
+ static_cast<T>(-9.9422465050776411957e+06L),
+ static_cast<T>(-6.6033732483649391093e+06L),
+ static_cast<T>(-1.5235293511811373833e+06L),
+ static_cast<T>(-1.0982405543459346727e+05L),
+ static_cast<T>(-1.6116166443246101165e+03L),
+ static_cast<T>(0.0L)
+ };
+ static const T QC[] = {
+ static_cast<T>(-4.4357578167941278568e+06L),
+ static_cast<T>(-9.9341243899345856590e+06L),
+ static_cast<T>(-6.5853394797230870728e+06L),
+ static_cast<T>(-1.5118095066341608816e+06L),
+ static_cast<T>(-1.0726385991103820119e+05L),
+ static_cast<T>(-1.4550094401904961825e+03L),
+ static_cast<T>(1.0L)
+ };
+ static const T PS[] = {
+ static_cast<T>(3.3220913409857223519e+04L),
+ static_cast<T>(8.5145160675335701966e+04L),
+ static_cast<T>(6.6178836581270835179e+04L),
+ static_cast<T>(1.8494262873223866797e+04L),
+ static_cast<T>(1.7063754290207680021e+03L),
+ static_cast<T>(3.5265133846636032186e+01L),
+ static_cast<T>(0.0L)
+ };
+ static const T QS[] = {
+ static_cast<T>(7.0871281941028743574e+05L),
+ static_cast<T>(1.8194580422439972989e+06L),
+ static_cast<T>(1.4194606696037208929e+06L),
+ static_cast<T>(4.0029443582266975117e+05L),
+ static_cast<T>(3.7890229745772202641e+04L),
+ static_cast<T>(8.6383677696049909675e+02L),
+ static_cast<T>(1.0L)
+ };
+ static const T x1 = static_cast<T>(3.8317059702075123156e+00L),
+ x2 = static_cast<T>(7.0155866698156187535e+00L),
+ x11 = static_cast<T>(9.810e+02L),
+ x12 = static_cast<T>(-3.2527979248768438556e-04L),
+ x21 = static_cast<T>(1.7960e+03L),
+ x22 = static_cast<T>(-3.8330184381246462950e-05L);
+
+ T value, factor, r, rc, rs, w;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ w = abs(x);
+ if (x == 0)
+ {
+ return static_cast<T>(0);
+ }
+ if (w <= 4) // w in (0, 4]
+ {
+ T y = x * x;
+ BOOST_ASSERT(sizeof(P1) == sizeof(Q1));
+ r = evaluate_rational(P1, Q1, y);
+ factor = w * (w + x1) * ((w - x11/256) - x12);
+ value = factor * r;
+ }
+ else if (w <= 8) // w in (4, 8]
+ {
+ T y = x * x;
+ BOOST_ASSERT(sizeof(P2) == sizeof(Q2));
+ r = evaluate_rational(P2, Q2, y);
+ factor = w * (w + x2) * ((w - x21/256) - x22);
+ value = factor * r;
+ }
+ else // w in (8, \infty)
+ {
+ T y = 8 / w;
+ T y2 = y * y;
+ T z = w - 0.75f * pi<T>();
+ BOOST_ASSERT(sizeof(PC) == sizeof(QC));
+ BOOST_ASSERT(sizeof(PS) == sizeof(QS));
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (w * pi<T>()));
+ value = factor * (rc * cos(z) - y * rs * sin(z));
+ }
+
+ if (x < 0)
+ {
+ value *= -1; // odd function
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_J1_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_jn.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_jn.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,86 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_JN_HPP
+#define BOOST_MATH_BESSEL_JN_HPP
+
+#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>
+
+// 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
+
+ if (n == 0)
+ {
+ return bessel_j0(x);
+ }
+ if (n == 1)
+ {
+ return bessel_j1(x);
+ }
+ if (n < 0)
+ {
+ factor = (n & 0x1) ? -1 : 1; // J_{-n}(z) = (-1)^n J_n(z)
+ n = -n;
+ }
+ else
+ {
+ factor = 1;
+ }
+
+ if (x == 0) // n >= 2
+ {
+ return static_cast<T>(0);
+ }
+
+ if (n < abs(x)) // forward recurrence
+ {
+ prev = bessel_j0(x);
+ current = bessel_j1(x);
+ for (int k = 1; k < n; k++)
+ {
+ value = 2 * k * current / x - prev;
+ prev = current;
+ current = value;
+ }
+ }
+ 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);
+ // tiny initial value to prevent overflow
+ T init = sqrt(tools::min_value<T>());
+ prev = fn * init;
+ current = init;
+ for (int k = n; k > 0; k--)
+ {
+ next = 2 * k * current / x - prev;
+ prev = current;
+ current = next;
+ }
+ T ratio = init / current; // scaling ratio
+ value = bessel_j0(x) * ratio; // normalization
+ }
+ value *= factor;
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_JN_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_jy.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_jy.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,361 @@
+// 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
+
+#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/simple_complex.hpp>
+#include <boost/math/special_functions/detail/bessel_jy_asym.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 {
+
+// 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 = tgamma1pm1(v, pol);
+ T gm = tgamma1pm1(-v, pol);
+ T spv = sin_pi(v, pol);
+ T spv2 = 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>() ? v*pi<T>()*pi<T>() / 2
+ : 2 * spv2 * spv2 / v;
+
+ T g1 = (v == 0) ? -euler<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>()) ? 1/constants::pi<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 = tools::epsilon<T>();
+ 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("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 * tools::epsilon<T>();
+ tiny = sqrt(tools::min_value<T>());
+ C = f = tiny; // b0 = 0, replace with tiny
+ D = 0.0L;
+ 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.0L) < tolerance)
+ { break; }
+ }
+ policies::check_series_iterations("boost::math::bessel_jy<%1%>(%1%,%1%) in CF1_jy", k / 100, pol);
+ *fv = -f;
+ *sign = s; // sign of denominator
+
+ return 0;
+}
+
+template <class T>
+struct complex_trait
+{
+ typedef typename mpl::if_<is_floating_point<T>,
+ std::complex<T>, sc::simple_complex<T> >::type type;
+};
+
+// Evaluate continued fraction p + iq = (J' + iY') / (J + iY), see
+// Press et al, Numerical Recipes in C, 2nd edition, 1992
+template <typename T, typename Policy>
+int CF2_jy(T v, T x, T* p, T* q, const Policy& pol)
+{
+ BOOST_MATH_STD_USING
+
+ typedef typename complex_trait<T>::type complex_type;
+
+ complex_type C, D, f, a, b, delta, one(1);
+ T tiny, zero(0.0L);
+ 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 * tools::epsilon<T>();
+ tiny = sqrt(tools::min_value<T>());
+ C = f = complex_type(-0.5f/x, 1.0L);
+ D = 0;
+ for (k = 1; k < policies::get_max_series_iterations<Policy>(); k++)
+ {
+ a = (k - 0.5f)*(k - 0.5f) - v*v;
+ if (k == 1)
+ {
+ a *= complex_type(T(0), 1/x);
+ }
+ b = complex_type(2*x, T(2*k));
+ C = b + a / C;
+ D = b + a * D;
+ if (C == zero) { C = tiny; }
+ if (D == zero) { D = tiny; }
+ D = one / D;
+ delta = C * D;
+ f *= delta;
+ if (abs(delta - one) < tolerance) { break; }
+ }
+ policies::check_series_iterations("boost::math::bessel_jy<%1%>(%1%,%1%) in CF2_jy", k, pol);
+ *p = real(f);
+ *q = imag(f);
+
+ 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;
+
+ 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 = real_cast<unsigned>(v + 0.5L);
+ u = v - n; // -1/2 <= u < 1/2
+
+ 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
+ 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;
+ for (k = 1; k <= n; k++) // forward recurrence for Y
+ {
+ next = 2 * (u + k) * current / x - 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 = W / (Yv * fv - Yv1); // Wronskian relation
+ }
+ else
+ Jv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
+ }
+ 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;
+ 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(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;
+ for (k = n; k > 0; k--) // backward recurrence for J
+ {
+ next = 2 * (u + k) * current / x - prev;
+ prev = current;
+ current = next;
+ }
+ T ratio = (s * init) / current; // scaling ratio
+ // can also call CF1_jy() to get fu, not much difference in precision
+ fu = prev / current;
+ 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
+ {
+ next = 2 * (u + k) * current / x - 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)
+ {
+ T z = (u + n % 2);
+ *J = cos_pi(z, pol) * Jv - sin_pi(z, pol) * Yv; // reflection formula
+ *Y = sin_pi(z, pol) * Jv + cos_pi(z, pol) * Yv;
+ }
+ else
+ {
+ *J = Jv;
+ *Y = Yv;
+ }
+
+ return 0;
+}
+
+} // namespace detail
+
+}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_JY_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_jy_asym.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_jy_asym.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,297 @@
+// 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
+
+#include <boost/math/special_functions/factorials.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+template <class T>
+inline T asymptotic_bessel_j_large_x_P(T v, T x)
+{
+ // A&S 9.2.9
+ T s = 1;
+ T mu = 4 * v * v;
+ T ez2 = 8 * x;
+ ez2 *= ez2;
+ s -= (mu-1) * (mu-9) / (2 * ez2);
+ s += (mu-1) * (mu-9) * (mu-25) * (mu - 49) / (24 * ez2 * ez2);
+ return s;
+}
+
+template <class T>
+inline T asymptotic_bessel_j_large_x_Q(T v, T x)
+{
+ // A&S 9.2.10
+ T s = 0;
+ T mu = 4 * v * v;
+ T ez = 8*x;
+ s += (mu-1) / ez;
+ s -= (mu-1) * (mu-9) * (mu-25) / (6 * ez*ez*ez);
+ return s;
+}
+
+template <class T>
+inline T asymptotic_bessel_j_large_x(T v, T x)
+{
+ //
+ // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
+ //
+ // Also A&S 9.2.5
+ //
+ BOOST_MATH_STD_USING // ADL of std names
+ T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
+ return sqrt(2 / (constants::pi<T>() * x))
+ * (asymptotic_bessel_j_large_x_P(v, x) * cos(chi)
+ - asymptotic_bessel_j_large_x_Q(v, x) * sin(chi));
+}
+
+template <class T>
+inline T asymptotic_bessel_y_large_x(T v, T x)
+{
+ //
+ // See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
+ //
+ // Also A&S 9.2.5
+ //
+ BOOST_MATH_STD_USING // ADL of std names
+ T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
+ return sqrt(2 / (constants::pi<T>() * x))
+ * (asymptotic_bessel_j_large_x_P(v, x) * sin(chi)
+ - asymptotic_bessel_j_large_x_Q(v, x) * cos(chi));
+}
+
+template <class T>
+inline T asymptotic_bessel_amplitude(T v, T x)
+{
+ // Calculate the amplitude of J(v, x) and Y(v, x) for large
+ // x: see A&S 9.2.28.
+ BOOST_MATH_STD_USING
+ T s = 1;
+ T mu = 4 * v * v;
+ T txq = 2 * x;
+ txq *= txq;
+
+ s += (mu - 1) / (2 * txq);
+ s += 3 * (mu - 1) * (mu - 9) / (txq * txq * 8);
+ s += 15 * (mu - 1) * (mu - 9) * (mu - 25) / (txq * txq * txq * 8 * 6);
+
+ return sqrt(s * 2 / (constants::pi<T>() * x));
+}
+
+template <class T>
+T asymptotic_bessel_phase_mx(T v, T x)
+{
+ //
+ // Calculate the phase of J(v, x) and Y(v, x) for large x.
+ // See A&S 9.2.29.
+ // Note that the result returned is the phase less x.
+ //
+ T mu = 4 * v * v;
+ T denom = 4 * x;
+ T denom_mult = denom * denom;
+
+ T s = -constants::pi<T>() * (v / 2 + 0.25f);
+ s += (mu - 1) / (2 * denom);
+ denom *= denom_mult;
+ s += (mu - 1) * (mu - 25) / (6 * denom);
+ denom *= denom_mult;
+ s += (mu - 1) * (mu * mu - 114 * mu + 1073) / (5 * denom);
+ denom *= denom_mult;
+ s += (mu - 1) * (5 * mu * mu * mu - 1535 * mu * mu + 54703 * mu - 375733) / (14 * denom);
+ return s;
+}
+
+template <class T>
+inline T asymptotic_bessel_y_large_x_2(T v, T x)
+{
+ // See A&S 9.2.19.
+ BOOST_MATH_STD_USING
+ // Get the phase and amplitude:
+ T ampl = asymptotic_bessel_amplitude(v, x);
+ T phase = asymptotic_bessel_phase_mx(v, x);
+ //
+ // Calculate the sine of the phase, using:
+ // sin(x+p) = sin(x)cos(p) + cos(x)sin(p)
+ //
+ T sin_phase = sin(phase) * cos(x) + cos(phase) * sin(x);
+ return sin_phase * ampl;
+}
+
+template <class T>
+inline T asymptotic_bessel_j_large_x_2(T v, T x)
+{
+ // See A&S 9.2.19.
+ BOOST_MATH_STD_USING
+ // Get the phase and amplitude:
+ T ampl = asymptotic_bessel_amplitude(v, x);
+ T phase = asymptotic_bessel_phase_mx(v, x);
+ //
+ // Calculate the sine of the phase, using:
+ // cos(x+p) = cos(x)cos(p) - sin(x)sin(p)
+ //
+ T sin_phase = cos(phase) * cos(x) - sin(phase) * sin(x);
+ return sin_phase * ampl;
+}
+
+//
+// Various limits for the J and Y asymptotics
+// (the asympotic expansions are safe to use if
+// x is less than the limit given).
+// We assume that if we don't use these expansions then the
+// error will likely be >100eps, so the limits given are chosen
+// to lead to < 100eps truncation error.
+//
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<0>&)
+{
+ // default case:
+ BOOST_MATH_STD_USING
+ return 2.25 / pow(100 * tools::epsilon<T>() / T(0.001f), T(0.2f));
+}
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<53>&)
+{
+ // double case:
+ return 304 /*780*/;
+}
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<64>&)
+{
+ // 80-bit extended-double case:
+ return 1552 /*3500*/;
+}
+template <class T>
+inline T asymptotic_bessel_y_limit(const mpl::int_<113>&)
+{
+ // 128-bit long double case:
+ return 1245243 /*3128000*/;
+}
+
+template <class T, class Policy>
+struct bessel_asymptotic_tag
+{
+ typedef typename policies::precision<T, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::or_<
+ mpl::equal_to<precision_type, mpl::int_<0> >,
+ mpl::greater<precision_type, mpl::int_<113> > >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::greater<precision_type, mpl::int_<64> >,
+ mpl::int_<113>,
+ typename mpl::if_<
+ mpl::greater<precision_type, mpl::int_<53> >,
+ mpl::int_<64>,
+ mpl::int_<53>
+ >::type
+ >::type
+ >::type type;
+};
+
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<0>&)
+{
+ // default case:
+ BOOST_MATH_STD_USING
+ T v2 = (std::max)(T(3), v * v);
+ return v2 / pow(100 * tools::epsilon<T>() / T(2e-5f), T(0.17f));
+}
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<53>&)
+{
+ // double case:
+ T v2 = (std::max)(T(3), v * v);
+ return v2 * 33 /*73*/;
+}
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<64>&)
+{
+ // 80-bit extended-double case:
+ T v2 = (std::max)(T(3), v * v);
+ return v2 * 121 /*266*/;
+}
+template <class T>
+inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<113>&)
+{
+ // 128-bit long double case:
+ T v2 = (std::max)(T(3), v * v);
+ return v2 * 39154 /*85700*/;
+}
+
+template <class T, class Policy>
+void temme_asyptotic_y_small_x(T v, T x, T* Y, T* Y1, const Policy& pol)
+{
+ T c = 1;
+ T p = (v / sin_pi(v, pol)) * pow(x / 2, -v) / tgamma(1 - v, pol);
+ T q = (v / sin_pi(v, pol)) * pow(x / 2, v) / tgamma(1 + v, pol);
+ T f = (p - q) / v;
+ T g_prefix = 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
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_k0.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_k0.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,116 @@
+// 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
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/assert.hpp>
+
+// Modified Bessel function of the second kind of order zero
+// minimax rational approximations on intervals, see
+// Russon and Blair, Chalk River Report AECL-3461, 1969
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_k0(T x, const Policy& pol)
+{
+ BOOST_MATH_INSTRUMENT_CODE(x);
+
+ static const T P1[] = {
+ static_cast<T>(2.4708152720399552679e+03L),
+ static_cast<T>(5.9169059852270512312e+03L),
+ static_cast<T>(4.6850901201934832188e+02L),
+ static_cast<T>(1.1999463724910714109e+01L),
+ static_cast<T>(1.3166052564989571850e-01L),
+ static_cast<T>(5.8599221412826100000e-04L)
+ };
+ static const T Q1[] = {
+ static_cast<T>(2.1312714303849120380e+04L),
+ static_cast<T>(-2.4994418972832303646e+02L),
+ static_cast<T>(1.0L)
+ };
+ static const T P2[] = {
+ static_cast<T>(-1.6128136304458193998e+06L),
+ static_cast<T>(-3.7333769444840079748e+05L),
+ static_cast<T>(-1.7984434409411765813e+04L),
+ static_cast<T>(-2.9501657892958843865e+02L),
+ static_cast<T>(-1.6414452837299064100e+00L)
+ };
+ static const T Q2[] = {
+ static_cast<T>(-1.6128136304458193998e+06L),
+ static_cast<T>(2.9865713163054025489e+04L),
+ static_cast<T>(-2.5064972445877992730e+02L),
+ static_cast<T>(1.0L)
+ };
+ static const T P3[] = {
+ static_cast<T>(1.1600249425076035558e+02L),
+ static_cast<T>(2.3444738764199315021e+03L),
+ static_cast<T>(1.8321525870183537725e+04L),
+ static_cast<T>(7.1557062783764037541e+04L),
+ static_cast<T>(1.5097646353289914539e+05L),
+ static_cast<T>(1.7398867902565686251e+05L),
+ static_cast<T>(1.0577068948034021957e+05L),
+ static_cast<T>(3.1075408980684392399e+04L),
+ static_cast<T>(3.6832589957340267940e+03L),
+ static_cast<T>(1.1394980557384778174e+02L)
+ };
+ static const T Q3[] = {
+ static_cast<T>(9.2556599177304839811e+01L),
+ static_cast<T>(1.8821890840982713696e+03L),
+ static_cast<T>(1.4847228371802360957e+04L),
+ static_cast<T>(5.8824616785857027752e+04L),
+ static_cast<T>(1.2689839587977598727e+05L),
+ static_cast<T>(1.5144644673520157801e+05L),
+ static_cast<T>(9.7418829762268075784e+04L),
+ static_cast<T>(3.1474655750295278825e+04L),
+ static_cast<T>(4.4329628889746408858e+03L),
+ static_cast<T>(2.0013443064949242491e+02L),
+ static_cast<T>(1.0L)
+ };
+ T value, factor, r, r1, r2;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::bessel_k0<%1%>(%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got x = %1%, but argument x must be non-negative, complex number result not supported", x, pol);
+ }
+ if (x == 0)
+ {
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ if (x <= 1) // x in (0, 1]
+ {
+ T y = x * x;
+ r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = log(x);
+ value = r1 - factor * r2;
+ }
+ else // x in (1, \infty)
+ {
+ T y = 1 / x;
+ r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
+ factor = exp(-x) / sqrt(x);
+ value = factor * r;
+ BOOST_MATH_INSTRUMENT_CODE("y = " << y);
+ BOOST_MATH_INSTRUMENT_CODE("r = " << r);
+ BOOST_MATH_INSTRUMENT_CODE("factor = " << factor);
+ BOOST_MATH_INSTRUMENT_CODE("value = " << value);
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_K0_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_k1.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_k1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,112 @@
+// Copyright (c) 2006 Xiaogang Zhang
+// Use, modification and distribution are subject to the
+// Boost Software License, Version 1.0. (See accompanying file
+// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_MATH_BESSEL_K1_HPP
+#define BOOST_MATH_BESSEL_K1_HPP
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/assert.hpp>
+
+// Modified Bessel function of the second kind of order one
+// minimax rational approximations on intervals, see
+// Russon and Blair, Chalk River Report AECL-3461, 1969
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_k1(T x, const Policy& pol)
+{
+ static const T P1[] = {
+ static_cast<T>(-2.2149374878243304548e+06L),
+ static_cast<T>(7.1938920065420586101e+05L),
+ static_cast<T>(1.7733324035147015630e+05L),
+ static_cast<T>(7.1885382604084798576e+03L),
+ static_cast<T>(9.9991373567429309922e+01L),
+ static_cast<T>(4.8127070456878442310e-01L)
+ };
+ static const T Q1[] = {
+ static_cast<T>(-2.2149374878243304548e+06L),
+ static_cast<T>(3.7264298672067697862e+04L),
+ static_cast<T>(-2.8143915754538725829e+02L),
+ static_cast<T>(1.0L)
+ };
+ static const T P2[] = {
+ static_cast<T>(0.0L),
+ static_cast<T>(-1.3531161492785421328e+06L),
+ static_cast<T>(-1.4758069205414222471e+05L),
+ static_cast<T>(-4.5051623763436087023e+03L),
+ static_cast<T>(-5.3103913335180275253e+01L),
+ static_cast<T>(-2.2795590826955002390e-01L)
+ };
+ static const T Q2[] = {
+ static_cast<T>(-2.7062322985570842656e+06L),
+ static_cast<T>(4.3117653211351080007e+04L),
+ static_cast<T>(-3.0507151578787595807e+02L),
+ static_cast<T>(1.0L)
+ };
+ static const T P3[] = {
+ static_cast<T>(2.2196792496874548962e+00L),
+ static_cast<T>(4.4137176114230414036e+01L),
+ static_cast<T>(3.4122953486801312910e+02L),
+ static_cast<T>(1.3319486433183221990e+03L),
+ static_cast<T>(2.8590657697910288226e+03L),
+ static_cast<T>(3.4540675585544584407e+03L),
+ static_cast<T>(2.3123742209168871550e+03L),
+ static_cast<T>(8.1094256146537402173e+02L),
+ static_cast<T>(1.3182609918569941308e+02L),
+ static_cast<T>(7.5584584631176030810e+00L),
+ static_cast<T>(6.4257745859173138767e-02L)
+ };
+ static const T Q3[] = {
+ static_cast<T>(1.7710478032601086579e+00L),
+ static_cast<T>(3.4552228452758912848e+01L),
+ static_cast<T>(2.5951223655579051357e+02L),
+ static_cast<T>(9.6929165726802648634e+02L),
+ static_cast<T>(1.9448440788918006154e+03L),
+ static_cast<T>(2.1181000487171943810e+03L),
+ static_cast<T>(1.2082692316002348638e+03L),
+ static_cast<T>(3.3031020088765390854e+02L),
+ static_cast<T>(3.6001069306861518855e+01L),
+ static_cast<T>(1.0L)
+ };
+ T value, factor, r, r1, r2;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+
+ static const char* function = "boost::math::bessel_k1<%1%>(%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol);
+ }
+ if (x == 0)
+ {
+ return policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ if (x <= 1) // x in (0, 1]
+ {
+ T y = x * x;
+ r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
+ r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
+ factor = log(x);
+ value = (r1 + factor * r2) / x;
+ }
+ else // x in (1, \infty)
+ {
+ T y = 1 / x;
+ r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
+ factor = exp(-x) / sqrt(x);
+ value = factor * r;
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_K1_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_kn.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_kn.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,69 @@
+// 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
+
+#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);
+ do
+ {
+ value = 2 * k * current / x + prev;
+ prev = current;
+ current = value;
+ ++k;
+ }
+ while(k < n);
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_KN_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_y0.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_y0.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,177 @@
+// 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
+
+#include <boost/math/special_functions/detail/bessel_j0.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/assert.hpp>
+
+// Bessel function of the second kind of order zero
+// x <= 8, minimax rational approximations on root-bracketing intervals
+// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_y0(T x, const Policy& pol)
+{
+ static const T P1[] = {
+ static_cast<T>(1.0723538782003176831e+11L),
+ static_cast<T>(-8.3716255451260504098e+09L),
+ static_cast<T>(2.0422274357376619816e+08L),
+ static_cast<T>(-2.1287548474401797963e+06L),
+ static_cast<T>(1.0102532948020907590e+04L),
+ static_cast<T>(-1.8402381979244993524e+01L),
+ };
+ static const T Q1[] = {
+ static_cast<T>(5.8873865738997033405e+11L),
+ static_cast<T>(8.1617187777290363573e+09L),
+ static_cast<T>(5.5662956624278251596e+07L),
+ static_cast<T>(2.3889393209447253406e+05L),
+ static_cast<T>(6.6475986689240190091e+02L),
+ static_cast<T>(1.0L),
+ };
+ static const T P2[] = {
+ static_cast<T>(-2.2213976967566192242e+13L),
+ static_cast<T>(-5.5107435206722644429e+11L),
+ static_cast<T>(4.3600098638603061642e+10L),
+ static_cast<T>(-6.9590439394619619534e+08L),
+ static_cast<T>(4.6905288611678631510e+06L),
+ static_cast<T>(-1.4566865832663635920e+04L),
+ static_cast<T>(1.7427031242901594547e+01L),
+ };
+ static const T Q2[] = {
+ static_cast<T>(4.3386146580707264428e+14L),
+ static_cast<T>(5.4266824419412347550e+12L),
+ static_cast<T>(3.4015103849971240096e+10L),
+ static_cast<T>(1.3960202770986831075e+08L),
+ static_cast<T>(4.0669982352539552018e+05L),
+ static_cast<T>(8.3030857612070288823e+02L),
+ static_cast<T>(1.0L),
+ };
+ static const T P3[] = {
+ static_cast<T>(-8.0728726905150210443e+15L),
+ static_cast<T>(6.7016641869173237784e+14L),
+ static_cast<T>(-1.2829912364088687306e+11L),
+ static_cast<T>(-1.9363051266772083678e+11L),
+ static_cast<T>(2.1958827170518100757e+09L),
+ static_cast<T>(-1.0085539923498211426e+07L),
+ static_cast<T>(2.1363534169313901632e+04L),
+ static_cast<T>(-1.7439661319197499338e+01L),
+ };
+ static const T Q3[] = {
+ static_cast<T>(3.4563724628846457519e+17L),
+ static_cast<T>(3.9272425569640309819e+15L),
+ static_cast<T>(2.2598377924042897629e+13L),
+ static_cast<T>(8.6926121104209825246e+10L),
+ static_cast<T>(2.4727219475672302327e+08L),
+ static_cast<T>(5.3924739209768057030e+05L),
+ static_cast<T>(8.7903362168128450017e+02L),
+ static_cast<T>(1.0L),
+ };
+ static const T PC[] = {
+ static_cast<T>(2.2779090197304684302e+04L),
+ static_cast<T>(4.1345386639580765797e+04L),
+ static_cast<T>(2.1170523380864944322e+04L),
+ static_cast<T>(3.4806486443249270347e+03L),
+ static_cast<T>(1.5376201909008354296e+02L),
+ static_cast<T>(8.8961548424210455236e-01L),
+ };
+ static const T QC[] = {
+ static_cast<T>(2.2779090197304684318e+04L),
+ static_cast<T>(4.1370412495510416640e+04L),
+ static_cast<T>(2.1215350561880115730e+04L),
+ static_cast<T>(3.5028735138235608207e+03L),
+ static_cast<T>(1.5711159858080893649e+02L),
+ static_cast<T>(1.0L),
+ };
+ static const T PS[] = {
+ static_cast<T>(-8.9226600200800094098e+01L),
+ static_cast<T>(-1.8591953644342993800e+02L),
+ static_cast<T>(-1.1183429920482737611e+02L),
+ static_cast<T>(-2.2300261666214198472e+01L),
+ static_cast<T>(-1.2441026745835638459e+00L),
+ static_cast<T>(-8.8033303048680751817e-03L),
+ };
+ static const T QS[] = {
+ static_cast<T>(5.7105024128512061905e+03L),
+ static_cast<T>(1.1951131543434613647e+04L),
+ static_cast<T>(7.2642780169211018836e+03L),
+ static_cast<T>(1.4887231232283756582e+03L),
+ static_cast<T>(9.0593769594993125859e+01L),
+ static_cast<T>(1.0L),
+ };
+ static const T x1 = static_cast<T>(8.9357696627916752158e-01L),
+ x2 = static_cast<T>(3.9576784193148578684e+00L),
+ x3 = static_cast<T>(7.0860510603017726976e+00L),
+ x11 = static_cast<T>(2.280e+02L),
+ x12 = static_cast<T>(2.9519662791675215849e-03L),
+ x21 = static_cast<T>(1.0130e+03L),
+ x22 = static_cast<T>(6.4716931485786837568e-04L),
+ x31 = static_cast<T>(1.8140e+03L),
+ x32 = static_cast<T>(1.1356030177269762362e-04L)
+ ;
+ T value, factor, r, rc, rs;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ static const char* function = "boost::math::bessel_y0<%1%>(%1%,%1%)";
+
+ if (x < 0)
+ {
+ return policies::raise_domain_error<T>(function,
+ "Got x = %1% but x must be non-negative, complex result not supported.", x, pol);
+ }
+ if (x == 0)
+ {
+ return -policies::raise_overflow_error<T>(function, 0, pol);
+ }
+ if (x <= 3) // x in (0, 3]
+ {
+ T y = x * x;
+ T z = 2 * log(x/x1) * bessel_j0(x) / pi<T>();
+ r = evaluate_rational(P1, Q1, y);
+ factor = (x + x1) * ((x - x11/256) - x12);
+ value = z + factor * r;
+ }
+ else if (x <= 5.5f) // x in (3, 5.5]
+ {
+ T y = x * x;
+ T z = 2 * log(x/x2) * bessel_j0(x) / pi<T>();
+ r = evaluate_rational(P2, Q2, y);
+ factor = (x + x2) * ((x - x21/256) - x22);
+ value = z + factor * r;
+ }
+ else if (x <= 8) // x in (5.5, 8]
+ {
+ T y = x * x;
+ T z = 2 * log(x/x3) * bessel_j0(x) / pi<T>();
+ r = evaluate_rational(P3, Q3, y);
+ factor = (x + x3) * ((x - x31/256) - x32);
+ value = z + factor * r;
+ }
+ else // x in (8, \infty)
+ {
+ T y = 8 / x;
+ T y2 = y * y;
+ T z = x - 0.25f * pi<T>();
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (x * pi<T>()));
+ value = factor * (rc * sin(z) + y * rs * cos(z));
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_Y0_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_y1.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_y1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,150 @@
+// 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
+
+#include <boost/math/special_functions/detail/bessel_j1.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/assert.hpp>
+
+// Bessel function of the second kind of order one
+// x <= 8, minimax rational approximations on root-bracketing intervals
+// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
+
+namespace boost { namespace math { namespace detail{
+
+template <typename T, typename Policy>
+T bessel_y1(T x, const Policy& pol)
+{
+ static const T P1[] = {
+ static_cast<T>(4.0535726612579544093e+13L),
+ static_cast<T>(5.4708611716525426053e+12L),
+ static_cast<T>(-3.7595974497819597599e+11L),
+ static_cast<T>(7.2144548214502560419e+09L),
+ static_cast<T>(-5.9157479997408395984e+07L),
+ static_cast<T>(2.2157953222280260820e+05L),
+ static_cast<T>(-3.1714424660046133456e+02L),
+ };
+ static const T Q1[] = {
+ static_cast<T>(3.0737873921079286084e+14L),
+ static_cast<T>(4.1272286200406461981e+12L),
+ static_cast<T>(2.7800352738690585613e+10L),
+ static_cast<T>(1.2250435122182963220e+08L),
+ static_cast<T>(3.8136470753052572164e+05L),
+ static_cast<T>(8.2079908168393867438e+02L),
+ static_cast<T>(1.0L),
+ };
+ static const T P2[] = {
+ static_cast<T>(1.1514276357909013326e+19L),
+ static_cast<T>(-5.6808094574724204577e+18L),
+ static_cast<T>(-2.3638408497043134724e+16L),
+ static_cast<T>(4.0686275289804744814e+15L),
+ static_cast<T>(-5.9530713129741981618e+13L),
+ static_cast<T>(3.7453673962438488783e+11L),
+ static_cast<T>(-1.1957961912070617006e+09L),
+ static_cast<T>(1.9153806858264202986e+06L),
+ static_cast<T>(-1.2337180442012953128e+03L),
+ };
+ static const T Q2[] = {
+ static_cast<T>(5.3321844313316185697e+20L),
+ static_cast<T>(5.6968198822857178911e+18L),
+ static_cast<T>(3.0837179548112881950e+16L),
+ static_cast<T>(1.1187010065856971027e+14L),
+ static_cast<T>(3.0221766852960403645e+11L),
+ static_cast<T>(6.3550318087088919566e+08L),
+ static_cast<T>(1.0453748201934079734e+06L),
+ static_cast<T>(1.2855164849321609336e+03L),
+ static_cast<T>(1.0L),
+ };
+ static const T PC[] = {
+ static_cast<T>(-4.4357578167941278571e+06L),
+ static_cast<T>(-9.9422465050776411957e+06L),
+ static_cast<T>(-6.6033732483649391093e+06L),
+ static_cast<T>(-1.5235293511811373833e+06L),
+ static_cast<T>(-1.0982405543459346727e+05L),
+ static_cast<T>(-1.6116166443246101165e+03L),
+ static_cast<T>(0.0L),
+ };
+ static const T QC[] = {
+ static_cast<T>(-4.4357578167941278568e+06L),
+ static_cast<T>(-9.9341243899345856590e+06L),
+ static_cast<T>(-6.5853394797230870728e+06L),
+ static_cast<T>(-1.5118095066341608816e+06L),
+ static_cast<T>(-1.0726385991103820119e+05L),
+ static_cast<T>(-1.4550094401904961825e+03L),
+ static_cast<T>(1.0L),
+ };
+ static const T PS[] = {
+ static_cast<T>(3.3220913409857223519e+04L),
+ static_cast<T>(8.5145160675335701966e+04L),
+ static_cast<T>(6.6178836581270835179e+04L),
+ static_cast<T>(1.8494262873223866797e+04L),
+ static_cast<T>(1.7063754290207680021e+03L),
+ static_cast<T>(3.5265133846636032186e+01L),
+ static_cast<T>(0.0L),
+ };
+ static const T QS[] = {
+ static_cast<T>(7.0871281941028743574e+05L),
+ static_cast<T>(1.8194580422439972989e+06L),
+ static_cast<T>(1.4194606696037208929e+06L),
+ static_cast<T>(4.0029443582266975117e+05L),
+ static_cast<T>(3.7890229745772202641e+04L),
+ static_cast<T>(8.6383677696049909675e+02L),
+ static_cast<T>(1.0L),
+ };
+ static const T x1 = static_cast<T>(2.1971413260310170351e+00L),
+ x2 = static_cast<T>(5.4296810407941351328e+00L),
+ x11 = static_cast<T>(5.620e+02L),
+ x12 = static_cast<T>(1.8288260310170351490e-03L),
+ x21 = static_cast<T>(1.3900e+03L),
+ x22 = static_cast<T>(-6.4592058648672279948e-06L)
+ ;
+ T value, factor, r, rc, rs;
+
+ BOOST_MATH_STD_USING
+ using namespace boost::math::tools;
+ using namespace boost::math::constants;
+
+ if (x <= 0)
+ {
+ return policies::raise_domain_error<T>("bost::math::bessel_y1<%1%>(%1%,%1%)",
+ "Got x == %1%, but x must be > 0, complex result not supported.", x, pol);
+ }
+ if (x <= 4) // x in (0, 4]
+ {
+ T y = x * x;
+ T z = 2 * log(x/x1) * bessel_j1(x) / pi<T>();
+ r = evaluate_rational(P1, Q1, y);
+ factor = (x + x1) * ((x - x11/256) - x12) / x;
+ value = z + factor * r;
+ }
+ else if (x <= 8) // x in (4, 8]
+ {
+ T y = x * x;
+ T z = 2 * log(x/x2) * bessel_j1(x) / pi<T>();
+ r = evaluate_rational(P2, Q2, y);
+ factor = (x + x2) * ((x - x21/256) - x22) / x;
+ value = z + factor * r;
+ }
+ else // x in (8, \infty)
+ {
+ T y = 8 / x;
+ T y2 = y * y;
+ T z = x - 0.75f * pi<T>();
+ rc = evaluate_rational(PC, QC, y2);
+ rs = evaluate_rational(PS, QS, y2);
+ factor = sqrt(2 / (x * pi<T>()));
+ value = factor * (rc * sin(z) + y * rs * cos(z));
+ }
+
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_Y1_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/bessel_yn.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/bessel_yn.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,79 @@
+// 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
+
+#include <boost/math/special_functions/detail/bessel_y0.hpp>
+#include <boost/math/special_functions/detail/bessel_y1.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)
+{
+ 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 (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
+ {
+ value = 2 * k * current / x - prev;
+ prev = current;
+ current = value;
+ ++k;
+ }
+ while(k < n);
+ value *= factor;
+ }
+ return value;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_BESSEL_YN_HPP
Added: branches/bcbboost/boost/math/special_functions/detail/erf_inv.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/erf_inv.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,464 @@
+// (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
+
+namespace boost{ namespace math{
+
+namespace detail{
+//
+// The inverse erf and erfc functions share a common implementation,
+// this version is for 80-bit long double's and smaller:
+//
+template <class T, class Policy>
+T erf_inv_imp(const T& p, const T& q, const Policy&, const boost::mpl::int_<64>*)
+{
+ BOOST_MATH_STD_USING // for ADL of std names.
+
+ T result = 0;
+
+ if(p <= 0.5)
+ {
+ //
+ // Evaluate inverse erf using the rational approximation:
+ //
+ // x = p(p+10)(Y+R(p))
+ //
+ // Where Y is a constant, and R(p) is optimised for a low
+ // absolute error compared to |Y|.
+ //
+ // double: Max error found: 2.001849e-18
+ // long double: Max error found: 1.017064e-20
+ // Maximum Deviation Found (actual error term at infinite precision) 8.030e-21
+ //
+ static const float Y = 0.0891314744949340820313f;
+ static const T P[] = {
+ -0.000508781949658280665617L,
+ -0.00836874819741736770379L,
+ 0.0334806625409744615033L,
+ -0.0126926147662974029034L,
+ -0.0365637971411762664006L,
+ 0.0219878681111168899165L,
+ 0.00822687874676915743155L,
+ -0.00538772965071242932965L
+ };
+ static const T Q[] = {
+ 1,
+ -0.970005043303290640362L,
+ -1.56574558234175846809L,
+ 1.56221558398423026363L,
+ 0.662328840472002992063L,
+ -0.71228902341542847553L,
+ -0.0527396382340099713954L,
+ 0.0795283687341571680018L,
+ -0.00233393759374190016776L,
+ 0.000886216390456424707504L
+ };
+ T g = p * (p + 10);
+ T r = tools::evaluate_polynomial(P, p) / tools::evaluate_polynomial(Q, p);
+ result = g * Y + g * r;
+ }
+ else if(q >= 0.25)
+ {
+ //
+ // Rational approximation for 0.5 > q >= 0.25
+ //
+ // x = sqrt(-2*log(q)) / (Y + R(q))
+ //
+ // Where Y is a constant, and R(q) is optimised for a low
+ // absolute error compared to Y.
+ //
+ // double : Max error found: 7.403372e-17
+ // long double : Max error found: 6.084616e-20
+ // Maximum Deviation Found (error term) 4.811e-20
+ //
+ static const float Y = 2.249481201171875f;
+ static const T P[] = {
+ -0.202433508355938759655L,
+ 0.105264680699391713268L,
+ 8.37050328343119927838L,
+ 17.6447298408374015486L,
+ -18.8510648058714251895L,
+ -44.6382324441786960818L,
+ 17.445385985570866523L,
+ 21.1294655448340526258L,
+ -3.67192254707729348546L
+ };
+ static const T Q[] = {
+ 1L,
+ 6.24264124854247537712L,
+ 3.9713437953343869095L,
+ -28.6608180499800029974L,
+ -20.1432634680485188801L,
+ 48.5609213108739935468L,
+ 10.8268667355460159008L,
+ -22.6436933413139721736L,
+ 1.72114765761200282724L
+ };
+ T g = sqrt(-2 * log(q));
+ T xs = q - 0.25;
+ T r = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = g / (Y + r);
+ }
+ else
+ {
+ //
+ // For q < 0.25 we have a series of rational approximations all
+ // of the general form:
+ //
+ // let: x = sqrt(-log(q))
+ //
+ // Then the result is given by:
+ //
+ // x(Y+R(x-B))
+ //
+ // where Y is a constant, B is the lowest value of x for which
+ // the approximation is valid, and R(x-B) is optimised for a low
+ // absolute error compared to Y.
+ //
+ // Note that almost all code will really go through the first
+ // or maybe second approximation. After than we're dealing with very
+ // small input values indeed: 80 and 128 bit long double's go all the
+ // way down to ~ 1e-5000 so the "tail" is rather long...
+ //
+ T x = sqrt(-log(q));
+ if(x < 3)
+ {
+ // Max error found: 1.089051e-20
+ static const float Y = 0.807220458984375f;
+ static const T P[] = {
+ -0.131102781679951906451L,
+ -0.163794047193317060787L,
+ 0.117030156341995252019L,
+ 0.387079738972604337464L,
+ 0.337785538912035898924L,
+ 0.142869534408157156766L,
+ 0.0290157910005329060432L,
+ 0.00214558995388805277169L,
+ -0.679465575181126350155e-6L,
+ 0.285225331782217055858e-7L,
+ -0.681149956853776992068e-9L
+ };
+ static const T Q[] = {
+ 1,
+ 3.46625407242567245975L,
+ 5.38168345707006855425L,
+ 4.77846592945843778382L,
+ 2.59301921623620271374L,
+ 0.848854343457902036425L,
+ 0.152264338295331783612L,
+ 0.01105924229346489121L
+ };
+ T xs = x - 1.125;
+ T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = Y * x + R * x;
+ }
+ else if(x < 6)
+ {
+ // Max error found: 8.389174e-21
+ static const float Y = 0.93995571136474609375f;
+ static const T P[] = {
+ -0.0350353787183177984712L,
+ -0.00222426529213447927281L,
+ 0.0185573306514231072324L,
+ 0.00950804701325919603619L,
+ 0.00187123492819559223345L,
+ 0.000157544617424960554631L,
+ 0.460469890584317994083e-5L,
+ -0.230404776911882601748e-9L,
+ 0.266339227425782031962e-11L
+ };
+ static const T Q[] = {
+ 1L,
+ 1.3653349817554063097L,
+ 0.762059164553623404043L,
+ 0.220091105764131249824L,
+ 0.0341589143670947727934L,
+ 0.00263861676657015992959L,
+ 0.764675292302794483503e-4L
+ };
+ T xs = x - 3;
+ T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = Y * x + R * x;
+ }
+ else if(x < 18)
+ {
+ // Max error found: 1.481312e-19
+ static const float Y = 0.98362827301025390625f;
+ static const T P[] = {
+ -0.0167431005076633737133L,
+ -0.00112951438745580278863L,
+ 0.00105628862152492910091L,
+ 0.000209386317487588078668L,
+ 0.149624783758342370182e-4L,
+ 0.449696789927706453732e-6L,
+ 0.462596163522878599135e-8L,
+ -0.281128735628831791805e-13L,
+ 0.99055709973310326855e-16L
+ };
+ static const T Q[] = {
+ 1L,
+ 0.591429344886417493481L,
+ 0.138151865749083321638L,
+ 0.0160746087093676504695L,
+ 0.000964011807005165528527L,
+ 0.275335474764726041141e-4L,
+ 0.282243172016108031869e-6L
+ };
+ T xs = x - 6;
+ T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = Y * x + R * x;
+ }
+ else if(x < 44)
+ {
+ // Max error found: 5.697761e-20
+ static const float Y = 0.99714565277099609375f;
+ static const T P[] = {
+ -0.0024978212791898131227L,
+ -0.779190719229053954292e-5L,
+ 0.254723037413027451751e-4L,
+ 0.162397777342510920873e-5L,
+ 0.396341011304801168516e-7L,
+ 0.411632831190944208473e-9L,
+ 0.145596286718675035587e-11L,
+ -0.116765012397184275695e-17L
+ };
+ static const T Q[] = {
+ 1L,
+ 0.207123112214422517181L,
+ 0.0169410838120975906478L,
+ 0.000690538265622684595676L,
+ 0.145007359818232637924e-4L,
+ 0.144437756628144157666e-6L,
+ 0.509761276599778486139e-9L
+ };
+ T xs = x - 18;
+ T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = Y * x + R * x;
+ }
+ else
+ {
+ // Max error found: 1.279746e-20
+ static const float Y = 0.99941349029541015625f;
+ static const T P[] = {
+ -0.000539042911019078575891L,
+ -0.28398759004727721098e-6L,
+ 0.899465114892291446442e-6L,
+ 0.229345859265920864296e-7L,
+ 0.225561444863500149219e-9L,
+ 0.947846627503022684216e-12L,
+ 0.135880130108924861008e-14L,
+ -0.348890393399948882918e-21L
+ };
+ static const T Q[] = {
+ 1L,
+ 0.0845746234001899436914L,
+ 0.00282092984726264681981L,
+ 0.468292921940894236786e-4L,
+ 0.399968812193862100054e-6L,
+ 0.161809290887904476097e-8L,
+ 0.231558608310259605225e-11L
+ };
+ T xs = x - 44;
+ T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
+ result = Y * x + R * x;
+ }
+ }
+ return result;
+}
+
+template <class T, class Policy>
+struct erf_roots
+{
+ std::tr1::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 std::tr1::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)
+ {
+ 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);
+ }
+ 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);
+ }
+ }
+ 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
Added: branches/bcbboost/boost/math/special_functions/detail/gamma_inva.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/gamma_inva.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,178 @@
+// (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
+
+#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 T, class Policy>
+inline T gamma_p_inva(T x, T p, const Policy& pol)
+{
+ return detail::gamma_inva_imp(x, p, 1 - p, pol);
+}
+
+template <class T, class Policy>
+inline T gamma_q_inva(T x, T q, const Policy& pol)
+{
+ return detail::gamma_inva_imp(x, 1 - q, q, pol);
+}
+
+template <class T>
+inline T gamma_p_inva(T x, T p)
+{
+ return detail::gamma_inva_imp(x, p, 1 - p, policies::policy<>());
+}
+
+template <class T>
+inline T gamma_q_inva(T x, T q)
+{
+ return detail::gamma_inva_imp(x, 1 - q, q, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SP_DETAIL_GAMMA_INVA
+
+
Added: branches/bcbboost/boost/math/special_functions/detail/ibeta_inv_ab.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/ibeta_inv_ab.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,211 @@
+// (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
+
+#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)(b * 2, T(1));
+ }
+ else
+ {
+ guess = (std::min)(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)(b * 2, T(10));
+ }
+ else
+ {
+ guess = (std::min)(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 T, class Policy>
+inline T ibeta_inva(T b, T x, T p, const Policy& pol)
+{
+ return detail::ibeta_inv_ab_imp(b, x, p, 1 - p, false, pol);
+}
+
+template <class T, class Policy>
+inline T ibetac_inva(T b, T x, T q, const Policy& pol)
+{
+ return detail::ibeta_inv_ab_imp(b, x, 1 - q, q, false, pol);
+}
+
+template <class T, class Policy>
+inline T ibeta_invb(T b, T x, T p, const Policy& pol)
+{
+ return detail::ibeta_inv_ab_imp(b, x, p, 1 - p, true, pol);
+}
+
+template <class T, class Policy>
+inline T ibetac_invb(T b, T x, T q, const Policy& pol)
+{
+ return detail::ibeta_inv_ab_imp(b, x, 1 - q, q, true, pol);
+}
+
+template <class T>
+inline T ibeta_inva(T b, T x, T p)
+{
+ return detail::ibeta_inv_ab_imp(b, x, p, 1 - p, false, policies::policy<>());
+}
+
+template <class T>
+inline T ibetac_inva(T b, T x, T q)
+{
+ return detail::ibeta_inv_ab_imp(b, x, 1 - q, q, false, policies::policy<>());
+}
+
+template <class T>
+inline T ibeta_invb(T b, T x, T p)
+{
+ return detail::ibeta_inv_ab_imp(b, x, p, 1 - p, true, policies::policy<>());
+}
+
+template <class T>
+inline T ibetac_invb(T b, T x, T q)
+{
+ return detail::ibeta_inv_ab_imp(b, x, 1 - q, q, true, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SP_DETAIL_BETA_INV_AB
+
+
Added: branches/bcbboost/boost/math/special_functions/detail/ibeta_inverse.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/ibeta_inverse.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,932 @@
+// 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
+
+#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_) {}
+
+ std::tr1::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 std::tr1::make_tuple(-big, -big);
+ }
+ if(x == 0)
+ {
+ T big = tools::max_value<T>() / 4;
+ return std::tr1::make_tuple(-big, big);
+ }
+ T f = log(x) + a * log(y) + t;
+ T f1 = (1 / x) - (a / (y));
+ return std::tr1::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, 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, 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) co3[] = { 1, -13, 13 };
+ workspace[3] = tools::evaluate_polynomial(co3, workspace[0], 3) / (36 * s * c);
+ static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 1, 21, -69, 46 };
+ workspace[4] = tools::evaluate_polynomial(co4, 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) {}
+
+ std::tr1::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 std::tr1::make_tuple(f, f1, f2);
+ }
+private:
+ T a, b, target;
+ bool invert;
+};
+
+template <class T, class Policy>
+T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
+{
+ BOOST_MATH_STD_USING // For ADL of math functions.
+
+ //
+ // The flag invert is set to true if we swap a for b and p for q,
+ // in which case the result has to be subtracted from 1:
+ //
+ bool invert = false;
+ //
+ // 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)
+ {
+ std::swap(a, b);
+ std::swap(p, q);
+ invert = !invert;
+ }
+ //
+ // 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;
+ }
+ else 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) && (lambda >= 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 = true;
+ 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 = true;
+ }
+ //
+ // 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 ? 1 - x : -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 = true;
+ }
+ 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:
+ //
+ 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);
+ //
+ // 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)
+{
+ return ibetac_inv(a, b, q, static_cast<RT1*>(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)
+{
+ return ibetac_inv(a, b, q, static_cast<RT1*>(0), pol);
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
+
+
+
Added: branches/bcbboost/boost/math/special_functions/detail/igamma_inverse.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/igamma_inverse.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,466 @@
+// (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
+
+#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>
+#include <boost/tr1/tuple.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)
+{
+ //
+ // 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;
+
+ if(a == 1)
+ result = -log(q);
+ else if(a < 1)
+ {
+ T g = boost::math::tgamma(a, pol);
+ T b = q * g;
+ 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);
+ }
+ else
+ {
+ u = exp((-q / a) - constants::euler<T>());
+ }
+ result = u / (1 - (u / (a + 1)));
+ }
+ 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);
+ }
+ 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));
+ }
+ 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));
+ }
+ 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);
+ }
+ }
+ else
+ {
+ // DiDonato and Morris Eq 31:
+ T s = find_inverse_s(p, q);
+
+ 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);
+
+ 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);
+
+ if((a >= 500) && (fabs(1 - w / a) < 1e-6))
+ {
+ result = w;
+ }
+ else if (p > 0.5)
+ {
+ if(w < 3 * a)
+ {
+ result = w;
+ }
+ else
+ {
+ T D = (std::max)(T(2), 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);
+ }
+ 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));
+ }
+ }
+ }
+ else
+ {
+ // DiDonato and Morris Eq 35:
+ T z = didonato_FN(p, a, w, 0, T(0), pol);
+ z = didonato_FN(p, a, z, 2, T(0), pol);
+ z = didonato_FN(p, a, z, 2, T(0), pol);
+ z = didonato_FN(p, a, z, 3, T(0), pol);
+
+ if((z <= 0.01 * (a + 1)) || (z > 0.7 * (a + 1)))
+ {
+ result = z;
+ }
+ else
+ {
+ // DiDonato and Morris Eq 36:
+ T zb = didonato_FN(p, a, z, 100, T(1e-4), pol);
+ T u = log(p) + boost::math::lgamma(a + 1, pol);
+ result = zb * (1 - (a * log(zb) - zb - u + log(didonato_SN(a, z, 100, T(1e-4)))) / (a - zb));
+ }
+ }
+ }
+ 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;
+ }
+ }
+
+ std::tr1::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 std::tr1::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%)";
+
+ 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;
+ T guess = detail::find_inverse_gamma(a, p, 1 - p, pol);
+ 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>() * 2) / 3;
+ 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:
+ //
+ guess = tools::halley_iterate(
+ detail::gamma_p_inverse_func<T, Policy>(a, p, false),
+ guess,
+ lower,
+ tools::max_value<T>(),
+ digits);
+ 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;
+ T guess = detail::find_inverse_gamma(a, 1 - q, q, pol);
+ 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>() * 2) / 3;
+ 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:
+ //
+ guess = tools::halley_iterate(
+ detail::gamma_p_inverse_func<T, Policy>(a, q, true),
+ guess,
+ lower,
+ tools::max_value<T>(),
+ digits);
+ 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
+
+
Added: branches/bcbboost/boost/math/special_functions/detail/igamma_large.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/igamma_large.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,764 @@
+// 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
+
+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 = -log1pmx(sigma, pol);
+ T y = a * phi;
+ T z = sqrt(2 * phi);
+ if(x < a)
+ z = -z;
+
+ T workspace[13];
+
+ static const T C0[] = {
+ -0.333333333333333333333L,
+ 0.0833333333333333333333L,
+ -0.0148148148148148148148L,
+ 0.00115740740740740740741L,
+ 0.000352733686067019400353L,
+ -0.0001787551440329218107L,
+ 0.39192631785224377817e-4L,
+ -0.218544851067999216147e-5L,
+ -0.18540622107151599607e-5L,
+ 0.829671134095308600502e-6L,
+ -0.176659527368260793044e-6L,
+ 0.670785354340149858037e-8L,
+ 0.102618097842403080426e-7L,
+ -0.438203601845335318655e-8L,
+ 0.914769958223679023418e-9L,
+ -0.255141939949462497669e-10L,
+ -0.583077213255042506746e-10L,
+ 0.243619480206674162437e-10L,
+ -0.502766928011417558909e-11L,
+ };
+ workspace[0] = tools::evaluate_polynomial(C0, z);
+
+ static const T C1[] = {
+ -0.00185185185185185185185L,
+ -0.00347222222222222222222L,
+ 0.00264550264550264550265L,
+ -0.000990226337448559670782L,
+ 0.000205761316872427983539L,
+ -0.40187757201646090535e-6L,
+ -0.18098550334489977837e-4L,
+ 0.764916091608111008464e-5L,
+ -0.161209008945634460038e-5L,
+ 0.464712780280743434226e-8L,
+ 0.137863344691572095931e-6L,
+ -0.575254560351770496402e-7L,
+ 0.119516285997781473243e-7L,
+ -0.175432417197476476238e-10L,
+ -0.100915437106004126275e-8L,
+ 0.416279299184258263623e-9L,
+ -0.856390702649298063807e-10L,
+ };
+ workspace[1] = tools::evaluate_polynomial(C1, z);
+
+ static const T C2[] = {
+ 0.00413359788359788359788L,
+ -0.00268132716049382716049L,
+ 0.000771604938271604938272L,
+ 0.200938786008230452675e-5L,
+ -0.000107366532263651605215L,
+ 0.529234488291201254164e-4L,
+ -0.127606351886187277134e-4L,
+ 0.342357873409613807419e-7L,
+ 0.137219573090629332056e-5L,
+ -0.629899213838005502291e-6L,
+ 0.142806142060642417916e-6L,
+ -0.204770984219908660149e-9L,
+ -0.140925299108675210533e-7L,
+ 0.622897408492202203356e-8L,
+ -0.136704883966171134993e-8L,
+ };
+ workspace[2] = tools::evaluate_polynomial(C2, z);
+
+ static const T C3[] = {
+ 0.000649434156378600823045L,
+ 0.000229472093621399176955L,
+ -0.000469189494395255712128L,
+ 0.000267720632062838852962L,
+ -0.756180167188397641073e-4L,
+ -0.239650511386729665193e-6L,
+ 0.110826541153473023615e-4L,
+ -0.56749528269915965675e-5L,
+ 0.142309007324358839146e-5L,
+ -0.278610802915281422406e-10L,
+ -0.169584040919302772899e-6L,
+ 0.809946490538808236335e-7L,
+ -0.191111684859736540607e-7L,
+ };
+ workspace[3] = tools::evaluate_polynomial(C3, z);
+
+ static const T C4[] = {
+ -0.000861888290916711698605L,
+ 0.000784039221720066627474L,
+ -0.000299072480303190179733L,
+ -0.146384525788434181781e-5L,
+ 0.664149821546512218666e-4L,
+ -0.396836504717943466443e-4L,
+ 0.113757269706784190981e-4L,
+ 0.250749722623753280165e-9L,
+ -0.169541495365583060147e-5L,
+ 0.890750753220530968883e-6L,
+ -0.229293483400080487057e-6L,
+ };
+ workspace[4] = tools::evaluate_polynomial(C4, z);
+
+ static const T C5[] = {
+ -0.000336798553366358150309L,
+ -0.697281375836585777429e-4L,
+ 0.000277275324495939207873L,
+ -0.000199325705161888477003L,
+ 0.679778047793720783882e-4L,
+ 0.141906292064396701483e-6L,
+ -0.135940481897686932785e-4L,
+ 0.801847025633420153972e-5L,
+ -0.229148117650809517038e-5L,
+ };
+ workspace[5] = tools::evaluate_polynomial(C5, z);
+
+ static const T C6[] = {
+ 0.000531307936463992223166L,
+ -0.000592166437353693882865L,
+ 0.000270878209671804482771L,
+ 0.790235323266032787212e-6L,
+ -0.815396936756196875093e-4L,
+ 0.561168275310624965004e-4L,
+ -0.183291165828433755673e-4L,
+ -0.307961345060330478256e-8L,
+ 0.346515536880360908674e-5L,
+ -0.20291327396058603727e-5L,
+ 0.57887928631490037089e-6L,
+ };
+ workspace[6] = tools::evaluate_polynomial(C6, z);
+
+ static const T C7[] = {
+ 0.000344367606892377671254L,
+ 0.517179090826059219337e-4L,
+ -0.000334931610811422363117L,
+ 0.000281269515476323702274L,
+ -0.000109765822446847310235L,
+ -0.127410090954844853795e-6L,
+ 0.277444515115636441571e-4L,
+ -0.182634888057113326614e-4L,
+ 0.578769494973505239894e-5L,
+ };
+ workspace[7] = tools::evaluate_polynomial(C7, z);
+
+ static const T C8[] = {
+ -0.000652623918595309418922L,
+ 0.000839498720672087279993L,
+ -0.000438297098541721005061L,
+ -0.696909145842055197137e-6L,
+ 0.000166448466420675478374L,
+ -0.000127835176797692185853L,
+ 0.462995326369130429061e-4L,
+ };
+ workspace[8] = tools::evaluate_polynomial(C8, z);
+
+ static const T C9[] = {
+ -0.000596761290192746250124L,
+ -0.720489541602001055909e-4L,
+ 0.000678230883766732836162L,
+ -0.0006401475260262758451L,
+ 0.000277501076343287044992L,
+ };
+ workspace[9] = tools::evaluate_polynomial(C9, z);
+
+ static const T C10[] = {
+ 0.00133244544948006563713L,
+ -0.0019144384985654775265L,
+ 0.00110893691345966373396L,
+ };
+ workspace[10] = tools::evaluate_polynomial(C10, z);
+
+ static const T C11[] = {
+ 0.00157972766073083495909L,
+ 0.000162516262783915816899L,
+ -0.00206334210355432762645L,
+ 0.00213896861856890981541L,
+ -0.00101085593912630031708L,
+ };
+ workspace[11] = tools::evaluate_polynomial(C11, z);
+
+ static const T C12[] = {
+ -0.00407251211951401664727L,
+ 0.00640336283380806979482L,
+ -0.00404101610816766177474L,
+ };
+ workspace[12] = tools::evaluate_polynomial(C12, z);
+
+ T result = tools::evaluate_polynomial(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 = -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(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 = -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 = -log1pmx(sigma, pol);
+ T y = a * phi;
+ T z = sqrt(2 * phi);
+ if(x < a)
+ z = -z;
+
+ T workspace[14];
+
+ static const T C0[] = {
+ -0.333333333333333333333333333333333333L,
+ 0.0833333333333333333333333333333333333L,
+ -0.0148148148148148148148148148148148148L,
+ 0.00115740740740740740740740740740740741L,
+ 0.0003527336860670194003527336860670194L,
+ -0.000178755144032921810699588477366255144L,
+ 0.391926317852243778169704095630021556e-4L,
+ -0.218544851067999216147364295512443661e-5L,
+ -0.185406221071515996070179883622956325e-5L,
+ 0.829671134095308600501624213166443227e-6L,
+ -0.17665952736826079304360054245742403e-6L,
+ 0.670785354340149858036939710029613572e-8L,
+ 0.102618097842403080425739573227252951e-7L,
+ -0.438203601845335318655297462244719123e-8L,
+ 0.914769958223679023418248817633113681e-9L,
+ -0.255141939949462497668779537993887013e-10L,
+ -0.583077213255042506746408945040035798e-10L,
+ 0.243619480206674162436940696707789943e-10L,
+ -0.502766928011417558909054985925744366e-11L,
+ 0.110043920319561347708374174497293411e-12L,
+ 0.337176326240098537882769884169200185e-12L,
+ -0.13923887224181620659193661848957998e-12L,
+ 0.285348938070474432039669099052828299e-13L,
+ -0.513911183424257261899064580300494205e-15L,
+ -0.197522882943494428353962401580710912e-14L,
+ 0.809952115670456133407115668702575255e-15L,
+ -0.165225312163981618191514820265351162e-15L,
+ 0.253054300974788842327061090060267385e-17L,
+ 0.116869397385595765888230876507793475e-16L,
+ -0.477003704982048475822167804084816597e-17L,
+ 0.969912605905623712420709685898585354e-18L,
+ };
+ workspace[0] = tools::evaluate_polynomial(C0, z);
+
+ static const T C1[] = {
+ -0.00185185185185185185185185185185185185L,
+ -0.00347222222222222222222222222222222222L,
+ 0.0026455026455026455026455026455026455L,
+ -0.000990226337448559670781893004115226337L,
+ 0.000205761316872427983539094650205761317L,
+ -0.401877572016460905349794238683127572e-6L,
+ -0.180985503344899778370285914867533523e-4L,
+ 0.76491609160811100846374214980916921e-5L,
+ -0.16120900894563446003775221882217767e-5L,
+ 0.464712780280743434226135033938722401e-8L,
+ 0.137863344691572095931187533077488877e-6L,
+ -0.575254560351770496402194531835048307e-7L,
+ 0.119516285997781473243076536699698169e-7L,
+ -0.175432417197476476237547551202312502e-10L,
+ -0.100915437106004126274577504686681675e-8L,
+ 0.416279299184258263623372347219858628e-9L,
+ -0.856390702649298063807431562579670208e-10L,
+ 0.606721510160475861512701762169919581e-13L,
+ 0.716249896481148539007961017165545733e-11L,
+ -0.293318664377143711740636683615595403e-11L,
+ 0.599669636568368872330374527568788909e-12L,
+ -0.216717865273233141017100472779701734e-15L,
+ -0.497833997236926164052815522048108548e-13L,
+ 0.202916288237134247736694804325894226e-13L,
+ -0.413125571381061004935108332558187111e-14L,
+ 0.828651623988309644380188591057589316e-18L,
+ 0.341003088693333279336339355910600992e-15L,
+ -0.138541953028939715357034547426313703e-15L,
+ 0.281234665322887466568860332727259483e-16L,
+ };
+ workspace[1] = tools::evaluate_polynomial(C1, z);
+
+ static const T C2[] = {
+ 0.0041335978835978835978835978835978836L,
+ -0.00268132716049382716049382716049382716L,
+ 0.000771604938271604938271604938271604938L,
+ 0.200938786008230452674897119341563786e-5L,
+ -0.000107366532263651605215391223621676297L,
+ 0.529234488291201254164217127180090143e-4L,
+ -0.127606351886187277133779191392360117e-4L,
+ 0.34235787340961380741902003904747389e-7L,
+ 0.137219573090629332055943852926020279e-5L,
+ -0.629899213838005502290672234278391876e-6L,
+ 0.142806142060642417915846008822771748e-6L,
+ -0.204770984219908660149195854409200226e-9L,
+ -0.140925299108675210532930244154315272e-7L,
+ 0.622897408492202203356394293530327112e-8L,
+ -0.136704883966171134992724380284402402e-8L,
+ 0.942835615901467819547711211663208075e-12L,
+ 0.128722524000893180595479368872770442e-9L,
+ -0.556459561343633211465414765894951439e-10L,
+ 0.119759355463669810035898150310311343e-10L,
+ -0.416897822518386350403836626692480096e-14L,
+ -0.109406404278845944099299008640802908e-11L,
+ 0.4662239946390135746326204922464679e-12L,
+ -0.990510576390690597844122258212382301e-13L,
+ 0.189318767683735145056885183170630169e-16L,
+ 0.885922187259112726176031067028740667e-14L,
+ -0.373782039804640545306560251777191937e-14L,
+ 0.786883363903515525774088394065960751e-15L,
+ };
+ workspace[2] = tools::evaluate_polynomial(C2, z);
+
+ static const T C3[] = {
+ 0.000649434156378600823045267489711934156L,
+ 0.000229472093621399176954732510288065844L,
+ -0.000469189494395255712128140111679206329L,
+ 0.000267720632062838852962309752433209223L,
+ -0.756180167188397641072538191879755666e-4L,
+ -0.239650511386729665193314027333231723e-6L,
+ 0.110826541153473023614770299726861227e-4L,
+ -0.567495282699159656749963105701560205e-5L,
+ 0.14230900732435883914551894470580433e-5L,
+ -0.278610802915281422405802158211174452e-10L,
+ -0.16958404091930277289864168795820267e-6L,
+ 0.809946490538808236335278504852724081e-7L,
+ -0.191111684859736540606728140872727635e-7L,
+ 0.239286204398081179686413514022282056e-11L,
+ 0.206201318154887984369925818486654549e-8L,
+ -0.946049666185513217375417988510192814e-9L,
+ 0.215410497757749078380130268468744512e-9L,
+ -0.138882333681390304603424682490735291e-13L,
+ -0.218947616819639394064123400466489455e-10L,
+ 0.979099895117168512568262802255883368e-11L,
+ -0.217821918801809621153859472011393244e-11L,
+ 0.62088195734079014258166361684972205e-16L,
+ 0.212697836327973697696702537114614471e-12L,
+ -0.934468879151743333127396765626749473e-13L,
+ 0.204536712267828493249215913063207436e-13L,
+ };
+ workspace[3] = tools::evaluate_polynomial(C3, z);
+
+ static const T C4[] = {
+ -0.000861888290916711698604702719929057378L,
+ 0.00078403922172006662747403488144228885L,
+ -0.000299072480303190179733389609932819809L,
+ -0.146384525788434181781232535690697556e-5L,
+ 0.664149821546512218665853782451862013e-4L,
+ -0.396836504717943466443123507595386882e-4L,
+ 0.113757269706784190980552042885831759e-4L,
+ 0.250749722623753280165221942390057007e-9L,
+ -0.169541495365583060147164356781525752e-5L,
+ 0.890750753220530968882898422505515924e-6L,
+ -0.229293483400080487057216364891158518e-6L,
+ 0.295679413754404904696572852500004588e-10L,
+ 0.288658297427087836297341274604184504e-7L,
+ -0.141897394378032193894774303903982717e-7L,
+ 0.344635804994648970659527720474194356e-8L,
+ -0.230245171745280671320192735850147087e-12L,
+ -0.394092330280464052750697640085291799e-9L,
+ 0.186023389685045019134258533045185639e-9L,
+ -0.435632300505661804380678327446262424e-10L,
+ 0.127860010162962312660550463349930726e-14L,
+ 0.467927502665791946200382739991760062e-11L,
+ -0.214924647061348285410535341910721086e-11L,
+ 0.490881561480965216323649688463984082e-12L,
+ };
+ workspace[4] = tools::evaluate_polynomial(C4, z);
+
+ static const T C5[] = {
+ -0.000336798553366358150308767592718210002L,
+ -0.697281375836585777429398828575783308e-4L,
+ 0.00027727532449593920787336425196507501L,
+ -0.000199325705161888477003360405280844238L,
+ 0.679778047793720783881640176604435742e-4L,
+ 0.141906292064396701483392727105575757e-6L,
+ -0.135940481897686932784583938837504469e-4L,
+ 0.80184702563342015397192571980419684e-5L,
+ -0.229148117650809517038048790128781806e-5L,
+ -0.325247355129845395166230137750005047e-9L,
+ 0.346528464910852649559195496827579815e-6L,
+ -0.184471871911713432765322367374920978e-6L,
+ 0.482409670378941807563762631738989002e-7L,
+ -0.179894667217435153025754291716644314e-13L,
+ -0.630619450001352343517516981425944698e-8L,
+ 0.316241762877456793773762181540969623e-8L,
+ -0.784092425369742929000839303523267545e-9L,
+ };
+ workspace[5] = tools::evaluate_polynomial(C5, z);
+
+ static const T C6[] = {
+ 0.00053130793646399222316574854297762391L,
+ -0.000592166437353693882864836225604401187L,
+ 0.000270878209671804482771279183488328692L,
+ 0.790235323266032787212032944390816666e-6L,
+ -0.815396936756196875092890088464682624e-4L,
+ 0.561168275310624965003775619041471695e-4L,
+ -0.183291165828433755673259749374098313e-4L,
+ -0.307961345060330478256414192546677006e-8L,
+ 0.346515536880360908673728529745376913e-5L,
+ -0.202913273960586037269527254582695285e-5L,
+ 0.578879286314900370889997586203187687e-6L,
+ 0.233863067382665698933480579231637609e-12L,
+ -0.88286007463304835250508524317926246e-7L,
+ 0.474359588804081278032150770595852426e-7L,
+ -0.125454150207103824457130611214783073e-7L,
+ };
+ workspace[6] = tools::evaluate_polynomial(C6, z);
+
+ static const T C7[] = {
+ 0.000344367606892377671254279625108523655L,
+ 0.517179090826059219337057843002058823e-4L,
+ -0.000334931610811422363116635090580012327L,
+ 0.000281269515476323702273722110707777978L,
+ -0.000109765822446847310235396824500789005L,
+ -0.127410090954844853794579954588107623e-6L,
+ 0.277444515115636441570715073933712622e-4L,
+ -0.182634888057113326614324442681892723e-4L,
+ 0.578769494973505239894178121070843383e-5L,
+ 0.493875893393627039981813418398565502e-9L,
+ -0.105953670140260427338098566209633945e-5L,
+ 0.616671437611040747858836254004890765e-6L,
+ -0.175629733590604619378669693914265388e-6L,
+ };
+ workspace[7] = tools::evaluate_polynomial(C7, z);
+
+ static const T C8[] = {
+ -0.000652623918595309418922034919726622692L,
+ 0.000839498720672087279993357516764983445L,
+ -0.000438297098541721005061087953050560377L,
+ -0.696909145842055197136911097362072702e-6L,
+ 0.00016644846642067547837384572662326101L,
+ -0.000127835176797692185853344001461664247L,
+ 0.462995326369130429061361032704489636e-4L,
+ 0.455790986792270771162749294232219616e-8L,
+ -0.105952711258051954718238500312872328e-4L,
+ 0.678334290486516662273073740749269432e-5L,
+ -0.210754766662588042469972680229376445e-5L,
+ };
+ workspace[8] = tools::evaluate_polynomial(C8, z);
+
+ static const T C9[] = {
+ -0.000596761290192746250124390067179459605L,
+ -0.720489541602001055908571930225015052e-4L,
+ 0.000678230883766732836161951166000673426L,
+ -0.000640147526026275845100045652582354779L,
+ 0.000277501076343287044992374518205845463L,
+ 0.181970083804651510461686554030325202e-6L,
+ -0.847950711706850318239732559632810086e-4L,
+ 0.610519208250153101764709122740859458e-4L,
+ -0.210739201834048624082975255893773306e-4L,
+ };
+ workspace[9] = tools::evaluate_polynomial(C9, z);
+
+ static const T C10[] = {
+ 0.00133244544948006563712694993432717968L,
+ -0.00191443849856547752650089885832852254L,
+ 0.0011089369134596637339607446329267522L,
+ 0.993240412264229896742295262075817566e-6L,
+ -0.000508745012930931989848393025305956774L,
+ 0.00042735056665392884328432271160040444L,
+ -0.000168588537679107988033552814662382059L,
+ };
+ workspace[10] = tools::evaluate_polynomial(C10, z);
+
+ static const T C11[] = {
+ 0.00157972766073083495908785631307733022L,
+ 0.000162516262783915816898635123980270998L,
+ -0.00206334210355432762645284467690276817L,
+ 0.00213896861856890981541061922797693947L,
+ -0.00101085593912630031708085801712479376L,
+ };
+ workspace[11] = tools::evaluate_polynomial(C11, z);
+
+ static const T C12[] = {
+ -0.00407251211951401664727281097914544601L,
+ 0.00640336283380806979482363809026579583L,
+ -0.00404101610816766177473974858518094879L,
+ };
+ workspace[12] = tools::evaluate_polynomial(C12, z);
+ workspace[13] = -0.0059475779383993002845382844736066323L;
+
+ T result = tools::evaluate_polynomial(workspace, 1/a);
+ result *= exp(-y) / sqrt(2 * constants::pi<T>() * a);
+ if(x < a)
+ result = -result;
+
+ result += boost::math::erfc(sqrt(y), pol) / 2;
+
+ return result;
+}
+
+
+} // namespace detail
+} // namespace math
+} // namespace math
+
+
+#endif // BOOST_MATH_DETAIL_IGAMMA_LARGE
Added: branches/bcbboost/boost/math/special_functions/detail/lgamma_small.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/lgamma_small.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,507 @@
+// (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
+
+namespace boost{ namespace math{ namespace detail{
+
+//
+// lgamma for small arguments:
+//
+template <class T, class Policy, class L>
+T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<64>&, const Policy& /* l */, const L&)
+{
+ // This version uses rational approximations for small
+ // values of z accurate enough for 64-bit mantissas
+ // (80-bit long doubles), works well for 53-bit doubles as well.
+ // L is only used to select the Lanczos function.
+
+ BOOST_MATH_STD_USING // for ADL of std names
+ T result = 0;
+ if(z < tools::epsilon<T>())
+ {
+ result = -log(z);
+ }
+ else if((zm1 == 0) || (zm2 == 0))
+ {
+ // nothing to do, result is zero....
+ }
+ else if(z > 2)
+ {
+ //
+ // Begin by performing argument reduction until
+ // z is in [2,3):
+ //
+ if(z >= 3)
+ {
+ do
+ {
+ z -= 1;
+ zm2 -= 1;
+ result += log(z);
+ }while(z >= 3);
+ // Update zm2, we need it below:
+ zm2 = z - 2;
+ }
+
+ //
+ // Use the following form:
+ //
+ // lgamma(z) = (z-2)(z+1)(Y + R(z-2))
+ //
+ // where R(z-2) is a rational approximation optimised for
+ // low absolute error - as long as it's absolute error
+ // is small compared to the constant Y - then any rounding
+ // error in it's computation will get wiped out.
+ //
+ // R(z-2) has the following properties:
+ //
+ // At double: Max error found: 4.231e-18
+ // At long double: Max error found: 1.987e-21
+ // Maximum Deviation Found (approximation error): 5.900e-24
+ //
+ static const T P[] = {
+ static_cast<T>(-0.180355685678449379109e-1L),
+ static_cast<T>(0.25126649619989678683e-1L),
+ static_cast<T>(0.494103151567532234274e-1L),
+ static_cast<T>(0.172491608709613993966e-1L),
+ static_cast<T>(-0.259453563205438108893e-3L),
+ static_cast<T>(-0.541009869215204396339e-3L),
+ static_cast<T>(-0.324588649825948492091e-4L)
+ };
+ static const T Q[] = {
+ static_cast<T>(0.1e1),
+ static_cast<T>(0.196202987197795200688e1L),
+ static_cast<T>(0.148019669424231326694e1L),
+ static_cast<T>(0.541391432071720958364e0L),
+ static_cast<T>(0.988504251128010129477e-1L),
+ static_cast<T>(0.82130967464889339326e-2L),
+ static_cast<T>(0.224936291922115757597e-3L),
+ static_cast<T>(-0.223352763208617092964e-6L)
+ };
+
+ static const float Y = 0.158963680267333984375e0f;
+
+ T r = zm2 * (z + 1);
+ T R = tools::evaluate_polynomial(P, zm2);
+ R /= tools::evaluate_polynomial(Q, zm2);
+
+ result += r * Y + r * R;
+ }
+ else
+ {
+ //
+ // If z is less than 1 use recurrance to shift to
+ // z in the interval [1,2]:
+ //
+ if(z < 1)
+ {
+ result += -log(z);
+ zm2 = zm1;
+ zm1 = z;
+ z += 1;
+ }
+ //
+ // Two approximations, on for z in [1,1.5] and
+ // one for z in [1.5,2]:
+ //
+ if(z <= 1.5)
+ {
+ //
+ // Use the following form:
+ //
+ // lgamma(z) = (z-1)(z-2)(Y + R(z-1))
+ //
+ // where R(z-1) is a rational approximation optimised for
+ // low absolute error - as long as it's absolute error
+ // is small compared to the constant Y - then any rounding
+ // error in it's computation will get wiped out.
+ //
+ // R(z-1) has the following properties:
+ //
+ // At double precision: Max error found: 1.230011e-17
+ // At 80-bit long double precision: Max error found: 5.631355e-21
+ // Maximum Deviation Found: 3.139e-021
+ // Expected Error Term: 3.139e-021
+
+ //
+ static const float Y = 0.52815341949462890625f;
+
+ static const T P[] = {
+ static_cast<T>(0.490622454069039543534e-1L),
+ static_cast<T>(-0.969117530159521214579e-1L),
+ static_cast<T>(-0.414983358359495381969e0L),
+ static_cast<T>(-0.406567124211938417342e0L),
+ static_cast<T>(-0.158413586390692192217e0L),
+ static_cast<T>(-0.240149820648571559892e-1L),
+ static_cast<T>(-0.100346687696279557415e-2L)
+ };
+ static const T Q[] = {
+ static_cast<T>(0.1e1L),
+ static_cast<T>(0.302349829846463038743e1L),
+ static_cast<T>(0.348739585360723852576e1L),
+ static_cast<T>(0.191415588274426679201e1L),
+ static_cast<T>(0.507137738614363510846e0L),
+ static_cast<T>(0.577039722690451849648e-1L),
+ static_cast<T>(0.195768102601107189171e-2L)
+ };
+
+ T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1);
+ T prefix = zm1 * zm2;
+
+ result += prefix * Y + prefix * r;
+ }
+ else
+ {
+ //
+ // Use the following form:
+ //
+ // lgamma(z) = (2-z)(1-z)(Y + R(2-z))
+ //
+ // where R(2-z) is a rational approximation optimised for
+ // low absolute error - as long as it's absolute error
+ // is small compared to the constant Y - then any rounding
+ // error in it's computation will get wiped out.
+ //
+ // R(2-z) has the following properties:
+ //
+ // At double precision, max error found: 1.797565e-17
+ // At 80-bit long double precision, max error found: 9.306419e-21
+ // Maximum Deviation Found: 2.151e-021
+ // Expected Error Term: 2.150e-021
+ //
+ static const float Y = 0.452017307281494140625f;
+
+ static const T P[] = {
+ static_cast<T>(-0.292329721830270012337e-1L),
+ static_cast<T>(0.144216267757192309184e0L),
+ static_cast<T>(-0.142440390738631274135e0L),
+ static_cast<T>(0.542809694055053558157e-1L),
+ static_cast<T>(-0.850535976868336437746e-2L),
+ static_cast<T>(0.431171342679297331241e-3L)
+ };
+ static const T Q[] = {
+ static_cast<T>(0.1e1),
+ static_cast<T>(-0.150169356054485044494e1L),
+ static_cast<T>(0.846973248876495016101e0L),
+ static_cast<T>(-0.220095151814995745555e0L),
+ static_cast<T>(0.25582797155975869989e-1L),
+ static_cast<T>(-0.100666795539143372762e-2L),
+ static_cast<T>(-0.827193521891290553639e-6L)
+ };
+ T r = zm2 * zm1;
+ T R = tools::evaluate_polynomial(P, -zm2) / tools::evaluate_polynomial(Q, -zm2);
+
+ result += r * Y + r * R;
+ }
+ }
+ return result;
+}
+template <class T, class Policy, class L>
+T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<113>&, const Policy& /* l */, const L&)
+{
+ //
+ // This version uses rational approximations for small
+ // values of z accurate enough for 113-bit mantissas
+ // (128-bit long doubles).
+ //
+ BOOST_MATH_STD_USING // for ADL of std names
+ T result = 0;
+ if(z < tools::epsilon<T>())
+ {
+ result = -log(z);
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ else if((zm1 == 0) || (zm2 == 0))
+ {
+ // nothing to do, result is zero....
+ }
+ else if(z > 2)
+ {
+ //
+ // Begin by performing argument reduction until
+ // z is in [2,3):
+ //
+ if(z >= 3)
+ {
+ do
+ {
+ z -= 1;
+ result += log(z);
+ }while(z >= 3);
+ zm2 = z - 2;
+ }
+ BOOST_MATH_INSTRUMENT_CODE(zm2);
+ BOOST_MATH_INSTRUMENT_CODE(z);
+ BOOST_MATH_INSTRUMENT_CODE(result);
+
+ //
+ // Use the following form:
+ //
+ // lgamma(z) = (z-2)(z+1)(Y + R(z-2))
+ //
+ // where R(z-2) is a rational approximation optimised for
+ // low absolute error - as long as it's absolute error
+ // is small compared to the constant Y - then any rounding
+ // error in it's computation will get wiped out.
+ //
+ // Maximum Deviation Found (approximation error) 3.73e-37
+
+ static const T P[] = {
+ -0.018035568567844937910504030027467476655L,
+ 0.013841458273109517271750705401202404195L,
+ 0.062031842739486600078866923383017722399L,
+ 0.052518418329052161202007865149435256093L,
+ 0.01881718142472784129191838493267755758L,
+ 0.0025104830367021839316463675028524702846L,
+ -0.00021043176101831873281848891452678568311L,
+ -0.00010249622350908722793327719494037981166L,
+ -0.11381479670982006841716879074288176994e-4L,
+ -0.49999811718089980992888533630523892389e-6L,
+ -0.70529798686542184668416911331718963364e-8L
+ };
+ static const T Q[] = {
+ 1L,
+ 2.5877485070422317542808137697939233685L,
+ 2.8797959228352591788629602533153837126L,
+ 1.8030885955284082026405495275461180977L,
+ 0.69774331297747390169238306148355428436L,
+ 0.17261566063277623942044077039756583802L,
+ 0.02729301254544230229429621192443000121L,
+ 0.0026776425891195270663133581960016620433L,
+ 0.00015244249160486584591370355730402168106L,
+ 0.43997034032479866020546814475414346627e-5L,
+ 0.46295080708455613044541885534408170934e-7L,
+ -0.93326638207459533682980757982834180952e-11L,
+ 0.42316456553164995177177407325292867513e-13L
+ };
+
+ T R = tools::evaluate_polynomial(P, zm2);
+ R /= tools::evaluate_polynomial(Q, zm2);
+
+ static const float Y = 0.158963680267333984375F;
+
+ T r = zm2 * (z + 1);
+
+ result += r * Y + r * R;
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ else
+ {
+ //
+ // If z is less than 1 use recurrance to shift to
+ // z in the interval [1,2]:
+ //
+ if(z < 1)
+ {
+ result += -log(z);
+ zm2 = zm1;
+ zm1 = z;
+ z += 1;
+ }
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ BOOST_MATH_INSTRUMENT_CODE(z);
+ BOOST_MATH_INSTRUMENT_CODE(zm2);
+ //
+ // Three approximations, on for z in [1,1.35], [1.35,1.625] and [1.625,1]
+ //
+ if(z <= 1.35)
+ {
+ //
+ // Use the following form:
+ //
+ // lgamma(z) = (z-1)(z-2)(Y + R(z-1))
+ //
+ // where R(z-1) is a rational approximation optimised for
+ // low absolute error - as long as it's absolute error
+ // is small compared to the constant Y - then any rounding
+ // error in it's computation will get wiped out.
+ //
+ // R(z-1) has the following properties:
+ //
+ // Maximum Deviation Found (approximation error) 1.659e-36
+ // Expected Error Term (theoretical error) 1.343e-36
+ // Max error found at 128-bit long double precision 1.007e-35
+ //
+ static const float Y = 0.54076099395751953125f;
+
+ static const T P[] = {
+ 0.036454670944013329356512090082402429697L,
+ -0.066235835556476033710068679907798799959L,
+ -0.67492399795577182387312206593595565371L,
+ -1.4345555263962411429855341651960000166L,
+ -1.4894319559821365820516771951249649563L,
+ -0.87210277668067964629483299712322411566L,
+ -0.29602090537771744401524080430529369136L,
+ -0.0561832587517836908929331992218879676L,
+ -0.0053236785487328044334381502530383140443L,
+ -0.00018629360291358130461736386077971890789L,
+ -0.10164985672213178500790406939467614498e-6L,
+ 0.13680157145361387405588201461036338274e-8L
+ };
+ static const T Q[] = {
+ 1,
+ 4.9106336261005990534095838574132225599L,
+ 10.258804800866438510889341082793078432L,
+ 11.88588976846826108836629960537466889L,
+ 8.3455000546999704314454891036700998428L,
+ 3.6428823682421746343233362007194282703L,
+ 0.97465989807254572142266753052776132252L,
+ 0.15121052897097822172763084966793352524L,
+ 0.012017363555383555123769849654484594893L,
+ 0.0003583032812720649835431669893011257277L
+ };
+
+ T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1);
+ T prefix = zm1 * zm2;
+
+ result += prefix * Y + prefix * r;
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ else if(z <= 1.625)
+ {
+ //
+ // Use the following form:
+ //
+ // lgamma(z) = (2-z)(1-z)(Y + R(2-z))
+ //
+ // where R(2-z) is a rational approximation optimised for
+ // low absolute error - as long as it's absolute error
+ // is small compared to the constant Y - then any rounding
+ // error in it's computation will get wiped out.
+ //
+ // R(2-z) has the following properties:
+ //
+ // Max error found at 128-bit long double precision 9.634e-36
+ // Maximum Deviation Found (approximation error) 1.538e-37
+ // Expected Error Term (theoretical error) 2.350e-38
+ //
+ static const float Y = 0.483787059783935546875f;
+
+ static const T P[] = {
+ -0.017977422421608624353488126610933005432L,
+ 0.18484528905298309555089509029244135703L,
+ -0.40401251514859546989565001431430884082L,
+ 0.40277179799147356461954182877921388182L,
+ -0.21993421441282936476709677700477598816L,
+ 0.069595742223850248095697771331107571011L,
+ -0.012681481427699686635516772923547347328L,
+ 0.0012489322866834830413292771335113136034L,
+ -0.57058739515423112045108068834668269608e-4L,
+ 0.8207548771933585614380644961342925976e-6L
+ };
+ static const T Q[] = {
+ 1,
+ -2.9629552288944259229543137757200262073L,
+ 3.7118380799042118987185957298964772755L,
+ -2.5569815272165399297600586376727357187L,
+ 1.0546764918220835097855665680632153367L,
+ -0.26574021300894401276478730940980810831L,
+ 0.03996289731752081380552901986471233462L,
+ -0.0033398680924544836817826046380586480873L,
+ 0.00013288854760548251757651556792598235735L,
+ -0.17194794958274081373243161848194745111e-5L
+ };
+ T r = zm2 * zm1;
+ T R = tools::evaluate_polynomial(P, 0.625 - zm1) / tools::evaluate_polynomial(Q, 0.625 - zm1);
+
+ result += r * Y + r * R;
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ else
+ {
+ //
+ // Same form as above.
+ //
+ // Max error found (at 128-bit long double precision) 1.831e-35
+ // Maximum Deviation Found (approximation error) 8.588e-36
+ // Expected Error Term (theoretical error) 1.458e-36
+ //
+ static const float Y = 0.443811893463134765625f;
+
+ static const T P[] = {
+ -0.021027558364667626231512090082402429494L,
+ 0.15128811104498736604523586803722368377L,
+ -0.26249631480066246699388544451126410278L,
+ 0.21148748610533489823742352180628489742L,
+ -0.093964130697489071999873506148104370633L,
+ 0.024292059227009051652542804957550866827L,
+ -0.0036284453226534839926304745756906117066L,
+ 0.0002939230129315195346843036254392485984L,
+ -0.11088589183158123733132268042570710338e-4L,
+ 0.13240510580220763969511741896361984162e-6L
+ };
+ static const T Q[] = {
+ 1,
+ -2.4240003754444040525462170802796471996L,
+ 2.4868383476933178722203278602342786002L,
+ -1.4047068395206343375520721509193698547L,
+ 0.47583809087867443858344765659065773369L,
+ -0.09865724264554556400463655444270700132L,
+ 0.012238223514176587501074150988445109735L,
+ -0.00084625068418239194670614419707491797097L,
+ 0.2796574430456237061420839429225710602e-4L,
+ -0.30202973883316730694433702165188835331e-6L
+ };
+ // (2 - x) * (1 - x) * (c + R(2 - x))
+ T r = zm2 * zm1;
+ T R = tools::evaluate_polynomial(P, -zm2) / tools::evaluate_polynomial(Q, -zm2);
+
+ result += r * Y + r * R;
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ }
+ }
+ BOOST_MATH_INSTRUMENT_CODE(result);
+ return result;
+}
+template <class T, class Policy, class L>
+T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<0>&, const Policy& pol, const L&)
+{
+ //
+ // No rational approximations are available because either
+ // T has no numeric_limits support (so we can't tell how
+ // many digits it has), or T has more digits than we know
+ // what to do with.... we do have a Lanczos approximation
+ // though, and that can be used to keep errors under control.
+ //
+ BOOST_MATH_STD_USING // for ADL of std names
+ T result = 0;
+ if(z < tools::epsilon<T>())
+ {
+ result = -log(z);
+ }
+ else if(z < 0.5)
+ {
+ // taking the log of tgamma reduces the error, no danger of overflow here:
+ result = log(gamma_imp(z, pol, L()));
+ }
+ else if(z >= 3)
+ {
+ // taking the log of tgamma reduces the error, no danger of overflow here:
+ result = log(gamma_imp(z, pol, L()));
+ }
+ else if(z >= 1.5)
+ {
+ // special case near 2:
+ T dz = zm2;
+ result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e<T>());
+ result += boost::math::log1p(dz / (L::g() + T(1.5)), pol) * T(1.5);
+ result += boost::math::log1p(L::lanczos_sum_near_2(dz), pol);
+ }
+ else
+ {
+ // special case near 1:
+ T dz = zm1;
+ result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e<T>());
+ result += boost::math::log1p(dz / (L::g() + T(0.5)), pol) / 2;
+ result += boost::math::log1p(L::lanczos_sum_near_1(dz), pol);
+ }
+ return result;
+}
+
+}}} // namespaces
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
Deleted: branches/bcbboost/boost/math/special_functions/detail/series.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/detail/series.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
+++ (empty file)
@@ -1,52 +0,0 @@
-// (C) Copyright John Maddock 2005.
-// 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_SERIES_INCLUDED
-#define BOOST_MATH_SERIES_INCLUDED
-
-#include <cmath>
-
-#ifdef BOOST_NO_STDC_NAMESPACE
-namespace std{ using ::pow; using ::fabs; }
-#endif
-
-
-namespace boost{ namespace math{ namespace detail{
-
-//
-// Algorithm kahan_sum_series invokes Functor func until the N'th
-// term is too small to have any effect on the total, the terms
-// are added using the Kahan summation method.
-//
-// CAUTION: Optimizing compilers combined with extended-precision
-// machine registers conspire to render this algorithm partly broken:
-// double rounding of intermediate terms (first to a long double machine
-// register, and then to a double result) cause the rounding error computed
-// by the algorithm to be off by up to 1ulp. However this occurs rarely, and
-// in any case the result is still much better than a naive summation.
-//
-template <class Functor>
-typename Functor::result_type kahan_sum_series(Functor& func, int bits)
-{
- typedef typename Functor::result_type result_type;
- result_type factor = std::pow(result_type(2), bits);
- result_type result = func();
- result_type next_term, y, t;
- result_type carry = 0;
- do{
- next_term = func();
- y = next_term - carry;
- t = result + y;
- carry = t - result;
- carry -= y;
- result = t;
- }
- while(std::fabs(result) < std::fabs(factor * next_term));
- return result;
-}
-
-} } } // namespaces
-
-#endif // BOOST_MATH_SERIES_INCLUDED
Added: branches/bcbboost/boost/math/special_functions/detail/simple_complex.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/simple_complex.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,167 @@
+// 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_SF_DETAIL_SIMPLE_COMPLEX_HPP
+#define BOOST_MATH_SF_DETAIL_SIMPLE_COMPLEX_HPP
+
+namespace boost{ namespace math{ namespace detail{ namespace sc{
+
+template <class T>
+class simple_complex
+{
+public:
+ simple_complex() : r(0), i(0) {}
+ simple_complex(T a) : r(a) {}
+ template <class U>
+ simple_complex(U a) : r(a) {}
+ simple_complex(T a, T b) : r(a), i(b) {}
+
+ simple_complex& operator += (const simple_complex& o)
+ {
+ r += o.r;
+ i += o.i;
+ return *this;
+ }
+ simple_complex& operator -= (const simple_complex& o)
+ {
+ r -= o.r;
+ i -= o.i;
+ return *this;
+ }
+ simple_complex& operator *= (const simple_complex& o)
+ {
+ T lr = r * o.r - i * o.i;
+ T li = i * o.r + r * o.i;
+ r = lr;
+ i = li;
+ return *this;
+ }
+ simple_complex& operator /= (const simple_complex& o)
+ {
+ BOOST_MATH_STD_USING
+ T lr;
+ T li;
+ if(fabs(o.r) > fabs(o.i))
+ {
+ T rat = o.i / o.r;
+ lr = r + i * rat;
+ li = i - r * rat;
+ rat = o.r + o.i * rat;
+ lr /= rat;
+ li /= rat;
+ }
+ else
+ {
+ T rat = o.r / o.i;
+ lr = i + r * rat;
+ li = i * rat - r;
+ rat = o.r * rat + o.i;
+ lr /= rat;
+ li /= rat;
+ }
+ r = lr;
+ i = li;
+ return *this;
+ }
+ bool operator == (const simple_complex& o)
+ {
+ return (r == o.r) && (i == o.i);
+ }
+ bool operator != (const simple_complex& o)
+ {
+ return !((r == o.r) && (i == o.i));
+ }
+ bool operator == (const T& o)
+ {
+ return (r == o) && (i == 0);
+ }
+ simple_complex& operator += (const T& o)
+ {
+ r += o;
+ return *this;
+ }
+ simple_complex& operator -= (const T& o)
+ {
+ r -= o;
+ return *this;
+ }
+ simple_complex& operator *= (const T& o)
+ {
+ r *= o;
+ i *= o;
+ return *this;
+ }
+ simple_complex& operator /= (const T& o)
+ {
+ r /= o;
+ i /= o;
+ return *this;
+ }
+ T real()const
+ {
+ return r;
+ }
+ T imag()const
+ {
+ return i;
+ }
+private:
+ T r, i;
+};
+
+template <class T>
+inline simple_complex<T> operator+(const simple_complex<T>& a, const simple_complex<T>& b)
+{
+ simple_complex<T> result(a);
+ result += b;
+ return result;
+}
+
+template <class T>
+inline simple_complex<T> operator-(const simple_complex<T>& a, const simple_complex<T>& b)
+{
+ simple_complex<T> result(a);
+ result -= b;
+ return result;
+}
+
+template <class T>
+inline simple_complex<T> operator*(const simple_complex<T>& a, const simple_complex<T>& b)
+{
+ simple_complex<T> result(a);
+ result *= b;
+ return result;
+}
+
+template <class T>
+inline simple_complex<T> operator/(const simple_complex<T>& a, const simple_complex<T>& b)
+{
+ simple_complex<T> result(a);
+ result /= b;
+ return result;
+}
+
+template <class T>
+inline T real(const simple_complex<T>& c)
+{
+ return c.real();
+}
+
+template <class T>
+inline T imag(const simple_complex<T>& c)
+{
+ return c.imag();
+}
+
+template <class T>
+inline T abs(const simple_complex<T>& c)
+{
+ return hypot(c.real(), c.imag());
+}
+
+}}}} // namespace
+
+#endif
+
Added: branches/bcbboost/boost/math/special_functions/detail/t_distribution_inv.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/t_distribution_inv.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,509 @@
+// 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
+
+#include <boost/math/special_functions/cbrt.hpp>
+
+namespace boost{ namespace math{ namespace detail{
+
+//
+// The main method used is due to Hill:
+//
+// G. W. Hill, Algorithm 396, Students 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 Students 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(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):
+ //
+ c[2] = T(1) / 6 + T(1) / (6 * df);
+ T in = 1 / df;
+ c[3] = (((T(1) / 120) * in) + (T(1) / 15)) * in + (T(7) / 120);
+ c[4] = ((((T(1) / 5040) * in + (T(1) / 560)) * in + (T(3) / 112)) * in + T(127) / 5040);
+ c[5] = ((((T(1) / 362880) * in + (T(17) / 45360)) * in + (T(67) / 60480)) * in + (T(479) / 45360)) * in + (T(4369) / 362880);
+ c[6] = ((((((T(1) / 39916800) * in + (T(2503) / 39916800)) * in + (T(11867) / 19958400)) * in + (T(1285) / 798336)) * in + (T(153161) / 39916800)) * in + (T(34807) / 5702400));
+ c[7] = (((((((T(1) / 6227020800LL) * in + (T(37) / 2402400)) * in +
+ (T(339929) / 2075673600LL)) * in + (T(67217) / 97297200)) * in +
+ (T(870341) / 691891200LL)) * in + (T(70691) / 64864800LL)) * in +
+ (T(20036983LL) / 6227020800LL));
+ c[8] = (((((((T(1) / 1307674368000LL) * in + (T(1042243LL) / 261534873600LL)) * in +
+ (T(21470159) / 435891456000LL)) * in + (T(326228899LL) / 1307674368000LL)) * in +
+ (T(843620579) / 1307674368000LL)) * in + (T(332346031LL) / 435891456000LL)) * in +
+ (T(43847599) / 1307674368000LL)) * in + (T(2280356863LL) / 1307674368000LL);
+ c[9] = (((((((((T(1) / 355687428096000LL)) * in + (T(24262727LL) / 22230464256000LL)) * in +
+ (T(123706507LL) / 8083805184000LL)) * in + (T(404003599LL) / 4446092851200LL)) * in +
+ (T(51811946317LL) / 177843714048000LL)) * in + (T(91423417LL) / 177843714048LL)) * in +
+ (T(32285445833LL) / 88921857024000LL)) * in + (T(531839683LL) / 1710035712000LL)) * in +
+ (T(49020204823LL) / 50812489728000LL);
+ c[10] = (((((((((T(1) / 121645100408832000LL) * in +
+ (T(4222378423LL) / 13516122267648000LL)) * in +
+ (T(49573465457LL) / 10137091700736000LL)) * in +
+ (T(176126809LL) / 5304600576000LL)) * in +
+ (T(44978231873LL) / 355687428096000LL)) * in +
+ (T(5816850595639LL) / 20274183401472000LL)) * in +
+ (T(73989712601LL) / 206879422464000LL)) * in +
+ (T(26591354017LL) / 259925428224000LL)) * in +
+ (T(14979648446341LL) / 40548366802944000LL)) * in +
+ (T(65967241200001LL) / 121645100408832000LL);
+ //
+ // The result is then a polynomial in v (see Eq 56 of Shaw):
+ //
+ return tools::evaluate_odd_polynomial(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(boost::math::tools::real_cast<int>(df))
+ {
+ 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 ? -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.85498797333834849467655443627193L;
+ 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 ? -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, tools::real_cast<int>(df / -0.654f));
+ 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 ? -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) ? 0.5f - q / 2 : 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;
+ 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, 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)> 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
+
+
Added: branches/bcbboost/boost/math/special_functions/detail/unchecked_factorial.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/detail/unchecked_factorial.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,398 @@
+// 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
+
+#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 <cmath>
+
+namespace boost { namespace math
+{
+// Forward declarations:
+template <class T>
+T unchecked_factorial(unsigned i);
+template <class T>
+struct max_factorial;
+
+// efinitions:
+template <>
+inline float unchecked_factorial<float>(unsigned i)
+{
+ 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)
+{
+ 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(unsigned i)
+{
+ return static_cast<double>(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)
+{
+ 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);
+};
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_SP_UC_FACTORIALS_HPP
Added: branches/bcbboost/boost/math/special_functions/digamma.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/digamma.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,445 @@
+// (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
+
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/tools/promotion.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/mpl/comparison.hpp>
+
+namespace boost{
+namespace math{
+namespace detail{
+//
+// Begin by defining the smallest value for which it is safe to
+// use the asymptotic expansion for digamma:
+//
+inline unsigned digamma_large_lim(const mpl::int_<0>*)
+{ return 20; }
+
+inline unsigned digamma_large_lim(const void*)
+{ return 10; }
+//
+// Implementations of the asymptotic expansion come next,
+// the coefficients of the series have been evaluated
+// in advance at high precision, and the series truncated
+// at the first term that's too small to effect the result.
+// Note that the series becomes divergent after a while
+// so truncation is very important.
+//
+// This first one gives 34-digit precision for x >= 20:
+//
+template <class T>
+inline T digamma_imp_large(T x, const mpl::int_<0>*)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+ static const T P[] = {
+ 0.083333333333333333333333333333333333333333333333333L,
+ -0.0083333333333333333333333333333333333333333333333333L,
+ 0.003968253968253968253968253968253968253968253968254L,
+ -0.0041666666666666666666666666666666666666666666666667L,
+ 0.0075757575757575757575757575757575757575757575757576L,
+ -0.021092796092796092796092796092796092796092796092796L,
+ 0.083333333333333333333333333333333333333333333333333L,
+ -0.44325980392156862745098039215686274509803921568627L,
+ 3.0539543302701197438039543302701197438039543302701L,
+ -26.456212121212121212121212121212121212121212121212L,
+ 281.4601449275362318840579710144927536231884057971L,
+ -3607.510546398046398046398046398046398046398046398L,
+ 54827.583333333333333333333333333333333333333333333L,
+ -974936.82385057471264367816091954022988505747126437L,
+ 20052695.796688078946143462272494530559046688078946L,
+ -472384867.72162990196078431372549019607843137254902L,
+ 12635724795.916666666666666666666666666666666666667L
+ };
+ x -= 1;
+ T result = log(x);
+ result += 1 / (2 * x);
+ T z = 1 / (x*x);
+ result -= z * tools::evaluate_polynomial(P, z);
+ return result;
+}
+//
+// 19-digit precision for x >= 10:
+//
+template <class T>
+inline T digamma_imp_large(T x, const mpl::int_<64>*)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+ static const T P[] = {
+ 0.083333333333333333333333333333333333333333333333333L,
+ -0.0083333333333333333333333333333333333333333333333333L,
+ 0.003968253968253968253968253968253968253968253968254L,
+ -0.0041666666666666666666666666666666666666666666666667L,
+ 0.0075757575757575757575757575757575757575757575757576L,
+ -0.021092796092796092796092796092796092796092796092796L,
+ 0.083333333333333333333333333333333333333333333333333L,
+ -0.44325980392156862745098039215686274509803921568627L,
+ 3.0539543302701197438039543302701197438039543302701L,
+ -26.456212121212121212121212121212121212121212121212L,
+ 281.4601449275362318840579710144927536231884057971L,
+ };
+ x -= 1;
+ T result = log(x);
+ result += 1 / (2 * x);
+ T z = 1 / (x*x);
+ result -= z * tools::evaluate_polynomial(P, z);
+ return result;
+}
+//
+// 17-digit precision for x >= 10:
+//
+template <class T>
+inline T digamma_imp_large(T x, const mpl::int_<53>*)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+ static const T P[] = {
+ 0.083333333333333333333333333333333333333333333333333L,
+ -0.0083333333333333333333333333333333333333333333333333L,
+ 0.003968253968253968253968253968253968253968253968254L,
+ -0.0041666666666666666666666666666666666666666666666667L,
+ 0.0075757575757575757575757575757575757575757575757576L,
+ -0.021092796092796092796092796092796092796092796092796L,
+ 0.083333333333333333333333333333333333333333333333333L,
+ -0.44325980392156862745098039215686274509803921568627L
+ };
+ x -= 1;
+ T result = log(x);
+ result += 1 / (2 * x);
+ T z = 1 / (x*x);
+ result -= z * tools::evaluate_polynomial(P, z);
+ return result;
+}
+//
+// 9-digit precision for x >= 10:
+//
+template <class T>
+inline T digamma_imp_large(T x, const mpl::int_<24>*)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+ static const T P[] = {
+ 0.083333333333333333333333333333333333333333333333333L,
+ -0.0083333333333333333333333333333333333333333333333333L,
+ 0.003968253968253968253968253968253968253968253968254L
+ };
+ x -= 1;
+ T result = log(x);
+ result += 1 / (2 * x);
+ T z = 1 / (x*x);
+ result -= z * tools::evaluate_polynomial(P, z);
+ return result;
+}
+//
+// Now follow rational approximations over the range [1,2].
+//
+// 35-digit precision:
+//
+template <class T>
+T digamma_imp_1_2(T x, const mpl::int_<0>*)
+{
+ //
+ // Now the approximation, we use the form:
+ //
+ // digamma(x) = (x - root) * (Y + R(x-1))
+ //
+ // Where root is the location of the positive root of digamma,
+ // Y is a constant, and R is optimised for low absolute error
+ // compared to Y.
+ //
+ // Max error found at 128-bit long double precision: 5.541e-35
+ // Maximum Deviation Found (approximation error): 1.965e-35
+ //
+ static const float Y = 0.99558162689208984375F;
+
+ static const T root1 = 1569415565.0 / 1073741824uL;
+ static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
+ static const T root3 = ((111616537.0 / 1073741824uL) / 1073741824uL) / 1073741824uL;
+ static const T root4 = (((503992070.0 / 1073741824uL) / 1073741824uL) / 1073741824uL) / 1073741824uL;
+ static const T root5 = 0.52112228569249997894452490385577338504019838794544e-36L;
+
+ static const T P[] = {
+ 0.25479851061131551526977464225335883769L,
+ -0.18684290534374944114622235683619897417L,
+ -0.80360876047931768958995775910991929922L,
+ -0.67227342794829064330498117008564270136L,
+ -0.26569010991230617151285010695543858005L,
+ -0.05775672694575986971640757748003553385L,
+ -0.0071432147823164975485922555833274240665L,
+ -0.00048740753910766168912364555706064993274L,
+ -0.16454996865214115723416538844975174761e-4L,
+ -0.20327832297631728077731148515093164955e-6L
+ };
+ static const T Q[] = {
+ 1,
+ 2.6210924610812025425088411043163287646L,
+ 2.6850757078559596612621337395886392594L,
+ 1.4320913706209965531250495490639289418L,
+ 0.4410872083455009362557012239501953402L,
+ 0.081385727399251729505165509278152487225L,
+ 0.0089478633066857163432104815183858149496L,
+ 0.00055861622855066424871506755481997374154L,
+ 0.1760168552357342401304462967950178554e-4L,
+ 0.20585454493572473724556649516040874384e-6L,
+ -0.90745971844439990284514121823069162795e-11L,
+ 0.48857673606545846774761343500033283272e-13L,
+ };
+ T g = x - root1;
+ g -= root2;
+ g -= root3;
+ g -= root4;
+ g -= root5;
+ T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
+ T result = g * Y + g * r;
+
+ return result;
+}
+//
+// 19-digit precision:
+//
+template <class T>
+T digamma_imp_1_2(T x, const mpl::int_<64>*)
+{
+ //
+ // Now the approximation, we use the form:
+ //
+ // digamma(x) = (x - root) * (Y + R(x-1))
+ //
+ // Where root is the location of the positive root of digamma,
+ // Y is a constant, and R is optimised for low absolute error
+ // compared to Y.
+ //
+ // Max error found at 80-bit long double precision: 5.016e-20
+ // Maximum Deviation Found (approximation error): 3.575e-20
+ //
+ static const float Y = 0.99558162689208984375F;
+
+ static const T root1 = 1569415565.0 / 1073741824uL;
+ static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
+ static const T root3 = 0.9016312093258695918615325266959189453125e-19L;
+
+ static const T P[] = {
+ 0.254798510611315515235L,
+ -0.314628554532916496608L,
+ -0.665836341559876230295L,
+ -0.314767657147375752913L,
+ -0.0541156266153505273939L,
+ -0.00289268368333918761452L
+ };
+ static const T Q[] = {
+ 1,
+ 2.1195759927055347547L,
+ 1.54350554664961128724L,
+ 0.486986018231042975162L,
+ 0.0660481487173569812846L,
+ 0.00298999662592323990972L,
+ -0.165079794012604905639e-5L,
+ 0.317940243105952177571e-7L
+ };
+ T g = x - root1;
+ g -= root2;
+ g -= root3;
+ T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
+ T result = g * Y + g * r;
+
+ return result;
+}
+//
+// 18-digit precision:
+//
+template <class T>
+T digamma_imp_1_2(T x, const mpl::int_<53>*)
+{
+ //
+ // Now the approximation, we use the form:
+ //
+ // digamma(x) = (x - root) * (Y + R(x-1))
+ //
+ // Where root is the location of the positive root of digamma,
+ // Y is a constant, and R is optimised for low absolute error
+ // compared to Y.
+ //
+ // Maximum Deviation Found: 1.466e-18
+ // At double precision, max error found: 2.452e-17
+ //
+ static const float Y = 0.99558162689208984F;
+
+ static const T root1 = 1569415565.0 / 1073741824uL;
+ static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
+ static const T root3 = 0.9016312093258695918615325266959189453125e-19L;
+
+ static const T P[] = {
+ 0.25479851061131551L,
+ -0.32555031186804491L,
+ -0.65031853770896507L,
+ -0.28919126444774784L,
+ -0.045251321448739056L,
+ -0.0020713321167745952L
+ };
+ static const T Q[] = {
+ 1L,
+ 2.0767117023730469L,
+ 1.4606242909763515L,
+ 0.43593529692665969L,
+ 0.054151797245674225L,
+ 0.0021284987017821144L,
+ -0.55789841321675513e-6L
+ };
+ T g = x - root1;
+ g -= root2;
+ g -= root3;
+ T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
+ T result = g * Y + g * r;
+
+ return result;
+}
+//
+// 9-digit precision:
+//
+template <class T>
+inline T digamma_imp_1_2(T x, const mpl::int_<24>*)
+{
+ //
+ // Now the approximation, we use the form:
+ //
+ // digamma(x) = (x - root) * (Y + R(x-1))
+ //
+ // Where root is the location of the positive root of digamma,
+ // Y is a constant, and R is optimised for low absolute error
+ // compared to Y.
+ //
+ // Maximum Deviation Found: 3.388e-010
+ // At float precision, max error found: 2.008725e-008
+ //
+ static const float Y = 0.99558162689208984f;
+ static const T root = 1532632.0f / 1048576;
+ static const T root_minor = static_cast<T>(0.3700660185912626595423257213284682051735604e-6L);
+ static const T P[] = {
+ 0.25479851023250261e0,
+ -0.44981331915268368e0,
+ -0.43916936919946835e0,
+ -0.61041765350579073e-1
+ };
+ static const T Q[] = {
+ 0.1e1,
+ 0.15890202430554952e1,
+ 0.65341249856146947e0,
+ 0.63851690523355715e-1
+ };
+ T g = x - root;
+ g -= root_minor;
+ T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
+ T result = g * Y + g * r;
+
+ return result;
+}
+
+template <class T, class Tag, class Policy>
+T digamma_imp(T x, const Tag* t, const Policy& pol)
+{
+ //
+ // This handles reflection of negative arguments, and all our
+ // error handling, then forwards to the T-specific approximation.
+ //
+ BOOST_MATH_STD_USING // ADL of std functions.
+
+ T result = 0;
+ //
+ // Check for negative arguments and use reflection:
+ //
+ if(x < 0)
+ {
+ // Reflect:
+ x = 1 - x;
+ // Argument reduction for tan:
+ T remainder = x - floor(x);
+ // Shift to negative if > 0.5:
+ if(remainder > 0.5)
+ {
+ remainder -= 1;
+ }
+ //
+ // check for evaluation at a negative pole:
+ //
+ if(remainder == 0)
+ {
+ return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", 0, (1-x), pol);
+ }
+ result = constants::pi<T>() / tan(constants::pi<T>() * remainder);
+ }
+ //
+ // If we're above the lower-limit for the
+ // asymptotic expansion then use it:
+ //
+ if(x >= digamma_large_lim(t))
+ {
+ result += digamma_imp_large(x, t);
+ }
+ else
+ {
+ //
+ // If x > 2 reduce to the interval [1,2]:
+ //
+ while(x > 2)
+ {
+ x -= 1;
+ result += 1/x;
+ }
+ //
+ // If x < 1 use recurrance to shift to > 1:
+ //
+ if(x < 1)
+ {
+ result = -1/x;
+ x += 1;
+ }
+ result += digamma_imp_1_2(x, t);
+ }
+ return result;
+}
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type
+ digamma(T x, const Policy& pol)
+{
+ typedef typename tools::promote_args<T>::type result_type;
+ typedef typename policies::evaluation<result_type, Policy>::type value_type;
+ typedef typename policies::precision<T, Policy>::type precision_type;
+ typedef typename mpl::if_<
+ mpl::or_<
+ mpl::less_equal<precision_type, mpl::int_<0> >,
+ mpl::greater<precision_type, mpl::int_<64> >
+ >,
+ mpl::int_<0>,
+ typename mpl::if_<
+ mpl::less<precision_type, mpl::int_<25> >,
+ mpl::int_<24>,
+ typename mpl::if_<
+ mpl::less<precision_type, mpl::int_<54> >,
+ mpl::int_<53>,
+ mpl::int_<64>
+ >::type
+ >::type
+ >::type tag_type;
+
+ return policies::checked_narrowing_cast<result_type, Policy>(detail::digamma_imp(
+ static_cast<value_type>(x),
+ static_cast<const tag_type*>(0), pol), "boost::math::digamma<%1%>(%1%)");
+}
+
+template <class T>
+inline typename tools::promote_args<T>::type
+ digamma(T x)
+{
+ return digamma(x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+#endif
Added: branches/bcbboost/boost/math/special_functions/ellint_1.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/ellint_1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,178 @@
+// 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
+
+#include <boost/math/special_functions/ellint_rf.hpp>
+#include <boost/math/constants/constants.hpp>
+#include <boost/math/policies/error_handling.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{
+
+// 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, constants::pi<T>() / 2);
+ BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
+ T m = 2 * (phi - rphi) / 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(cosp * cosp, 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 ? -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
Added: branches/bcbboost/boost/math/special_functions/ellint_2.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/ellint_2.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,162 @@
+// 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
+
+#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>
+
+// 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, constants::pi<T>() / 2);
+ T m = 2 * (phi - rphi) / 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 ? -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
Added: branches/bcbboost/boost/math/special_functions/ellint_3.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/ellint_3.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,326 @@
+// 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
+
+#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>
+
+// Elliptic integrals (complete and incomplete) of the third kind
+// Carlson, Numerische Mathematik, vol 33, 1 (1979)
+
+namespace boost { namespace math {
+
+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);
+
+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(fabs(phi), constants::pi<T>() / 2);
+ T m = 2 * (fabs(phi) - rphi) / 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;
+ }
+
+ if((m > 0) && (v > 1))
+ {
+ //
+ // The region with v > 1 and phi outside [0, pi/2] is
+ // currently unsupported:
+ //
+ return policies::raise_domain_error<T>(
+ function,
+ "Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol);
+ }
+ 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)
+ 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>
+inline typename tools::promote_args<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
Added: branches/bcbboost/boost/math/special_functions/ellint_rc.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/ellint_rc.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,110 @@
+// 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
+
+#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(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
Added: branches/bcbboost/boost/math/special_functions/ellint_rd.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/ellint_rd.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,125 @@
+// 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
+
+#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(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
Added: branches/bcbboost/boost/math/special_functions/ellint_rf.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/ellint_rf.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -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)
+//
+// 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
+
+#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(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
Added: branches/bcbboost/boost/math/special_functions/ellint_rj.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/ellint_rj.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,174 @@
+// 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
+
+#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>
+
+// 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 = ellint_rj(x, y, z, p, pol);
+ value *= pmy;
+ value -= 3 * ellint_rf(x, y, z, pol);
+ value += 3 * sqrt((x * y * z) / (x * z + p * q)) * 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 * 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(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
Added: branches/bcbboost/boost/math/special_functions/erf.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/erf.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,858 @@
+// (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
+
+#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>
+
+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(-z, invert, pol, t);
+ else
+ return 1 + erf_imp(-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::digits<T, Policy>(), max_iter, 1);
+ policies::check_series_iterations("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::digits<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(-z, invert, pol, t);
+ else if(z < -0.5)
+ return 2 - erf_imp(-z, invert, pol, t);
+ else
+ return 1 + erf_imp(-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 = T(0);
+ }
+ else if(z < 1e-10)
+ {
+ result = static_cast<T>(z * 1.125f + z * 0.003379167095512573896158903121545171688L);
+ }
+ else
+ {
+ static const T n[7] = { 0.00337916709551257778174L, -0.000147024115786688745475L, -0.37463022236812520164L, 0.0163061594494816999803L, -0.0534354147807331748737L, 0.00161898096813581982844L, -0.0059528010489182840404L };
+ static const T d[7] = { 1, -0.0435089806536379531594L, 0.442761965043509204727L, -0.017375974533016704678L, 0.0772756490303260060769L, -0.00210552465858669941879L, 0.00544772980263244037286L };
+ result = static_cast<T>(z * 1.125f + z * tools::evaluate_polynomial(n, z) / tools::evaluate_polynomial(d, z));
+ }
+ }
+ else if((z < 14) || ((z < 28) && invert))
+ {
+ //
+ // We'll be calculating erfc:
+ //
+ invert = !invert;
+ T r, b;
+ if(z < 0.75)
+ {
+ // Worst case absolute error found: 8.554649561e-018
+ static const T n[5] = { -0.0361790390718262468222L, 0.301888464724047222196L, 0.201731143672633894981L, 0.0659353268087389983319L, 0.00721876720062364930761L };
+ static const T d[6] = { 1, 1.58814245739127341535L, 0.99354580430196422336L, 0.291753007176902027213L, 0.033994791234913855515L, -0.000104234653166533504303L };
+ static const float f0 = 0.3440242112F;
+ r = tools::evaluate_polynomial(n, z - 0.5) / tools::evaluate_polynomial(d, z - 0.5);
+ b = f0;
+ }
+ else if(z < 1.25)
+ {
+ // Worst case absolute error found: 6.50251514e-018
+ static const T n[6] = { -0.039787689261113685983L, 0.160309168830518003303L, 0.163049978514596540313L, 0.0710685660158400750009L, 0.01497188097404877543L, 0.00130080628375002584279L };
+ static const T d[6] = { 1, 1.77564880074171280407L, 1.31438791181040008779L, 0.509359151038517059748L, 0.103958527905812829559L, 0.00901292460643094469406L };
+ static const float f0 = 0.419990927F;
+ r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75);
+ b = f0;
+ }
+ else if(z < 2.25)
+ {
+ // Worst case absolute error found: 1.132743504e-017
+ static const T n[6] = { -0.0300838560557949724172L, 0.0592886319615167248092L, 0.0622294724048409148736L, 0.0248575228109427909578L, 0.00463781847004901844581L, 0.000347305179334822548368L };
+ static const T d[7] = { 1, 1.57915060645728571344L, 1.03342495188878679417L, 0.35158678814344218974L, 0.062469256580984456783L, 0.00466640448020624599948L, 0.290106403940303572448e-6L };
+ static const float f0 = 0.4898625016F;
+ r = tools::evaluate_polynomial(n, z - 1.25) / tools::evaluate_polynomial(d, z - 1.25);
+ b = f0;
+ }
+ else if(z < 3.5)
+ {
+ // Worst case absolute error found: 3.446364609e-018
+ static const T n[6] = { -0.0117907570137227857015L, 0.0162667227692515660221L, 0.0175329212378413544794L, 0.00620897681269247137578L, 0.000986614895094589251706L, 0.601354618401624353425e-4L };
+ static const T d[6] = { 1, 1.33374851361555383557L, 0.73227756904205983415L, 0.207410266363727673685L, 0.0304034048466731110163L, 0.00185296959991832048613L };
+ static const float f0 = 0.5317370892F;
+ r = tools::evaluate_polynomial(n, z - 2.25) / tools::evaluate_polynomial(d, z - 2.25);
+ b = f0;
+ }
+ else if(z < 5.5)
+ {
+ // Worst case absolute error found: 1.579588208e-018
+ static const T n[6] = { -0.00588219091116732271979L, 0.00434428684527812140098L, 0.00466899990542371512895L, 0.00139937567253199794533L, 0.000179205902444982389766L, 0.845033527560949509345e-5L };
+ static const T d[6] = { 1, 1.07389345953392962127L, 0.470965611895885060643L, 0.105594730223366124873L, 0.0121252833787344059719L, 0.000571755036133730341579L };
+ static const float f0 = 0.5494099855F;
+ r = tools::evaluate_polynomial(n, z - 3.5) / tools::evaluate_polynomial(d, z - 3.5);
+ b = f0;
+ }
+ else if(z < 9)
+ {
+ // Worst case absolute error found: 1.410768708e-017
+ static const T n[5] = { -0.00273864253749621265032L, 0.0013089921066773026803L, 0.000775841526778089659703L, 0.000110909476102006410909L, 0.472577590124068298534e-5L };
+ static const T d[6] = { 1, 0.650694792327863647878L, 0.161126734432670927888L, 0.0180081468446110640846L, 0.000767341359508884026192L, -0.287636719206664167616e-9L };
+ static const float f0 = 0.5580308437F;
+ r = tools::evaluate_polynomial(n, z - 5.5) / tools::evaluate_polynomial(d, z - 5.5);
+ b = f0;
+ }
+ else if(z < 14)
+ {
+ // Worst case absolute error found: 1.458310511e-018
+ static const T n[5] = { -0.000995856413171151859346L, 0.000320252910249376187643L, 0.000129085624923151780987L, 0.121577881306587454509e-4L, 0.33293110334156470348e-6L };
+ static const T d[5] = { 1, 0.428034987547594828954L, 0.0692297359775940896439L, 0.00501515176145997560701L, 0.00013733589151338416322L };
+ static const float f0 = 0.5617653728F;
+ r = tools::evaluate_polynomial(n, z - 9) / tools::evaluate_polynomial(d, z - 9);
+ b = f0;
+ }
+ else if(z < 21)
+ {
+ // Worst case absolute error found: 1.08182873e-019
+ static const T n[5] = { -0.000395463268432048215535L, 0.91155953112698182321e-4L, 0.237451641259281193813e-4L, 0.145759953022524466816e-5L, 0.259395907606548998142e-7L };
+ static const T d[5] = { 1, 0.281604524251560309285L, 0.0298468482900092392397L, 0.00141114575715338885136L, 0.251128951158576064819e-4L };
+ static const float f0 = 0.5631566644F;
+ r = tools::evaluate_polynomial(n, z - 14) / tools::evaluate_polynomial(d, z - 14);
+ b = f0;
+ }
+ else
+ {
+ // Worst case absolute error found: 7.010370259e-018
+ static const T n[4] = { -0.000139182098873874523526L, 0.395254617101737287826e-4L, 0.376801239136290345387e-5L, 0.629017242098850415839e-7L };
+ static const T d[4] = { 1, 0.15077096006891495258L, 0.00756136203065884121997L, 0.000126226197336507576933L };
+ static const float f0 = 0.5636912584F;
+ r = tools::evaluate_polynomial(n, z - 21) / tools::evaluate_polynomial(d, z - 21);
+ b = f0;
+ }
+ T g = exp(-z * z) / z;
+ result = g * b + g * r;
+ }
+ 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 L>T erf_imp(T z, bool invert, const L& 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(-z, invert, pol, t);
+ else if(z < -0.5)
+ return 2 - erf_imp(-z, invert, pol, t);
+ else
+ return 1 + erf_imp(-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)
+ {
+ result = z * 1.125 + z * 0.003379167095512573896158903121545171688L;
+ }
+ else
+ {
+ // Worst case absolute error found: 6.688618532e-21
+ static const T n[8] = { 0.00337916709551257388990745L, -0.00073695653048167948530905L, -0.374732337392919607868241L, 0.0817442448733587196071743L, -0.0421089319936548595203468L, 0.0070165709512095756344528L, -0.00495091255982435110337458L, 0.000871646599037922480317225L };
+ static const T d[8] = { 1L, -0.218088218087924645390535L, 0.412542972725442099083918L, -0.0841891147873106755410271L, 0.0655338856400241519690695L, -0.0120019604454941768171266L, 0.00408165558926174048329689L, -0.000615900721557769691924509L };
+ result = z * 1.125 + z * tools::evaluate_polynomial(n, z) / tools::evaluate_polynomial(d, z);
+ }
+ }
+ else if((z < 110) || ((z < 110) && invert)) // TODO FIXME!!!
+ {
+ //
+ // We'll be calculating erfc:
+ //
+ invert = !invert;
+ T r, b;
+ if(z < 0.75)
+ {
+ // Worst case absolute error found: 5.582813374e-21
+ static const T n[6] = { -0.0361790390718262471360258L, 0.292251883444882683221149L, 0.281447041797604512774415L, 0.125610208862766947294894L, 0.0274135028268930549240776L, 0.00250839672168065762786937L };
+ static const T d[6] = { 1L, 1.8545005897903486499845L, 1.43575803037831418074962L, 0.582827658753036572454135L, 0.124810476932949746447682L, 0.0113724176546353285778481L };
+ static const float f0 = 0.3440242112F;
+ r = tools::evaluate_polynomial(n, z - 0.5) / tools::evaluate_polynomial(d, z - 0.5);
+ b = f0;
+ }
+ else if(z < 1.25)
+ {
+ // Worst case absolute error found: 4.01854729e-21
+ static const T n[7] = { -0.0397876892611136856954425L, 0.153165212467878293257683L, 0.191260295600936245503129L, 0.10276327061989304213645L, 0.029637090615738836726027L, 0.0046093486780275489468812L, 0.000307607820348680180548455L };
+ static const T d[7] = { 1L, 1.95520072987627704987886L, 1.64762317199384860109595L, 0.768238607022126250082483L, 0.209793185936509782784315L, 0.0319569316899913392596356L, 0.00213363160895785378615014L };
+ static const float f0 = 0.419990927F;
+ r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75);
+ b = f0;
+ }
+ else if(z < 2.25)
+ {
+ // Worst case absolute error found: 2.866005373e-21
+ static const T n[7] = { -0.0300838560557949717328341L, 0.0538578829844454508530552L, 0.0726211541651914182692959L, 0.0367628469888049348429018L, 0.00964629015572527529605267L, 0.00133453480075291076745275L, 0.778087599782504251917881e-4L };
+ static const T d[8] = { 1L, 1.75967098147167528287343L, 1.32883571437961120556307L, 0.552528596508757581287907L, 0.133793056941332861912279L, 0.0179509645176280768640766L, 0.00104712440019937356634038L, -0.106640381820357337177643e-7L };
+ static const float f0 = 0.4898625016F;
+ r = tools::evaluate_polynomial(n, z - 1.25) / tools::evaluate_polynomial(d, z - 1.25);
+ b = f0;
+ }
+ else if(z < 3.5)
+ {
+ // Worst case absolute error found: 1.045355789e-21
+ static const T n[7] = { -0.0117907570137227847827732L, 0.014262132090538809896674L, 0.0202234435902960820020765L, 0.00930668299990432009042239L, 0.00213357802422065994322516L, 0.00025022987386460102395382L, 0.120534912219588189822126e-4L };
+ static const T d[7] = { 1L, 1.50376225203620482047419L, 0.965397786204462896346934L, 0.339265230476796681555511L, 0.0689740649541569716897427L, 0.00771060262491768307365526L, 0.000371421101531069302990367L };
+ static const float f0 = 0.5317370892F;
+ r = tools::evaluate_polynomial(n, z - 2.25) / tools::evaluate_polynomial(d, z - 2.25);
+ b = f0;
+ }
+ else if(z < 5.25)
+ {
+ // Worst case absolute error found: 8.300028706e-22
+ static const T n[7] = { -0.00546954795538729307482955L, 0.00404190278731707110245394L, 0.0054963369553161170521356L, 0.00212616472603945399437862L, 0.000394984014495083900689956L, 0.365565477064442377259271e-4L, 0.135485897109932323253786e-5L };
+ static const T d[8] = { 1L, 1.21019697773630784832251L, 0.620914668221143886601045L, 0.173038430661142762569515L, 0.0276550813773432047594539L, 0.00240625974424309709745382L, 0.891811817251336577241006e-4L, -0.465528836283382684461025e-11L };
+ static const float f0 = 0.5489973426F;
+ r = tools::evaluate_polynomial(n, z - 3.5) / tools::evaluate_polynomial(d, z - 3.5);
+ b = f0;
+ }
+ else if(z < 8)
+ {
+ // Worst case absolute error found: 1.700157534e-21
+ static const T n[6] = { -0.00270722535905778347999196L, 0.0013187563425029400461378L, 0.00119925933261002333923989L, 0.00027849619811344664248235L, 0.267822988218331849989363e-4L, 0.923043672315028197865066e-6L };
+ static const T d[7] = { 1L, 0.814632808543141591118279L, 0.268901665856299542168425L, 0.0449877216103041118694989L, 0.00381759663320248459168994L, 0.000131571897888596914350697L, 0.404815359675764138445257e-11L };
+ static const float f0 = 0.5571740866F;
+ r = tools::evaluate_polynomial(n, z - 5.25) / tools::evaluate_polynomial(d, z - 5.25);
+ b = f0;
+ }
+ else if(z < 11.5)
+ {
+ //Worst case absolute error found: 3.002278011e-22
+ static const T n[6] = { -0.00109946720691742196814323L, 0.000406425442750422675169153L, 0.000274499489416900707787024L, 0.465293770646659383436343e-4L, 0.320955425395767463401993e-5L, 0.778286018145020892261936e-7L };
+ static const T d[6] = { 1L, 0.588173710611846046373373L, 0.139363331289409746077541L, 0.0166329340417083678763028L, 0.00100023921310234908642639L, 0.24254837521587225125068e-4L };
+ static const float f0 = 0.5609807968F;
+ r = tools::evaluate_polynomial(n, z - 8) / tools::evaluate_polynomial(d, z - 8);
+ b = f0;
+ }
+ else if(z < 17)
+ {
+ //Worst case absolute error found: 6.741114695e-21
+ static const T n[5] = { -0.00056907993601094962855594L, 0.000169498540373762264416984L, 0.518472354581100890120501e-4L, 0.382819312231928859704678e-5L, 0.824989931281894431781794e-7L };
+ static const T d[6] = { 1L, 0.339637250051139347430323L, 0.043472647870310663055044L, 0.00248549335224637114641629L, 0.535633305337152900549536e-4L, -0.117490944405459578783846e-12L };
+ static const float f0 = 0.5626493692F;
+ r = tools::evaluate_polynomial(n, z - 11.5) / tools::evaluate_polynomial(d, z - 11.5);
+ b = f0;
+ }
+ else if(z < 24)
+ {
+ // Worst case absolute error found: 7.802346984e-22
+ static const T n[5] = { -0.000241313599483991337479091L, 0.574224975202501512365975e-4L, 0.115998962927383778460557e-4L, 0.581762134402593739370875e-6L, 0.853971555085673614607418e-8L };
+ static const T d[5] = { 1L, 0.233044138299687841018015L, 0.0204186940546440312625597L, 0.000797185647564398289151125L, 0.117019281670172327758019e-4L };
+ static const float f0 = 0.5634598136F;
+ r = tools::evaluate_polynomial(n, z - 17) / tools::evaluate_polynomial(d, z - 17);
+ b = f0;
+ }
+ else if(z < 38)
+ {
+ // Worst case absolute error found: 2.414228989e-22
+ static const T n[5] = { -0.000146674699277760365803642L, 0.162666552112280519955647e-4L, 0.269116248509165239294897e-5L, 0.979584479468091935086972e-7L, 0.101994647625723465722285e-8L };
+ static const T d[5] = { 1L, 0.165907812944847226546036L, 0.0103361716191505884359634L, 0.000286593026373868366935721L, 0.298401570840900340874568e-5L };
+ static const float f0 = 0.5638477802F;
+ r = tools::evaluate_polynomial(n, z - 24) / tools::evaluate_polynomial(d, z - 24);
+ b = f0;
+ }
+ else if(z < 60)
+ {
+ // Worst case absolute error found: 5.896543869e-24
+ static const T n[5] = { -0.583905797629771786720406e-4L, 0.412510325105496173512992e-5L, 0.431790922420250949096906e-6L, 0.993365155590013193345569e-8L, 0.653480510020104699270084e-10L };
+ static const T d[5] = { 1L, 0.105077086072039915406159L, 0.00414278428675475620830226L, 0.726338754644523769144108e-4L, 0.477818471047398785369849e-6L };
+ static const float f0 = 0.5640528202F;
+ r = tools::evaluate_polynomial(n, z - 38) / tools::evaluate_polynomial(d, z - 38);
+ b = f0;
+ }
+ else if(z < 85)
+ {
+ // Worst case absolute error found: 3.080612264e-21
+ static const T n[4] = { -0.196457797609229579459841e-4L, 0.157243887666800692441195e-5L, 0.543902511192700878690335e-7L, 0.317472492369117710852685e-9L };
+ static const T d[5] = { 1L, 0.052803989240957632204885L, 0.000926876069151753290378112L, 0.541011723226630257077328e-5L, 0.535093845803642394908747e-15L };
+ static const float f0 = 0.5641309023F;
+ r = tools::evaluate_polynomial(n, z - 60) / tools::evaluate_polynomial(d, z - 60);
+ b = f0;
+ }
+ else
+ {
+ // Worst case absolute error found: 8.094633491e-22
+ static const T n[4] = { -0.789224703978722689089794e-5L, 0.622088451660986955124162e-6L, 0.145728445676882396797184e-7L, 0.603715505542715364529243e-10L };
+ static const T d[4] = { 1L, 0.0375328846356293715248719L, 0.000467919535974625308126054L, 0.193847039275845656900547e-5L };
+ static const float f0 = 0.5641584396F;
+ r = tools::evaluate_polynomial(n, z - 85) / tools::evaluate_polynomial(d, z - 85);
+ b = f0;
+ }
+ T g = exp(-z * z) / z;
+ result = g * b + g * r;
+ BOOST_MATH_INSTRUMENT_CODE("r = " << r);
+ BOOST_MATH_INSTRUMENT_CODE("b = " << b);
+ BOOST_MATH_INSTRUMENT_CODE("g = " << g);
+ }
+ 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 L>T erf_imp(T z, bool invert, const L& 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(-z, invert, pol, t);
+ else if(z < -0.5)
+ return 2 - erf_imp(-z, invert, pol, t);
+ else
+ return 1 + erf_imp(-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)
+ {
+ result = z * 1.125 + z * 0.003379167095512573896158903121545171688L;
+ }
+ else
+ {
+ // Worst case absolute error found: 1.928180863e-35
+ static const T n[13] = { 0.0033791670955125738961589031215451706772L, -0.000356604747854533671135323429762519216044L, -0.374476838669183581687167228866769133591L, 0.0395338132469809122364498388174446488042L, -0.070405473508786506375820161461872523315L, 0.00575264725772369303419496752516485264994L, -0.0122324470706306942925087773122510971344L, 0.000982833333252586078523570049842642796291L, -0.000937806155615159592441487275938040285833L, 0.485407838108763091860415874932955355755e-4L, -0.50171236926234625577876479444632561922e-4L, 0.19406068817888598455243350289053451571e-5L, -0.119351103792049576459000102632508734863e-5L };
+ static const T d[13] = { 1L, -0.105530368216503232473476334993759958083L, 0.488152943026846232046726653294817930988L, -0.0470361716364117780901924633553851211874L, 0.107663671943702835026199580597519084906L, -0.00919493879447389180633447493128337242362L, 0.0138231121717229362691899919242806829805L, -0.000994048559663865788847688218108232247441L, 0.00109769834527023265969224251892094019735L, -0.600458401801636062015615549258555311545e-4L, 0.51530723974502946291624848874654212384e-4L, -0.164121264470361558910636548509486296153e-5L, 0.112643498977070218963888579607359294396e-5L };
+
+ result = z * 1.125 + z * tools::evaluate_rational(n, d, z);
+ }
+ }
+ else if((z < 9) || ((z < 110) && invert)) // TODO FIXME!!
+ {
+ //
+ // We'll be calculating erfc:
+ //
+ invert = !invert;
+ T r, b;
+ if(z < 0.75)
+ {
+ // Worst case absolute error found: 9.46579566e-36
+ static const T n[10] = { -0.0361790390718262471349157886581290316118L, 0.268773785250238404882137450640472787307L, 0.46350995084084251624649426251701042395L, 0.368375435727102373204587584306335625665L, 0.177618123820303858190236222513516291818L, 0.0566304173556669007529719743050764079095L, 0.0121631149481817424284077180037019529004L, 0.00171397353209314111395429418066990259845L, 0.000144662387395699594624184141956722488753L, 0.559870522050008635715382724858714587198e-5L };
+ static const T d[10] = { 1L, 2.50344259590701770420935329380375393716L, 2.84905597172139276093882199286535521011L, 1.93691730181297099541395314232750876411L, 0.868059574796050528229446630538462280596L, 0.266360035323208212078527036132085926692L, 0.0560555526482963925944703505114360693216L, 0.0078174400311465420803366235814673576269L, 0.000657067309046405057499687417839930873806L, 0.254293850077789079098316521097979388983e-4L };
+ static const float f0 = 0.3440242112F;
+ r = tools::evaluate_rational(n, d, z - 0.5);
+ b = f0;
+ }
+ else if(z < 1.25)
+ {
+ // Worst case absolute error found: 1.222145602e-35
+ static const T n[10] = { -0.03978768926111368569548863384587917014L, 0.136218360681765349252731304877153919181L, 0.252782160406474440925641829129129001834L, 0.198264231106182362320012632943145619752L, 0.0923045825293507328801206570363391760624L, 0.0281157216148097885766639832985410722743L, 0.00573041663561645197870019701493117161792L, 0.000762341440133027349203518836487137709687L, 0.60471020134417423449877859375492618899e-4L, 0.219005333943510376644902615714724932217e-5L };
+ static const T d[11] = { 1L, 2.38113277319993574121349184069891082204L, 2.57380422881476860215664207822277590181L, 1.65937045609044738941173490190122101824L, 0.704055811320312044285417250966993014161L, 0.20414913933328592198279939394283925451L, 0.0405162285360227740710964820549709038107L, 0.00531638867177288975915820230980317499728L, 0.000419364368135139398723983192742319455284L, 0.151874665979234971229096136924566078234e-4L, 0.807869459506748684117962248796937508011e-11L };
+ static const float f0 = 0.419990927F;
+ r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75);
+ b = f0;
+ }
+ else if(z < 2)
+ {
+ // Worst case absolute error found: 5.893842955e-36
+ static const T n[11] = { -0.0255063683486569102096736247449691465143L, 0.045782379672906795594927072060091308408L, 0.113248439610400562258072020811195716817L, 0.0996016254422112410086711272219455446695L, 0.0508749250027894453228337309651895478017L, 0.0171081937013828309576540212196644542209L, 0.00395354196550210630440706013523069756354L, 0.000629022203390154585475081628606234279007L, 0.664903286194855400689101617763591823345e-4L, 0.423935693893425355108071655059640137208e-5L, 0.124304036910852727351487636048151737214e-6L };
+ static const T d[11] = { 1L, 2.39207679390801118396945702674440915308L, 2.62237869972649377524874287442154430843L, 1.73645189911172997548091140085423843725L, 0.769812706091926741262865732006953282036L, 0.238986814887891859065369830215615790694L, 0.0526759147274379214313767032352419949829L, 0.00814993801398361741777997755108018659382L, 0.00084829993036396244429607826663252633817L, 0.537276435448416921594616417908288527881e-4L, 0.157537193656690184073389824392669625417e-5L };
+ static const float f0 = 0.4852850139F;
+ r = tools::evaluate_rational(n, d, z - 1.25);
+ b = f0;
+ }
+ else if(z < 2.75)
+ {
+ // Worst case absolute error found: 4.024770853e-36
+ static const T n[10] = { -0.0108897177067473013323228381829144739013L, 0.0202210475357865979950082670101965963435L, 0.0403242149078991892599316678797913295452L, 0.0288492313188655084113941326565482276741L, 0.0116982647742533555237861890442866083526L, 0.00301908913020213436098518520436147263177L, 0.000511140165864993121203730804407968689429L, 0.555507897975436549741754647662158917103e-4L, 0.354571088276496768574495922471690102061e-5L, 0.101789333060641482357520298518780163915e-6L };
+ static const T d[11] = { 1L, 1.98184247277299581801610266575921553552L, 1.77518826058984218945272444617044495028L, 0.943934346956188464279312722940302202684L, 0.328630002685235061519039528479761588138L, 0.0777535542351039388345270792222146705189L, 0.0125143974181120800829065248546370953609L, 0.00132270605931460450441108147393979771563L, 0.834118048375722123506409257130329786209e-4L, 0.239456257167492104073765911366304033453e-5L, 0.197067742893785800814802969598122120027e-13L };
+ static const float f0 = 0.5216810703F;
+ r = tools::evaluate_polynomial(n, z - 2) / tools::evaluate_polynomial(d, z - 2);
+ b = f0;
+ }
+ else if(z < 3.75)
+ {
+ // Worst case absolute error found: 2.119317982e-36
+ static const T n[10] = { -0.00669534469911386821762042893742722704704L, 0.00779239067529714323524154862288379264056L, 0.0167670669587476509267036865033136655094L, 0.0113887916348251443051357686146040093464L, 0.00426976750247047946700539147728477144579L, 0.00100469100574064832665606356894416652764L, 0.000153533145320881108157829902752192859922L, 0.149337551064665413462766906201269176262e-4L, 0.846377837919513024118176704010972579138e-6L, 0.214045773545256889299689737489755489478e-7L };
+ static const T d[11] = { 1L, 1.78724215851193637544287795626580411105L, 1.44052576962222794702178612920219772782L, 0.687639905608366315245841860669607532265L, 0.214374367225822611754443822822738563207L, 0.0452948320968245754796139856381504201504L, 0.00649108394178118005887118777181540680812L, 0.000608904720665003139414993591868256489088L, 0.33959064390570911588709483563995284603e-4L, 0.858811916085393051026834431509997486704e-6L, 0.618878592093890510233502654703683447468e-15L };
+ static const float f0 = 0.5392661095F;
+ r = tools::evaluate_polynomial(n, z - 2.75) / tools::evaluate_polynomial(d, z - 2.75);
+ b = f0;
+ }
+ else if(z < 5)
+ {
+ // Worst case absolute error found: 3.131502824e-36
+ static const T n[10] = { -0.00378088626017041998499190989910098718437L, 0.0029008905292996011997575492874095588328L, 0.00662431938391549599757244232386689480515L, 0.00417809740399798845564363621020984935218L, 0.00142019749135652688012034919213168974543L, 0.000299107980170253223293530710056814995102L, 0.405161538841561396150507786831930770839e-4L, 0.346344371670880861875666253626975779945e-5L, 0.171091054330494778613793054233437928605e-6L, 0.373924433717749484258186454458704819755e-8L };
+ static const T d[10] = { 1L, 1.5810750672399887547849540367499389454L, 1.12479852885403050655678225945856872694L, 0.47277272679268851560291322980574597267L, 0.129444913616967588584693095240544707208L, 0.0239544490709674941887988416318107990646L, 0.00299775294496053944060700963645084591246L, 0.00024478412843088575835960648397300177201L, 0.118424712755145205302405346348931402917e-4L, 0.2588206250858483868392167535345681119e-6L };
+ static const float f0 = 0.549742341F;
+ r = tools::evaluate_rational(n, d, z - 3.75);
+ b = f0;
+ }
+ else if(z < 6.5)
+ {
+ // Worst case absolute error found: 3.352877573e-35
+ static const T n[9] = { -0.00210683958249012010206456754123471415706L, 0.00146329021314062287670019911742786780092L, 0.00242029064025351202243048169807220157512L, 0.0011321990764681390160708960047630195582L, 0.000277123780759366982673218537550876769487L, 0.401236501288775561636453586216146028714e-4L, 0.347799938323835778216424009916867086167e-5L, 0.167678812729975154456097184107934455429e-6L, 0.346722083660429051057284107535869165775e-8L };
+ static const T d[10] = { 1L, 1.22334833521124956366395053444841951468L, 0.661433457507589455018784737495591428263L, 0.206503622658778732280997770028712044451L, 0.0407323027711252752353388616742333806362L, 0.00519969889874877079704615143005539754407L, 0.000419679230772141031030427156828631265963L, 0.195896640254171597965013007459411704085e-4L, 0.405070207572551760879797790899826058473e-6L, -0.949400883467250846930389103621356900319e-17L };
+ static const float f0 = 0.5556300282F;
+ r = tools::evaluate_polynomial(n, z - 5) / tools::evaluate_polynomial(d, z - 5);
+ b = f0;
+ }
+ else if(z < 8)
+ {
+ // Worst case absolute error found: 2.10254551e-36
+ static const T n[9] = { -0.00107224589975857477185569028693588970638L, 0.00081159959093417892787006088639848404179L, 0.00105587689576932891666032146026668833287L, 0.000416243954540394829165805666548948771809L, 0.861189599093384016322579078144012057531e-4L, 0.105064862265647286966467927732505059558e-4L, 0.763674245263385902692134637353517251296e-6L, 0.306964079269190247526141442183490066292e-7L, 0.525762928524110511201313708396204710874e-9L };
+ static const T d[9] = { 1L, 1.03391233015873996503551085347368889767L, 0.471295765635712684194436077437130977978L, 0.123736066749315618886080242926593910851L, 0.0204690897886919138685460664198600282119L, 0.00218521816743913946855947853274936296576L, 0.000147057386621380823003258590658747813774L, 0.570514093706434168568509838021466564264e-5L, 0.977166974697066620826028345712327325748e-7L };
+ static const float f0 = 0.5588091016F;
+ r = tools::evaluate_rational(n, d, z - 6.5);
+ b = f0;
+ }
+ else if(z < 10)
+ {
+ // Worst case absolute error found: 8.006848023e-37
+ static const T n[9] = { -0.000764310289345400483607004463638641680792L, 0.000375959928342415987920641866513058424701L, 0.000477297615927227258961911005347799033473L, 0.000165573027183931250708334564452626717999L, 0.296617493157889183515359094859055088531e-4L, 0.310848843632513098624143817615592253324e-5L, 0.192932185180269434271810693046412848027e-6L, 0.658630702075882625552897504189436319318e-8L, 0.952880249971934343233104137698620618851e-10L };
+ static const T d[9] = { 1L, 0.885953297549629585611202995885653291163L, 0.345435500008639080844920938390800739845L, 0.0774289910213823638414558561872084410517L, 0.0109142290775434200609901181618181718948L, 0.000990815749814504617347317658063197107511L, 0.565801964505889288566864514277149126893e-4L, 0.185846832474795168475989869562411740416e-5L, 0.268875677412705938842038805073576012915e-7L };
+ static const float f0 = 0.5606456399F;
+ r = tools::evaluate_rational(n, d, z - 8);
+ b = f0;
+ }
+ else if(z < 12.5)
+ {
+ // Worst case absolute error found: 1.920487881e-37
+ static const T n[9] = { -0.00049563543942917072170112779531688430711L, 0.000181627479476470045833245371263435213396L, 0.000205326116055098869964168775605689851547L, 0.602131211119027087508128340443602490578e-4L, 0.904046610725767796892834734953040318357e-5L, 0.790026495730279360618915285828083295597e-6L, 0.407154634490633661408148126521656550974e-7L, 0.114947371191075676274146563385045083492e-8L, 0.136959786076422777905476122283384578138e-10L };
+ static const T d[9] = { 1L, 0.738936412939629363226408445024616124644L, 0.239911614287295587917806937612822134282L, 0.0447038494121568822243673246874110377585L, 0.00522920850086320874490830611785659031521L, 0.000393238307986133717620560371515858231357L, 0.18566831172454022627187937328433090172e-4L, 0.503267648562793696253090536560738864711e-6L, 0.599643373938283798258195761814169705225e-8L };
+ static const float f0 = 0.5619055629F;
+ r = tools::evaluate_rational(n, d, z - 10);
+ b = f0;
+ }
+ else if(z < 15.5)
+ {
+ // Worst case absolute error found: 1.257535398e-36
+ static const T n[8] = { -0.000310716603972278501158850534578560332617L, 0.00011678083970731888844953949114132723885L, 0.800190190430061077253903477346761222901e-4L, 0.156297703728913451581100601056534652076e-4L, 0.151432948873760306237990776980248434808e-5L, 0.798843820137664551611401320879346402013e-7L, 0.219398460602279142004550137383605410162e-8L, 0.244774638611231694720102050826438123042e-10L };
+ static const T d[9] = { 1L, 0.536396467095662522242258924420035847546L, 0.12368534422025248132153213926057643819L, 0.0158935327926481775020421628983323726346L, 0.00122923842249710594941031294559763761829L, 0.572250268558063378795115723535491980973e-4L, 0.148480028895780193980507551658637328542e-5L, 0.165653602646537759781637790321962585489e-7L, 0.159564067829807076335030582566349996674e-21L };
+ static const float f0 = 0.5627119541F;
+ r = tools::evaluate_polynomial(n, z - 12.5) / tools::evaluate_polynomial(d, z - 12.5);
+ b = f0;
+ }
+ else if(z < 20)
+ {
+ // Worst case absolute error found: 8.757869781e-37
+ static const T n[8] = { -0.000232165799411403604511899928682939571679L, 0.473280617901953093430938763139716601257e-4L, 0.322197983787538821545512424866901113822e-4L, 0.53341606003892328294004958671866936958e-5L, 0.429392533762301420884052643595872389588e-6L, 0.186707830002841677949013638707964861935e-7L, 0.420531779988891521855765212230340499168e-9L, 0.38311153882270641561622347190918577449e-11L };
+ static const T d[9] = { 1L, 0.440698415779467873589164469370853517393L, 0.0834079018864546179293964148377602724235L, 0.00878845776227345123101968908701592510214L, 0.000556792236817609981676018545344816931862L, 0.212109697877283363015270621439889468055e-4L, 0.449886743173619367191275104721917344569e-6L, 0.409854405005280582884236774230760402868e-8L, 0.185071069100878210011727114952196630136e-23L };
+ static const float f0 = 0.5632548332F;
+ r = tools::evaluate_polynomial(n, z - 15.5) / tools::evaluate_polynomial(d, z - 15.5);
+ b = f0;
+ }
+ else if(z < 26)
+ {
+ // Worst case absolute error found: 6.571456853e-37
+ static const T n[8] = { -0.000143129243915019877016909310584833592972L, 0.203555078616578752774553439209122798188e-4L, 0.116664173863253360297276766667046754002e-4L, 0.153607643549360281089355497044679566329e-5L, 0.976486412462035616905934994399021437658e-7L, 0.33416295362298759817564985788402188186e-8L, 0.590812660432887787644458409396105030781e-10L, 0.421471133628743008309458424282421874073e-12L };
+ static const T d[8] = { 1L, 0.346848503043261151874606241871432055165L, 0.0516236057301875770334953837585483539519L, 0.0042740199483843978391191804633398315544L, 0.000212586135154357046245694533825075007902L, 0.635258188334431428038271842518161892901e-5L, 0.105600415847309067601860633252823051505e-6L, 0.753327238218310630683194279382721367469e-9L };
+ static const float f0 = 0.5636301041F;
+ r = tools::evaluate_polynomial(n, z - 20) / tools::evaluate_polynomial(d, z - 20);
+ b = f0;
+ }
+ else if(z < 34)
+ {
+ // Worst case absolute error found: 2.529847851e-38
+ static const T n[8] = { -0.863162280463127451272161303767299107489e-4L, 0.876391266908317792353253474461536821127e-5L, 0.407624004719762912183133597708988715137e-5L, 0.418371930808379615690956857824418800194e-6L, 0.206376792034344913360458422974245946873e-7L, 0.546878311460852031076829190722479684e-9L, 0.74760305098509923829341087347518769626e-11L, 0.411832046806658129073165530819472782663e-13L };
+ static const T d[9] = { 1L, 0.268714425336129161136892060316889824437L, 0.0309686025544536788982104017649851516554L, 0.00198426609900573235086828549632290797514L, 0.763402107420631006526499294753645914808e-4L, 0.176354119917411263184292422389304506735e-5L, 0.226504369338582253171306523992412653547e-7L, 0.124774448034213281307712525982862926228e-9L, 0.541581693417048102342931921476367282462e-28L };
+ static const float f0 = 0.5638595223F;
+ r = tools::evaluate_polynomial(n, z - 26) / tools::evaluate_polynomial(d, z - 26);
+ b = f0;
+ }
+ else if(z < 46)
+ {
+ // Worst case absolute error found: 4.880939969e-36
+ static const T n[7] = { -0.552701065525823960321509114250962372959e-4L, 0.459798238451342341380837226471283129117e-5L, 0.117462487430397988459985818542278619172e-5L, 0.704965053290383355071079647747711714696e-7L, 0.191250482739845326510859812663255140286e-8L, 0.245913419605775857221974833985059356312e-10L, 0.120466123381598216554945834019040289508e-12L };
+ static const T d[8] = { 1L, 0.175852634004021068883919193145643406305L, 0.0128923775281953424344037205817061020944L, 0.000504385604406829419856756492198778141939L, 0.111061123996047697713589874603922096536e-4L, 0.130499191758882778721577274330215931713e-6L, 0.639279131688964342759306361922751772829e-9L, -0.10503012469906917938721140272475203112e-26L };
+ static const float f0 = 0.564001143F;
+ r = tools::evaluate_polynomial(n, z - 34) / tools::evaluate_polynomial(d, z - 34);
+ b = f0;
+ }
+ else if(z < 62)
+ {
+ // Worst case absolute error found: 8.634961697e-37
+ static const T n[7] = { -0.299551937061912926289705712581858190494e-4L, 0.188783643501597286680709990049243153264e-5L, 0.353403900815908094401075506391935032602e-6L, 0.156779149815977342177830075875441013335e-7L, 0.31456307256618424444443489905810774564e-9L, 0.29912544832845265905351204765862702307e-11L, 0.108360038290329929702659864116372774364e-13L };
+ static const T d[7] = { 1L, 0.13020345740128026085404079010013007005L, 0.00706598549835633149505923515407700416484L, 0.000204578844720147762058725212299415091588L, 0.333280847765611305843836201217690887394e-5L, 0.289666303356425428524772241712503072453e-7L, 0.104933404691983708511908027657434756019e-9L };
+ static const float f0 = 0.564086318F;
+ r = tools::evaluate_polynomial(n, z - 46) / tools::evaluate_polynomial(d, z - 46);
+ b = f0;
+ }
+ else if(z < 80)
+ {
+ // Worst case absolute error found: 6.10700166e-39
+ static const T n[7] = { -0.146162619512779884168960178459825270831e-4L, 0.952303834226435420147786300516273108344e-6L, 0.114559890033396819882468040960469980168e-6L, 0.368994353517438072494331750992706039868e-8L, 0.545158660461829568567388818070830588533e-10L, 0.383569328729331398089160922704933035281e-12L, 0.103104113324271568678309317039606225294e-14L };
+ static const T d[7] = { 1L, 0.0966822058944670599111360985490948186413L, 0.00389546596914826027568119425228340291579L, 0.837237328321088890541798035513749762375e-4L, 0.101236677684940943809478588316884539423e-5L, 0.652985528810044575089151077574382356898e-8L, 0.175523663960756825512727785416137345625e-10L };
+ static const float f0 = 0.5641308427F;
+ r = tools::evaluate_polynomial(n, z - 62) / tools::evaluate_polynomial(d, z - 62);
+ b = f0;
+ }
+ else
+ {
+ // Worst case absolute error found: 3.409761622e-39
+ static const T n[7] = { -0.103600733768855845278685109220598569282e-4L, 0.324846376725138276091774803419773168357e-6L, 0.376580042454826796817160322889753111347e-7L, 0.971125540805193703472871419997820785081e-9L, 0.112499588573918670534994853431614458564e-10L, 0.6161310085325929027114924903443564594e-13L, 0.128358125353302055468778305481781957985e-15L };
+ static const T d[7] = { 1L, 0.0749579802028981336679035635535776767532L, 0.00234137768051079846068630120744888560113L, 0.390095348825177571970348898222511084593e-4L, 0.365628111271063883320224395719085602867e-6L, 0.182790705425846241876560215158605843026e-8L, 0.380806548535012144489621218246876843627e-11L };
+ static const float f0 = 0.5641558766F;
+ r = tools::evaluate_polynomial(n, z - 80) / tools::evaluate_polynomial(d, z - 80);
+ b = f0;
+ }
+ T g = exp(-z * z) / z;
+ result = g * b + g * r;
+ }
+ 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 L>T erf_imp(T z, bool invert, const L& 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
+
+
+
Modified: branches/bcbboost/boost/math/special_functions/expm1.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/expm1.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/expm1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -1,4 +1,4 @@
-// (C) Copyright John Maddock 2005.
+// (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)
@@ -9,7 +9,13 @@
#include <cmath>
#include <math.h> // platform's ::expm1
#include <boost/limits.hpp>
-#include <boost/math/special_functions/detail/series.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/series.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/policies/error_handling.hpp>
+#include <boost/math/tools/rational.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
+#include <boost/mpl/less_equal.hpp>
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
# include <boost/static_assert.hpp>
@@ -17,87 +23,203 @@
# include <boost/assert.hpp>
#endif
-#ifdef BOOST_NO_STDC_NAMESPACE
-namespace std{ using ::exp; using ::fabs; }
-#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
+namespace detail
{
- 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&);
-};
-
-} // namespace
+ // Functor expm1_series returns the next term in the Taylor series
+ // x^k / k!
+ // each time that operator() is invoked.
+ //
+ template <class T>
+ struct expm1_series
+ {
+ typedef T result_type;
+
+ expm1_series(T x)
+ : k(0), m_x(x), m_term(1) {}
+
+ T operator()()
+ {
+ ++k;
+ m_term *= m_x;
+ m_term /= k;
+ return m_term;
+ }
+
+ int count()const
+ {
+ return k;
+ }
+
+ private:
+ int k;
+ const T m_x;
+ T m_term;
+ expm1_series(const expm1_series&);
+ expm1_series& operator=(const expm1_series&);
+ };
//
// Algorithm expm1 is part of C99, but is not yet provided by many compilers.
//
// This version uses a Taylor series expansion for 0.5 > |x| > epsilon.
//
-template <class T>
-T expm1(T x)
+template <class T, class Policy>
+T expm1_imp(T x, const mpl::int_<0>&, const Policy& pol)
{
-#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
- BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized);
+ BOOST_MATH_STD_USING
+
+ T a = fabs(x);
+ if(a > T(0.5L))
+ 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))
+ T result = tools::sum_series(s, policies::digits<T, Policy>(), max_iter);
#else
- BOOST_ASSERT(std::numeric_limits<T>::is_specialized);
+ T zero = 0;
+ T result = tools::sum_series(s, policies::digits<T, Policy>(), max_iter, zero);
#endif
+ policies::check_series_iterations("boost::math::expm1<%1%>(%1%)", max_iter, pol);
+ return result;
+}
- T a = std::fabs(x);
+template <class T, class P>
+T expm1_imp(T x, const mpl::int_<53>&, const P&)
+{
+ BOOST_MATH_STD_USING
+
+ T a = fabs(x);
if(a > T(0.5L))
- return std::exp(x) - T(1);
- if(a < std::numeric_limits<T>::epsilon())
+ return exp(x) - T(1);
+ if(a < tools::epsilon<T>())
return x;
- detail::expm1_series<T> s(x);
- T result = detail::kahan_sum_series(s, std::numeric_limits<T>::digits + 2);
+
+ 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;
}
-#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-inline float expm1(float z)
+
+template <class T, class P>
+T expm1_imp(T x, const mpl::int_<64>&, const P&)
{
- return expm1<float>(z);
+ BOOST_MATH_STD_USING
+
+ T a = fabs(x);
+ if(a > T(0.5L))
+ return exp(x) - T(1);
+ if(a < tools::epsilon<T>())
+ return x;
+
+ static const float Y = 0.10281276702880859375e1f;
+ static const T n[] = {
+ -0.281276702880859375e-1L,
+ 0.512980290285154286358e0L,
+ -0.667758794592881019644e-1L,
+ 0.131432469658444745835e-1L,
+ -0.72303795326880286965e-3L,
+ 0.447441185192951335042e-4L,
+ -0.714539134024984593011e-6L
+ };
+ static const T d[] = {
+ 1,
+ -0.461477618025562520389e0L,
+ 0.961237488025708540713e-1L,
+ -0.116483957658204450739e-1L,
+ 0.873308008461557544458e-3L,
+ -0.387922804997682392562e-4L,
+ 0.807473180049193557294e-6L
+ };
+
+ T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
+ return result;
}
-inline double expm1(double z)
+
+template <class T, class P>
+T expm1_imp(T x, const mpl::int_<113>&, const P&)
{
- return expm1<double>(z);
+ BOOST_MATH_STD_USING
+
+ T a = fabs(x);
+ if(a > T(0.5L))
+ return exp(x) - T(1);
+ if(a < tools::epsilon<T>())
+ return x;
+
+ static const float Y = 0.10281276702880859375e1f;
+ static const T n[] = {
+ -0.28127670288085937499999999999999999854e-1L,
+ 0.51278156911210477556524452177540792214e0L,
+ -0.63263178520747096729500254678819588223e-1L,
+ 0.14703285606874250425508446801230572252e-1L,
+ -0.8675686051689527802425310407898459386e-3L,
+ 0.88126359618291165384647080266133492399e-4L,
+ -0.25963087867706310844432390015463138953e-5L,
+ 0.14226691087800461778631773363204081194e-6L,
+ -0.15995603306536496772374181066765665596e-8L,
+ 0.45261820069007790520447958280473183582e-10L
+ };
+ static const T d[] = {
+ 1,
+ -0.45441264709074310514348137469214538853e0L,
+ 0.96827131936192217313133611655555298106e-1L,
+ -0.12745248725908178612540554584374876219e-1L,
+ 0.11473613871583259821612766907781095472e-2L,
+ -0.73704168477258911962046591907690764416e-4L,
+ 0.34087499397791555759285503797256103259e-5L,
+ -0.11114024704296196166272091230695179724e-6L,
+ 0.23987051614110848595909588343223896577e-8L,
+ -0.29477341859111589208776402638429026517e-10L,
+ 0.13222065991022301420255904060628100924e-12L
+ };
+
+ T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
+ return result;
}
-inline long double expm1(long double z)
+
+} // namespace detail
+
+template <class T, class Policy>
+inline typename tools::promote_args<T>::type expm1(T x, const Policy& /* pol */)
{
- return expm1<long double>(z);
+ 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%)");
}
-#endif
#ifdef expm1
# ifndef BOOST_HAS_expm1
@@ -108,14 +230,38 @@
#ifdef BOOST_HAS_EXPM1
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
-inline float expm1(float x){ return ::expm1f(x); }
-inline long double expm1(long double x){ return ::expm1l(x); }
+inline float expm1(float x, const policies::policy<>&){ return ::expm1f(x); }
+inline long double expm1(long double x, const policies::policy<>&){ return ::expm1l(x); }
#else
-inline float expm1(float x){ return ::expm1(x); }
+inline float expm1(float x, const policies::policy<>&){ return ::expm1(x); }
#endif
-inline double expm1(double x){ return ::expm1(x); }
+inline double expm1(double x, const policies::policy<>&){ return ::expm1(x); }
#endif
-} } // namespaces
+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);
+}
+inline long double expm1(long double z)
+{
+ return expm1<long double>(z);
+}
+#endif
+
+} // namespace math
+} // namespace boost
#endif // BOOST_MATH_HYPOT_INCLUDED
+
+
Added: branches/bcbboost/boost/math/special_functions/factorials.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/factorials.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,224 @@
+// 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_FACTORIALS_HPP
+#define BOOST_MATH_SP_FACTORIALS_HPP
+
+#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 <cmath>
+
+namespace boost { namespace math
+{
+
+template <class T, class Policy>
+inline T factorial(unsigned i, const Policy& pol)
+{
+ 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_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), (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)
+{
+ 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 / 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_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 = tools::real_cast<unsigned>(floor(xp1));
+ if(n2 == xp1)
+ return 0;
+ T result = 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 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
Added: branches/bcbboost/boost/math/special_functions/fpclassify.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/fpclassify.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,240 @@
+// 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_FPCLASSIFY_HPP
+#define BOOST_MATH_FPCLASSIFY_HPP
+
+#include <math.h>
+#include <cmath>
+#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>
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#include <float.h>
+#endif
+
+#ifdef BOOST_NO_STDC_NAMESPACE
+ namespace std{ using ::abs; using ::fabs; }
+#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) && (!_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC)
+# define BOOST_FPCLASSIFY_PREFIX ::std::
+# else
+# undef BOOST_HAS_FPCLASSIFY
+# define BOOST_FPCLASSIFY_PREFIX
+# endif
+#elif defined(__HP_aCC)
+// aCC 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{
+
+#if defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
+//
+// 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);
+#else // BOOST_HAS_FPCLASSIFY
+ return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == FP_NAN);
+#endif
+}
+
+template <class T>
+inline bool is_nan_helper(T t, const boost::false_type&)
+{
+ return false;
+}
+
+}
+
+#endif // defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
+
+namespace math{
+
+namespace detail{
+
+template <class T>
+inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const mpl::true_&)
+{
+ // whenever possible check for Nan's first:
+#ifdef BOOST_HAS_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 mpl::false_&)
+{
+ //
+ // An unknown type with no numeric_limits support,
+ // so what are we supposed to do we do here?
+ //
+ return t == 0 ? FP_ZERO : FP_NORMAL;
+}
+
+} // namespace detail
+
+template <class T>
+inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
+{
+#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
+ if(std::numeric_limits<T>::is_specialized)
+ return detail::fpclassify_imp(t, mpl::true_());
+ return detail::fpclassify_imp(t, mpl::false_());
+#else
+ return detail::fpclassify_imp(t, mpl::bool_< ::std::numeric_limits<T>::is_specialized>());
+#endif
+}
+
+#if defined(BOOST_HAS_FPCLASSIFY)
+inline int fpclassify BOOST_NO_MACRO_EXPAND(float t)
+{
+ return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
+}
+inline int fpclassify BOOST_NO_MACRO_EXPAND(double t)
+{
+ return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
+}
+#if !defined(__CYGWIN__) && !defined(__HP_aCC) && !defined(BOOST_INTEL) && !defined(BOOST_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
+// The native fpclassify broken for long doubles with aCC
+// use portable one instead....
+inline int fpclassify BOOST_NO_MACRO_EXPAND(long double t)
+{
+ return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
+}
+#endif
+
+#elif defined(_MSC_VER)
+// This only works for type double, for both float
+// and long double it gives misleading answers.
+inline int fpclassify BOOST_NO_MACRO_EXPAND(double t)
+{
+ switch(::_fpclass(t))
+ {
+ case _FPCLASS_SNAN /* Signaling NaN */ :
+ case _FPCLASS_QNAN /* Quiet NaN */ :
+ return FP_NAN;
+ case _FPCLASS_NINF /*Negative infinity ( INF) */ :
+ case _FPCLASS_PINF /* Positive infinity (+INF) */ :
+ return FP_INFINITE;
+ case _FPCLASS_NN /* Negative normalized non-zero */ :
+ case _FPCLASS_PN /* Positive normalized non-zero */ :
+ return FP_NORMAL;
+ case _FPCLASS_ND /* Negative denormalized */:
+ case _FPCLASS_PD /* Positive denormalized */ :
+ return FP_SUBNORMAL;
+ case _FPCLASS_NZ /* Negative zero ( 0) */ :
+ case _FPCLASS_PZ /* Positive 0 (+0) */ :
+ return FP_ZERO;
+ default:
+ /**/ ;
+ }
+ return FP_NAN; // should never get here!!!
+}
+#endif
+
+template <class T>
+inline bool isfinite BOOST_NO_MACRO_EXPAND(T z)
+{
+ int t = (::boost::math::fpclassify)(z);
+ return (t != FP_NAN) && (t != FP_INFINITE);
+}
+
+template <class T>
+inline bool isinf BOOST_NO_MACRO_EXPAND(T t)
+{
+ return (::boost::math::fpclassify)(t) == FP_INFINITE;
+}
+
+template <class T>
+inline bool isnan BOOST_NO_MACRO_EXPAND(T t)
+{
+ return (::boost::math::fpclassify)(t) == FP_NAN;
+}
+#ifdef isnan
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
+#elif defined(BOOST_MSVC)
+# pragma warning(push)
+# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
+# pragma warning(disable: 4244) // conversion from 'long double' to 'double',
+// No possible loss of data because they are same size.
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return _isnan(t); }
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return _isnan(t); }
+template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return _isnan(t); }
+#pragma warning (pop)
+#endif
+
+template <class T>
+inline bool isnormal BOOST_NO_MACRO_EXPAND(T t)
+{
+ return (::boost::math::fpclassify)(t) == FP_NORMAL;
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_FPCLASSIFY_HPP
+
+
+
Added: branches/bcbboost/boost/math/special_functions/gamma.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/gamma.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,1470 @@
+// 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
+
+#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/real_cast.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/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 <cmath>
+#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 L>
+T gamma_imp(T z, const Policy& pol, const L& 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) && (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(-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) == FP_SUBNORMAL)
+ return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", result, pol);
+ return result;
+ }
+
+ // shift z to > 1:
+ while(z < 1)
+ {
+ result /= z;
+ z += 1;
+ }
+ if((floor(z) == z) && (z < max_factorial<T>::value))
+ {
+ result *= unchecked_factorial<T>(tools::real_cast<unsigned>(z) - 1);
+ }
+ else
+ {
+ result *= L::lanczos_sum(z);
+ 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>(L::g()) - boost::math::constants::half<T>());
+ 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));
+ result *= hp / exp(zgh);
+ 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;
+ }
+ else
+ {
+ T zgh = (z + static_cast<T>(L::g()) - boost::math::constants::half<T>());
+ result *= pow(zgh, z - boost::math::constants::half<T>()) / exp(zgh);
+ }
+ }
+ return result;
+}
+//
+// lgamma(z) with Lanczos support:
+//
+template <class T, class Policy, class L>
+T lgamma_imp(T z, const Policy& pol, const L& 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::less_equal<precision_type, mpl::int_<64> >,
+ mpl::int_<64>,
+ typename mpl::if_<
+ mpl::less_equal<precision_type, mpl::int_<113> >,
+ mpl::int_<113>, mpl::int_<0> >::type
+ >::type tag_type;
+ result = lgamma_small_imp(z, z - 1, 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 + L::g() - boost::math::constants::half<T>());
+ T l = L::lanczos_sum_expG_scaled(z);
+ result = log(zgh) - 1;
+ result *= z - 0.5f;
+ result += log(l);
+ }
+
+ 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, int bits)
+{
+ // 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, bits));
+}
+
+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)
+{
+ // 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>();
+ int bits = policies::digits<T, Policy>();
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ T zero = 0;
+ T result = boost::math::tools::sum_series(s, bits, max_iter, zero);
+#else
+ T result = boost::math::tools::sum_series(s, bits, max_iter);
+#endif
+ policies::check_series_iterations("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(-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) == 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>(tools::real_cast<unsigned>(z) - 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::digits<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)(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::digits<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 L>
+T tgammap1m1_imp(T dz, Policy const& pol, const L& 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<L, 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(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(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(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) == 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 L>
+T regularised_gamma_prefix(T a, T z, const Policy& pol, const L& l)
+{
+ BOOST_MATH_STD_USING
+ T agh = a + static_cast<T>(L::g()) - T(0.5);
+ T prefix;
+ T d = ((z - a) - static_cast<T>(L::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 * log1pmx(d, pol) + z * static_cast<T>(0.5 - L::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>()) / L::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::digits<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)
+{
+ BOOST_MATH_STD_USING // ADL of std functions.
+ //
+ // Compute the full upper fraction (Q) when a is very small:
+ //
+ T result = tgamma1pm1(a, pol) - powm1(x, a, pol);
+ result /= a;
+ detail::small_gamma2_series<T> s(a, x);
+ boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
+#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
+ T zero = 0;
+ result -= pow(x, a) * tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter, zero);
+#else
+ result -= pow(x, a) * tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter);
+#endif
+ policies::check_series_iterations("boost::math::tgamma_small_upper_part<%1%>(%1%, %1%)", max_iter, pol);
+ return result;
+}
+//
+// Upper gamma fraction for integer a:
+//
+template <class T>
+inline T finite_gamma_q(T a, T x)
+{
+ //
+ // Calculates normalised Q when a is an integer:
+ //
+ BOOST_MATH_STD_USING
+ T sum = exp(-x);
+ if(sum != 0)
+ {
+ T term = sum;
+ for(unsigned n = 1; n < a; ++n)
+ {
+ term /= n;
+ term *= x;
+ sum += term;
+ }
+ }
+ 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;
+
+ BOOST_ASSERT((p_derivative == 0) || (normalised == true));
+
+ bool is_int = floor(a) == a;
+ bool is_half_int = (floor(2 * a) == 2 * a) && !is_int;
+ bool is_small_a = (a < 30) && (a <= x + 1);
+
+ if(is_int && is_small_a && (x > 0.6))
+ {
+ // calculate Q via finite sum:
+ invert = !invert;
+ result = finite_gamma_q(a, x);
+ if(normalised == false)
+ result *= boost::math::tgamma(a, pol);
+ // TODO: calculate derivative inside sum:
+ if(p_derivative)
+ *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
+ }
+ else if(is_half_int && is_small_a && (x > 0.2))
+ {
+ // calculate Q via finite sum for half integer a:
+ invert = !invert;
+ 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());
+ }
+ else if(x < 0.5)
+ {
+ //
+ // Changeover criterion chosen to give a changeover at Q ~ 0.33
+ //
+ if(-0.4 / log(x) < a)
+ {
+ // 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)
+ result *= detail::lower_gamma_series(a, x, pol) / a;
+ }
+ else
+ {
+ // Compute Q:
+ invert = !invert;
+ result = tgamma_small_upper_part(a, x, pol);
+ if(normalised)
+ result /= boost::math::tgamma(a, pol);
+ if(p_derivative)
+ *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
+ }
+ }
+ else if(x < 1.1)
+ {
+ //
+ // Changover here occurs when P ~ 0.6 or Q ~ 0.4:
+ //
+ if(x * 1.1f < a)
+ {
+ // 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)
+ result *= detail::lower_gamma_series(a, x, pol) / a;
+ }
+ else
+ {
+ // Compute Q:
+ invert = !invert;
+ result = tgamma_small_upper_part(a, x, pol);
+ if(normalised)
+ result /= boost::math::tgamma(a, pol);
+ if(p_derivative)
+ *p_derivative = regularised_gamma_prefix(a, x, pol, lanczos_type());
+ }
+ }
+ 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)
+ {
+ //
+ // 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());
+ }
+ else
+ {
+ //
+ // Regular case where the result will not be too close to 0.5.
+ //
+ // Changeover here occurs at P ~ Q ~ 0.5
+ //
+ result = normalised ? regularised_gamma_prefix(a, x, pol, lanczos_type()) : full_igamma_prefix(a, x, pol);
+ if(p_derivative)
+ *p_derivative = result;
+ if(x < a)
+ {
+ // Compute P:
+ if(result != 0)
+ result *= detail::lower_gamma_series(a, x, pol) / a;
+ }
+ else
+ {
+ // Compute Q:
+ invert = !invert;
+ if(result != 0)
+ result *= upper_gamma_fraction(a, x, policies::digits<T, Policy>());
+ }
+ }
+ }
+
+ 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 L>
+T tgamma_delta_ratio_imp_lanczos(T z, T delta, const Policy& pol, const L&)
+{
+ BOOST_MATH_STD_USING
+ T zgh = z + L::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 *= L::lanczos_sum(z) / L::lanczos_sum(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::digits<T, Policy>());
+ T sumd = detail::lower_gamma_series(zd, zd, pol) / zd;
+ sumd += detail::upper_gamma_fraction(zd, zd, ::boost::math::policies::digits<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>(tools::real_cast<unsigned>(z) - 1) / unchecked_factorial<T>(tools::real_cast<unsigned>(z + delta) - 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& pol, 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& 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<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& 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), 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& 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, 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& 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;
+
+ return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::tgamma_delta_ratio_imp(static_cast<value_type>(a), 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& 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::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
+
+
+
Added: branches/bcbboost/boost/math/special_functions/hermite.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/hermite.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,71 @@
+
+// (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
+
+#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
+
+
Modified: branches/bcbboost/boost/math/special_functions/hypot.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/hypot.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/hypot.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -1,4 +1,4 @@
-// (C) Copyright John Maddock 2005.
+// (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)
@@ -6,88 +6,76 @@
#ifndef BOOST_MATH_HYPOT_INCLUDED
#define BOOST_MATH_HYPOT_INCLUDED
+#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 <cmath>
-#include <boost/limits.hpp>
-#include <algorithm> // swap
-
-#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
-# include <boost/static_assert.hpp>
-#else
-# include <boost/assert.hpp>
-#endif
-
-#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x580))
-#include <boost/type_traits/remove_const.hpp>
-#define BOOST_RCT(T) typename remove_const<T>::type
-#else
-#define BOOST_RCT(T) T
-#endif
+#include <algorithm> // for swap
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::sqrt; using ::fabs; }
#endif
+namespace boost{ namespace math{ namespace detail{
-namespace boost{ namespace math{
-
-template <class T>
-T hypot(T x, T y)
+template <class T, class Policy>
+T hypot_imp(T x, T y, const Policy& pol)
{
-#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
- BOOST_STATIC_ASSERT(::std::numeric_limits<BOOST_RCT(T)>::is_specialized);
-#else
- BOOST_ASSERT(std::numeric_limits<BOOST_RCT(T)>::is_specialized);
-#endif
-
//
- // normalize x and y, so that both are positive and x >= y:
+ // Normalize x and y, so that both are positive and x >= y:
//
- x = (std::fabs)(x);
- y = (std::fabs)(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<BOOST_RCT(T)>::has_infinity
- && ((x == std::numeric_limits<BOOST_RCT(T)>::infinity())
- || (y == std::numeric_limits<BOOST_RCT(T)>::infinity())))
- return std::numeric_limits<BOOST_RCT(T)>::infinity();
+ 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)
+ if(y > x)
(std::swap)(x, y);
- //
- // figure out overflow and underflow limits:
- //
- T safe_upper = (std::sqrt)((std::numeric_limits<BOOST_RCT(T)>::max)()) / 2;
- T safe_lower = (std::sqrt)((std::numeric_limits<BOOST_RCT(T)>::min)());
- static const T one = 1;
- //
- // Now handle special cases:
- //
- if(x >= safe_upper)
- {
- if(y <= one)
- {
- // y is neligible:
- return x;
- }
- return (std::sqrt)(x) * (std::sqrt)(y) * (std::sqrt)(x/y + y/x);
- }
- else if(y <= safe_lower)
- {
- if((x >= one) || (y == 0))
- {
- // y is negligible:
- return x;
- }
- return (std::sqrt)(x) * (std::sqrt)(y) * (std::sqrt)(x/y + y/x);
- }
- //
- // If we get here then x^2+y^2 will not overflow or underflow:
- //
- return (std::sqrt)(x*x + y*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)
+
}
-} } // namespaces
+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);
+}
-#undef BOOST_RCT
+} // namespace math
+} // namespace boost
#endif // BOOST_MATH_HYPOT_INCLUDED
+
+
Added: branches/bcbboost/boost/math/special_functions/laguerre.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/laguerre.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,134 @@
+
+// (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
+
+#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
+
+
Added: branches/bcbboost/boost/math/special_functions/lanczos.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/lanczos.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,1231 @@
+// (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
+
+#include <boost/config.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>(8706.349592549009182288174442774377925882L),
+ static_cast<T>(8523.650341121874633477483696775067709735L),
+ static_cast<T>(3338.029219476423550899999750161289306564L),
+ static_cast<T>(653.6424994294008795995653541449610986791L),
+ static_cast<T>(63.99951844938187085666201263218840287667L),
+ static_cast<T>(2.506628274631006311133031631822390264407L)
+ };
+ 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>(32.81244541029783471623665933780748627823L),
+ static_cast<T>(32.12388941444332003446077108933558534361L),
+ static_cast<T>(12.58034729455216106950851080138931470954L),
+ static_cast<T>(2.463444478353241423633780693218408889251L),
+ static_cast<T>(0.2412010548258800231126240760264822486599L),
+ static_cast<T>(0.009446967704539249494420221613134244048319L)
+ };
+ 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>(2.044879010930422922760429926121241330235L),
+ static_cast<T>(-2.751366405578505366591317846728753993668L),
+ static_cast<T>(1.02282965224225004296750609604264824677L),
+ static_cast<T>(-0.09786124911582813985028889636665335893627L),
+ static_cast<T>(0.0009829742267506615183144364420540766510112L),
+ };
+ 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>(5.748142489536043490764289256167080091892L),
+ static_cast<T>(-7.734074268282457156081021756682138251825L),
+ static_cast<T>(2.875167944990511006997713242805893543947L),
+ static_cast<T>(-0.2750873773533504542306766137703788781776L),
+ static_cast<T>(0.002763134585812698552178368447708846850353L),
+ };
+ 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>(38474670393.31776828316099004518914832218L),
+ static_cast<T>(36857665043.51950660081971227404959150474L),
+ static_cast<T>(15889202453.72942008945006665994637853242L),
+ static_cast<T>(4059208354.298834770194507810788393801607L),
+ static_cast<T>(680547661.1834733286087695557084801366446L),
+ static_cast<T>(78239755.00312005289816041245285376206263L),
+ static_cast<T>(6246580.776401795264013335510453568106366L),
+ static_cast<T>(341986.3488721347032223777872763188768288L),
+ static_cast<T>(12287.19451182455120096222044424100527629L),
+ static_cast<T>(261.6140441641668190791708576058805625502L),
+ static_cast<T>(2.506628274631000502415573855452633787834L)
+ };
+ 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>(709811.662581657956893540610814842699825L),
+ static_cast<T>(679979.847415722640161734319823103390728L),
+ static_cast<T>(293136.785721159725251629480984140341656L),
+ static_cast<T>(74887.5403291467179935942448101441897121L),
+ static_cast<T>(12555.29058241386295096255111537516768137L),
+ static_cast<T>(1443.42992444170669746078056942194198252L),
+ static_cast<T>(115.2419459613734722083208906727972935065L),
+ static_cast<T>(6.30923920573262762719523981992008976989L),
+ static_cast<T>(0.2266840463022436475495508977579735223818L),
+ static_cast<T>(0.004826466289237661857584712046231435101741L),
+ static_cast<T>(0.4624429436045378766270459638520555557321e-4L)
+ };
+ 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>(4.005853070677940377969080796551266387954L),
+ static_cast<T>(-13.17044315127646469834125159673527183164L),
+ static_cast<T>(17.19146865350790353683895137079288129318L),
+ static_cast<T>(-11.36446409067666626185701599196274701126L),
+ static_cast<T>(4.024801119349323770107694133829772634737L),
+ static_cast<T>(-0.7445703262078094128346501724255463005006L),
+ static_cast<T>(0.06513861351917497265045550019547857713172L),
+ static_cast<T>(-0.00217899958561830354633560009312512312758L),
+ static_cast<T>(0.17655204574495137651670832229571934738e-4L),
+ static_cast<T>(-0.1036282091079938047775645941885460820853e-7L),
+ };
+ 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>(19.05889633808148715159575716844556056056L),
+ static_cast<T>(-62.66183664701721716960978577959655644762L),
+ static_cast<T>(81.7929198065004751699057192860287512027L),
+ static_cast<T>(-54.06941772964234828416072865069196553015L),
+ static_cast<T>(19.14904664790693019642068229478769661515L),
+ static_cast<T>(-3.542488556926667589704590409095331790317L),
+ static_cast<T>(0.3099140334815639910894627700232804503017L),
+ static_cast<T>(-0.01036716187296241640634252431913030440825L),
+ static_cast<T>(0.8399926504443119927673843789048514017761e-4L),
+ static_cast<T>(-0.493038376656195010308610694048822561263e-7L),
+ };
+ 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>(44012138428004.60895436261759919070125699L),
+ static_cast<T>(41590453358593.20051581730723108131357995L),
+ static_cast<T>(18013842787117.99677796276038389462742949L),
+ static_cast<T>(4728736263475.388896889723995205703970787L),
+ static_cast<T>(837910083628.4046470415724300225777912264L),
+ static_cast<T>(105583707273.4299344907359855510105321192L),
+ static_cast<T>(9701363618.494999493386608345339104922694L),
+ static_cast<T>(654914397.5482052641016767125048538245644L),
+ static_cast<T>(32238322.94213356530668889463945849409184L),
+ static_cast<T>(1128514.219497091438040721811544858643121L),
+ static_cast<T>(26665.79378459858944762533958798805525125L),
+ static_cast<T>(381.8801248632926870394389468349331394196L),
+ static_cast<T>(2.506628274631000502415763426076722427007L)
+ };
+ 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>(86091529.53418537217994842267760536134841L),
+ static_cast<T>(81354505.17858011242874285785316135398567L),
+ static_cast<T>(35236626.38815461910817650960734605416521L),
+ static_cast<T>(9249814.988024471294683815872977672237195L),
+ static_cast<T>(1639024.216687146960253839656643518985826L),
+ static_cast<T>(206530.8157641225032631778026076868855623L),
+ static_cast<T>(18976.70193530288915698282139308582105936L),
+ static_cast<T>(1281.068909912559479885759622791374106059L),
+ static_cast<T>(63.06093343420234536146194868906771599354L),
+ static_cast<T>(2.207470909792527638222674678171050209691L),
+ static_cast<T>(0.05216058694613505427476207805814960742102L),
+ static_cast<T>(0.0007469903808915448316510079585999893674101L),
+ static_cast<T>(0.4903180573459871862552197089738373164184e-5L)
+ };
+ 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>(4.832115561461656947793029596285626840312L),
+ static_cast<T>(-19.86441536140337740383120735104359034688L),
+ static_cast<T>(33.9927422807443239927197864963170585331L),
+ static_cast<T>(-31.41520692249765980987427413991250886138L),
+ static_cast<T>(17.0270866009599345679868972409543597821L),
+ static_cast<T>(-5.5077216950865501362506920516723682167L),
+ static_cast<T>(1.037811741948214855286817963800439373362L),
+ static_cast<T>(-0.106640468537356182313660880481398642811L),
+ static_cast<T>(0.005276450526660653288757565778182586742831L),
+ static_cast<T>(-0.0001000935625597121545867453746252064770029L),
+ static_cast<T>(0.462590910138598083940803704521211569234e-6L),
+ static_cast<T>(-0.1735307814426389420248044907765671743012e-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>(26.96979819614830698367887026728396466395L),
+ static_cast<T>(-110.8705424709385114023884328797900204863L),
+ static_cast<T>(189.7258846119231466417015694690434770085L),
+ static_cast<T>(-175.3397202971107486383321670769397356553L),
+ static_cast<T>(95.03437648691551457087250340903980824948L),
+ static_cast<T>(-30.7406022781665264273675797983497141978L),
+ static_cast<T>(5.792405601630517993355102578874590410552L),
+ static_cast<T>(-0.5951993240669148697377539518639997795831L),
+ static_cast<T>(0.02944979359164017509944724739946255067671L),
+ static_cast<T>(-0.0005586586555377030921194246330399163602684L),
+ static_cast<T>(0.2581888478270733025288922038673392636029e-5L),
+ static_cast<T>(-0.9685385411006641478305219367315965391289e-9L),
+ };
+ 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>(46198410803245094237463011094.12173081986L),
+ static_cast<T>(43735859291852324413622037436.321513777L),
+ static_cast<T>(19716607234435171720534556386.97481377748L),
+ static_cast<T>(5629401471315018442177955161.245623932129L),
+ static_cast<T>(1142024910634417138386281569.245580222392L),
+ static_cast<T>(175048529315951173131586747.695329230778L),
+ static_cast<T>(21044290245653709191654675.41581372963167L),
+ static_cast<T>(2033001410561031998451380.335553678782601L),
+ static_cast<T>(160394318862140953773928.8736211601848891L),
+ static_cast<T>(10444944438396359705707.48957290388740896L),
+ static_cast<T>(565075825801617290121.1466393747967538948L),
+ static_cast<T>(25475874292116227538.99448534450411942597L),
+ static_cast<T>(957135055846602154.6720835535232270205725L),
+ static_cast<T>(29874506304047462.23662392445173880821515L),
+ static_cast<T>(769651310384737.2749087590725764959689181L),
+ static_cast<T>(16193289100889.15989633624378404096011797L),
+ static_cast<T>(273781151680.6807433264462376754578933261L),
+ static_cast<T>(3630485900.32917021712188739762161583295L),
+ static_cast<T>(36374352.05577334277856865691538582936484L),
+ static_cast<T>(258945.7742115532455441786924971194951043L),
+ static_cast<T>(1167.501919472435718934219997431551246996L),
+ static_cast<T>(2.50662827463100050241576528481104525333L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[22] = {
+ (0uLL),
+ (2432902008176640000uLL),
+ (8752948036761600000uLL),
+ (13803759753640704000uLL),
+ (12870931245150988800uLL),
+ (8037811822645051776uLL),
+ (3599979517947607200uLL),
+ (1206647803780373360uLL),
+ (311333643161390640uLL),
+ (63030812099294896uLL),
+ (10142299865511450uLL),
+ (1307535010540395uLL),
+ (135585182899530uLL),
+ (11310276995381uLL),
+ (756111184500uLL),
+ (40171771630uLL),
+ (1672280820uLL),
+ (53327946uLL),
+ (1256850uLL),
+ (20615uLL),
+ (210uLL),
+ (1uLL)
+ };
+ 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>(6939996264376682180.277485395074954356211L),
+ static_cast<T>(6570067992110214451.87201438870245659384L),
+ static_cast<T>(2961859037444440551.986724631496417064121L),
+ static_cast<T>(845657339772791245.3541226499766163431651L),
+ static_cast<T>(171556737035449095.2475716923888737881837L),
+ static_cast<T>(26296059072490867.7822441885603400926007L),
+ static_cast<T>(3161305619652108.433798300149816829198706L),
+ static_cast<T>(305400596026022.4774396904484542582526472L),
+ static_cast<T>(24094681058862.55120507202622377623528108L),
+ static_cast<T>(1569055604375.919477574824168939428328839L),
+ static_cast<T>(84886558909.02047889339710230696942513159L),
+ static_cast<T>(3827024985.166751989686050643579753162298L),
+ static_cast<T>(143782298.9273215199098728674282885500522L),
+ static_cast<T>(4487794.24541641841336786238909171265944L),
+ static_cast<T>(115618.2025760830513505888216285273541959L),
+ static_cast<T>(2432.580773108508276957461757328744780439L),
+ static_cast<T>(41.12782532742893597168530008461874360191L),
+ static_cast<T>(0.5453771709477689805460179187388702295792L),
+ static_cast<T>(0.005464211062612080347167337964166505282809L),
+ static_cast<T>(0.388992321263586767037090706042788910953e-4L),
+ static_cast<T>(0.1753839324538447655939518484052327068859e-6L),
+ static_cast<T>(0.3765495513732730583386223384116545391759e-9L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[22] = {
+ (0uLL),
+ (2432902008176640000uLL),
+ (8752948036761600000uLL),
+ (13803759753640704000uLL),
+ (12870931245150988800uLL),
+ (8037811822645051776uLL),
+ (3599979517947607200uLL),
+ (1206647803780373360uLL),
+ (311333643161390640uLL),
+ (63030812099294896uLL),
+ (10142299865511450uLL),
+ (1307535010540395uLL),
+ (135585182899530uLL),
+ (11310276995381uLL),
+ (756111184500uLL),
+ (40171771630uLL),
+ (1672280820uLL),
+ (53327946uLL),
+ (1256850uLL),
+ (20615uLL),
+ (210uLL),
+ (1uLL)
+ };
+ 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>(8.318998691953337183034781139546384476554L),
+ static_cast<T>(-63.15415991415959158214140353299240638675L),
+ static_cast<T>(217.3108224383632868591462242669081540163L),
+ static_cast<T>(-448.5134281386108366899784093610397354889L),
+ static_cast<T>(619.2903759363285456927248474593012711346L),
+ static_cast<T>(-604.1630177420625418522025080080444177046L),
+ static_cast<T>(428.8166750424646119935047118287362193314L),
+ static_cast<T>(-224.6988753721310913866347429589434550302L),
+ static_cast<T>(87.32181627555510833499451817622786940961L),
+ static_cast<T>(-25.07866854821128965662498003029199058098L),
+ static_cast<T>(5.264398125689025351448861011657789005392L),
+ static_cast<T>(-0.792518936256495243383586076579921559914L),
+ static_cast<T>(0.08317448364744713773350272460937904691566L),
+ static_cast<T>(-0.005845345166274053157781068150827567998882L),
+ static_cast<T>(0.0002599412126352082483326238522490030412391L),
+ static_cast<T>(-0.6748102079670763884917431338234783496303e-5L),
+ static_cast<T>(0.908824383434109002762325095643458603605e-7L),
+ static_cast<T>(-0.5299325929309389890892469299969669579725e-9L),
+ static_cast<T>(0.994306085859549890267983602248532869362e-12L),
+ static_cast<T>(-0.3499893692975262747371544905820891835298e-15L),
+ static_cast<T>(0.7260746353663365145454867069182884694961e-20L),
+ };
+ 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>(75.39272007105208086018421070699575462226L),
+ static_cast<T>(-572.3481967049935412452681346759966390319L),
+ static_cast<T>(1969.426202741555335078065370698955484358L),
+ static_cast<T>(-4064.74968778032030891520063865996757519L),
+ static_cast<T>(5612.452614138013929794736248384309574814L),
+ static_cast<T>(-5475.357667500026172903620177988213902339L),
+ static_cast<T>(3886.243614216111328329547926490398103492L),
+ static_cast<T>(-2036.382026072125407192448069428134470564L),
+ static_cast<T>(791.3727954936062108045551843636692287652L),
+ static_cast<T>(-227.2808432388436552794021219198885223122L),
+ static_cast<T>(47.70974355562144229897637024320739257284L),
+ static_cast<T>(-7.182373807798293545187073539819697141572L),
+ static_cast<T>(0.7537866989631514559601547530490976100468L),
+ static_cast<T>(-0.05297470142240154822658739758236594717787L),
+ static_cast<T>(0.00235577330936380542539812701472320434133L),
+ static_cast<T>(-0.6115613067659273118098229498679502138802e-4L),
+ static_cast<T>(0.8236417010170941915758315020695551724181e-6L),
+ static_cast<T>(-0.4802628430993048190311242611330072198089e-8L),
+ static_cast<T>(0.9011113376981524418952720279739624707342e-11L),
+ static_cast<T>(-0.3171854152689711198382455703658589996796e-14L),
+ static_cast<T>(0.6580207998808093935798753964580596673177e-19L),
+ };
+ 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>(553681095419291969.2230556393350368550504L),
+ static_cast<T>(731918863887667017.2511276782146694632234L),
+ static_cast<T>(453393234285807339.4627124634539085143364L),
+ static_cast<T>(174701893724452790.3546219631779712198035L),
+ static_cast<T>(46866125995234723.82897281620357050883077L),
+ static_cast<T>(9281280675933215.169109622777099699054272L),
+ static_cast<T>(1403600894156674.551057997617468721789536L),
+ static_cast<T>(165345984157572.7305349809894046783973837L),
+ static_cast<T>(15333629842677.31531822808737907246817024L),
+ static_cast<T>(1123152927963.956626161137169462874517318L),
+ static_cast<T>(64763127437.92329018717775593533620578237L),
+ static_cast<T>(2908830362.657527782848828237106640944457L),
+ static_cast<T>(99764700.56999856729959383751710026787811L),
+ static_cast<T>(2525791.604886139959837791244686290089331L),
+ static_cast<T>(44516.94034970167828580039370201346554872L),
+ static_cast<T>(488.0063567520005730476791712814838113252L),
+ static_cast<T>(2.50662827463100050241576877135758834683L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[17] = {
+ (0uLL),
+ (1307674368000uLL),
+ (4339163001600uLL),
+ (6165817614720uLL),
+ (5056995703824uLL),
+ (2706813345600uLL),
+ (1009672107080uLL),
+ (272803210680uLL),
+ (54631129553uLL),
+ (8207628000uLL),
+ (928095740uLL),
+ (78558480uLL),
+ (4899622uLL),
+ (218400uLL),
+ (6580uLL),
+ (120uLL),
+ (1uLL)
+ };
+ 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>(2715894658327.717377557655133124376674911L),
+ static_cast<T>(3590179526097.912105038525528721129550434L),
+ static_cast<T>(2223966599737.814969312127353235818710172L),
+ static_cast<T>(856940834518.9562481809925866825485883417L),
+ static_cast<T>(229885871668.749072933597446453399395469L),
+ static_cast<T>(45526171687.54610815813502794395753410032L),
+ static_cast<T>(6884887713.165178784550917647709216424823L),
+ static_cast<T>(811048596.1407531864760282453852372777439L),
+ static_cast<T>(75213915.96540822314499613623119501704812L),
+ static_cast<T>(5509245.417224265151697527957954952830126L),
+ static_cast<T>(317673.5368435419126714931842182369574221L),
+ static_cast<T>(14268.27989845035520147014373320337523596L),
+ static_cast<T>(489.3618720403263670213909083601787814792L),
+ static_cast<T>(12.38941330038454449295883217865458609584L),
+ static_cast<T>(0.2183627389504614963941574507281683147897L),
+ static_cast<T>(0.002393749522058449186690627996063983095463L),
+ static_cast<T>(0.1229541408909435212800785616808830746135e-4L)
+ };
+ static const BOOST_MATH_INT_TABLE_TYPE(T, boost::uint64_t) denom[17] = {
+ (0uLL),
+ (1307674368000uLL),
+ (4339163001600uLL),
+ (6165817614720uLL),
+ (5056995703824uLL),
+ (2706813345600uLL),
+ (1009672107080uLL),
+ (272803210680uLL),
+ (54631129553uLL),
+ (8207628000uLL),
+ (928095740uLL),
+ (78558480uLL),
+ (4899622uLL),
+ (218400uLL),
+ (6580uLL),
+ (120uLL),
+ (1uLL)
+ };
+ 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>(4.493645054286536365763334986866616581265L),
+ static_cast<T>(-16.95716370392468543800733966378143997694L),
+ static_cast<T>(26.19196892983737527836811770970479846644L),
+ static_cast<T>(-21.3659076437988814488356323758179283908L),
+ static_cast<T>(9.913992596774556590710751047594507535764L),
+ static_cast<T>(-2.62888300018780199210536267080940382158L),
+ static_cast<T>(0.3807056693542503606384861890663080735588L),
+ static_cast<T>(-0.02714647489697685807340312061034730486958L),
+ static_cast<T>(0.0007815484715461206757220527133967191796747L),
+ static_cast<T>(-0.6108630817371501052576880554048972272435e-5L),
+ static_cast<T>(0.5037380238864836824167713635482801545086e-8L),
+ static_cast<T>(-0.1483232144262638814568926925964858237006e-13L),
+ static_cast<T>(0.1346609158752142460943888149156716841693e-14L),
+ static_cast<T>(-0.660492688923978805315914918995410340796e-15L),
+ static_cast<T>(0.1472114697343266749193617793755763792681e-15L),
+ static_cast<T>(-0.1410901942033374651613542904678399264447e-16L),
+ };
+ 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>(23.56409085052261327114594781581930373708L),
+ static_cast<T>(-88.92116338946308797946237246006238652361L),
+ static_cast<T>(137.3472822086847596961177383569603988797L),
+ static_cast<T>(-112.0400438263562152489272966461114852861L),
+ static_cast<T>(51.98768915202973863076166956576777843805L),
+ static_cast<T>(-13.78552090862799358221343319574970124948L),
+ static_cast<T>(1.996371068830872830250406773917646121742L),
+ static_cast<T>(-0.1423525874909934506274738563671862576161L),
+ static_cast<T>(0.004098338646046865122459664947239111298524L),
+ static_cast<T>(-0.3203286637326511000882086573060433529094e-4L),
+ static_cast<T>(0.2641536751640138646146395939004587594407e-7L),
+ static_cast<T>(-0.7777876663062235617693516558976641009819e-13L),
+ static_cast<T>(0.7061443477097101636871806229515157914789e-14L),
+ static_cast<T>(-0.3463537849537988455590834887691613484813e-14L),
+ static_cast<T>(0.7719578215795234036320348283011129450595e-15L),
+ static_cast<T>(-0.7398586479708476329563577384044188912075e-16L),
+ };
+ 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>(2029889364934367661624137213253.22102954656825019111612712252027267955023987678816620961507L),
+ static_cast<T>(2338599599286656537526273232565.2727349714338768161421882478417543004440597874814359063158L),
+ static_cast<T>(1288527989493833400335117708406.3953711906175960449186720680201425446299360322830739180195L),
+ static_cast<T>(451779745834728745064649902914.550539158066332484594436145043388809847364393288132164411521L),
+ static_cast<T>(113141284461097964029239556815.291212318665536114012605167994061291631013303788706545334708L),
+ static_cast<T>(21533689802794625866812941616.7509064680880468667055339259146063256555368135236149614592432L),
+ static_cast<T>(3235510315314840089932120340.71494940111731241353655381919722177496659303550321056514776757L),
+ static_cast<T>(393537392344185475704891959.081297108513472083749083165179784098220158201055270548272414314L),
+ static_cast<T>(39418265082950435024868801.5005452240816902251477336582325944930252142622315101857742955673L),
+ static_cast<T>(3290158764187118871697791.05850632319194734270969161036889516414516566453884272345518372696L),
+ static_cast<T>(230677110449632078321772.618245845856640677845629174549731890660612368500786684333975350954L),
+ static_cast<T>(13652233645509183190158.5916189185218250859402806777406323001463296297553612462737044693697L),
+ static_cast<T>(683661466754325350495.216655026531202476397782296585200982429378069417193575896602446904762L),
+ static_cast<T>(28967871782219334117.0122379171041074970463982134039409352925258212207710168851968215545064L),
+ static_cast<T>(1036104088560167006.2022834098572346459442601718514554488352117620272232373622553429728555L),
+ static_cast<T>(31128490785613152.8380102669349814751268126141105475287632676569913936040772990253369753962L),
+ static_cast<T>(779327504127342.536207878988196814811198475410572992436243686674896894543126229424358472541L),
+ static_cast<T>(16067543181294.643350688789124777020407337133926174150582333950666044399234540521336771876L),
+ static_cast<T>(268161795520.300916569439413185778557212729611517883948634711190170998896514639936969855484L),
+ static_cast<T>(3533216359.10528191668842486732408440112703691790824611391987708562111396961696753452085068L),
+ static_cast<T>(35378979.5479656110614685178752543826919239614088343789329169535932709470588426584501652577L),
+ static_cast<T>(253034.881362204346444503097491737872930637147096453940375713745904094735506180552724766444L),
+ static_cast<T>(1151.61895453463992438325318456328526085882924197763140514450975619271382783957699017875304L),
+ static_cast<T>(2.50662827463100050241576528481104515966515623051532908941425544355490413900497467936202516L)
+ };
+ static const T denom[24] = {
+ static_cast<T>(0L),
+ static_cast<T>(0.112400072777760768e22L),
+ static_cast<T>(0.414847677933545472e22L),
+ static_cast<T>(6756146673770930688000.0L),
+ static_cast<T>(6548684852703068697600.0L),
+ static_cast<T>(4280722865357147142912.0L),
+ static_cast<T>(2021687376910682741568.0L),
+ static_cast<T>(720308216440924653696.0L),
+ static_cast<T>(199321978221066137360.0L),
+ static_cast<T>(43714229649594412832.0L),
+ static_cast<T>(7707401101297361068.0L),
+ static_cast<T>(1103230881185949736.0L),
+ static_cast<T>(129006659818331295.0L),
+ static_cast<T>(12363045847086207.0L),
+ static_cast<T>(971250460939913.0L),
+ static_cast<T>(62382416421941.0L),
+ static_cast<T>(3256091103430.0L),
+ static_cast<T>(136717357942.0L),
+ static_cast<T>(4546047198.0L),
+ static_cast<T>(116896626L),
+ static_cast<T>(2240315L),
+ static_cast<T>(30107L),
+ static_cast<T>(253L),
+ static_cast<T>(1L)
+ };
+ 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>(3035162425359883494754.02878223286972654682199012688209026810841953293372712802258398358538L),
+ static_cast<T>(3496756894406430103600.16057175075063458536101374170860226963245118484234495645518505519827L),
+ static_cast<T>(1926652656689320888654.01954015145958293168365236755537645929361841917596501251362171653478L),
+ static_cast<T>(675517066488272766316.083023742440619929434602223726894748181327187670231286180156444871912L),
+ static_cast<T>(169172853104918752780.086262749564831660238912144573032141700464995906149421555926000038492L),
+ static_cast<T>(32197935167225605785.6444116302160245528783954573163541751756353183343357329404208062043808L),
+ static_cast<T>(4837849542714083249.37587447454818124327561966323276633775195138872820542242539845253171632L),
+ static_cast<T>(588431038090493242.308438203986649553459461798968819276505178004064031201740043314534404158L),
+ static_cast<T>(58939585141634058.6206417889192563007809470547755357240808035714047014324843817783741669733L),
+ static_cast<T>(4919561837722192.82991866530802080996138070630296720420704876654726991998309206256077395868L),
+ static_cast<T>(344916580244240.407442753122831512004021081677987651622305356145640394384006997569631719101L),
+ static_cast<T>(20413302960687.8250598845969238472629322716685686993835561234733641729957841485003560103066L),
+ static_cast<T>(1022234822943.78400752460970689311934727763870970686747383486600540378889311406851534545789L),
+ static_cast<T>(43313787191.9821354846952908076307094286897439975815501673706144217246093900159173598852503L),
+ static_cast<T>(1549219505.59667418528481770869280437577581951167003505825834192510436144666564648361001914L),
+ static_cast<T>(46544421.1998761919380541579358096705925369145324466147390364674998568485110045455014967149L),
+ static_cast<T>(1165278.06807504975090675074910052763026564833951579556132777702952882101173607903881127542L),
+ static_cast<T>(24024.759267256769471083727721827405338569868270177779485912486668586611981795179894572115L),
+ static_cast<T>(400.965008113421955824358063769761286758463521789765880962939528760888853281920872064838918L),
+ static_cast<T>(5.28299015654478269617039029170846385138134929147421558771949982217659507918482272439717603L),
+ static_cast<T>(0.0528999024412510102409256676599360516359062802002483877724963720047531347449011629466149805L),
+ static_cast<T>(0.000378346710654740685454266569593414561162134092347356968516522170279688139165340746957511115L),
+ static_cast<T>(0.172194142179211139195966608011235161516824700287310869949928393345257114743230967204370963e-5L),
+ static_cast<T>(0.374799931707148855771381263542708435935402853962736029347951399323367765509988401336565436e-8L)
+ };
+ static const T denom[24] = {
+ static_cast<T>(0L),
+ static_cast<T>(0.112400072777760768e22L),
+ static_cast<T>(0.414847677933545472e22L),
+ static_cast<T>(6756146673770930688000.0L),
+ static_cast<T>(6548684852703068697600.0L),
+ static_cast<T>(4280722865357147142912.0L),
+ static_cast<T>(2021687376910682741568.0L),
+ static_cast<T>(720308216440924653696.0L),
+ static_cast<T>(199321978221066137360.0L),
+ static_cast<T>(43714229649594412832.0L),
+ static_cast<T>(7707401101297361068.0L),
+ static_cast<T>(1103230881185949736.0L),
+ static_cast<T>(129006659818331295.0L),
+ static_cast<T>(12363045847086207.0L),
+ static_cast<T>(971250460939913.0L),
+ static_cast<T>(62382416421941.0L),
+ static_cast<T>(3256091103430.0L),
+ static_cast<T>(136717357942.0L),
+ static_cast<T>(4546047198.0L),
+ static_cast<T>(116896626L),
+ static_cast<T>(2240315L),
+ static_cast<T>(30107L),
+ static_cast<T>(253L),
+ static_cast<T>(1L)
+ };
+ 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>(7.4734083002469026177867421609938203388868806387315406134072298925733950040583068760685908L),
+ static_cast<T>(-50.4225805042247530267317342133388132970816607563062253708655085754357843064134941138154171L),
+ static_cast<T>(152.288200621747008570784082624444625293884063492396162110698238568311211546361189979357019L),
+ static_cast<T>(-271.894959539150384169327513139846971255640842175739337449692360299099322742181325023644769L),
+ static_cast<T>(319.240102980202312307047586791116902719088581839891008532114107693294261542869734803906793L),
+ static_cast<T>(-259.493144143048088289689500935518073716201741349569864988870534417890269467336454358361499L),
+ static_cast<T>(149.747518319689708813209645403067832020714660918583227716408482877303972685262557460145835L),
+ static_cast<T>(-61.9261301009341333289187201425188698128684426428003249782448828881580630606817104372760037L),
+ static_cast<T>(18.3077524177286961563937379403377462608113523887554047531153187277072451294845795496072365L),
+ static_cast<T>(-3.82011322251948043097070160584761236869363471824695092089556195047949392738162970152230254L),
+ static_cast<T>(0.549382685505691522516705902336780999493262538301283190963770663549981309645795228539620711L),
+ static_cast<T>(-0.0524814679715180697633723771076668718265358076235229045603747927518423453658004287459638024L),
+ static_cast<T>(0.00315392664003333528534120626687784812050217700942910879712808180705014754163256855643360698L),
+ static_cast<T>(-0.000110098373127648510519799564665442121339511198561008748083409549601095293123407080388658329L),
+ static_cast<T>(0.19809382866681658224945717689377373458866950897791116315219376038432014207446832310901893e-5L),
+ static_cast<T>(-0.152278977408600291408265615203504153130482270424202400677280558181047344681214058227949755e-7L),
+ static_cast<T>(0.364344768076106268872239259083188037615571711218395765792787047015406264051536972018235217e-10L),
+ static_cast<T>(-0.148897510480440424971521542520683536298361220674662555578951242811522959610991621951203526e-13L),
+ static_cast<T>(0.261199241161582662426512749820666625442516059622425213340053324061794752786482115387573582e-18L),
+ static_cast<T>(-0.780072664167099103420998436901014795601783313858454665485256897090476089641613851903791529e-24L),
+ static_cast<T>(0.303465867587106629530056603454807425512962762653755513440561256044986695349304176849392735e-24L),
+ static_cast<T>(-0.615420597971283870342083342286977366161772327800327789325710571275345878439656918541092056e-25L),
+ static_cast<T>(0.499641233843540749369110053005439398774706583601830828776209650445427083113181961630763702e-26L),
+ };
+ 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>(61.4165001061101455341808888883960361969557848005400286332291451422461117307237198559485365L),
+ static_cast<T>(-414.372973678657049667308134761613915623353625332248315105320470271523320700386200587519147L),
+ static_cast<T>(1251.50505818554680171298972755376376836161706773644771875668053742215217922228357204561873L),
+ static_cast<T>(-2234.43389421602399514176336175766511311493214354568097811220122848998413358085613880612158L),
+ static_cast<T>(2623.51647746991904821899989145639147785427273427135380151752779100215839537090464785708684L),
+ static_cast<T>(-2132.51572435428751962745870184529534443305617818870214348386131243463614597272260797772423L),
+ static_cast<T>(1230.62572059218405766499842067263311220019173335523810725664442147670956427061920234820189L),
+ static_cast<T>(-508.90919151163744999377586956023909888833335885805154492270846381061182696305011395981929L),
+ static_cast<T>(150.453184562246579758706538566480316921938628645961177699894388251635886834047343195475395L),
+ static_cast<T>(-31.3937061525822497422230490071156186113405446381476081565548185848237169870395131828731397L),
+ static_cast<T>(4.51482916590287954234936829724231512565732528859217337795452389161322923867318809206313688L),
+ static_cast<T>(-0.431292919341108177524462194102701868233551186625103849565527515201492276412231365776131952L),
+ static_cast<T>(0.0259189820815586225636729971503340447445001375909094681698918294680345547092233915092128323L),
+ static_cast<T>(-0.000904788882557558697594884691337532557729219389814315972435534723829065673966567231504429712L),
+ static_cast<T>(0.162793589759218213439218473348810982422449144393340433592232065020562974405674317564164312e-4L),
+ static_cast<T>(-0.125142926178202562426432039899709511761368233479483128438847484617555752948755923647214487e-6L),
+ static_cast<T>(0.299418680048132583204152682950097239197934281178261879500770485862852229898797687301941982e-9L),
+ static_cast<T>(-0.122364035267809278675627784883078206654408225276233049012165202996967011873995261617995421e-12L),
+ static_cast<T>(0.21465364366598631597052073538883430194257709353929022544344097235100199405814005393447785e-17L),
+ static_cast<T>(-0.641064035802907518396608051803921688237330857546406669209280666066685733941549058513986818e-23L),
+ static_cast<T>(0.249388374622173329690271566855185869111237201309011956145463506483151054813346819490278951e-23L),
+ static_cast<T>(-0.505752900177513489906064295001851463338022055787536494321532352380960774349054239257683149e-24L),
+ static_cast<T>(0.410605371184590959139968810080063542546949719163227555918846829816144878123034347778284006e-25L),
+ };
+ 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
+
+#endif // BOOST_MATH_SPECIAL_FUNCTIONS_LANCZOS
+
+
+
Added: branches/bcbboost/boost/math/special_functions/legendre.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/legendre.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,189 @@
+
+// (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
+
+#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 = 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 * 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 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 = 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, 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
+
+
Modified: branches/bcbboost/boost/math/special_functions/log1p.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/log1p.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/log1p.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -1,4 +1,4 @@
-// (C) Copyright John Maddock 2005.
+// (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)
@@ -9,7 +9,10 @@
#include <cmath>
#include <math.h> // platform's ::log1p
#include <boost/limits.hpp>
-#include <boost/math/special_functions/detail/series.hpp>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/series.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>
@@ -17,77 +20,90 @@
# include <boost/assert.hpp>
#endif
-#ifdef BOOST_NO_STDC_NAMESPACE
-namespace std{ using ::fabs; using ::log; }
-#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
+namespace detail
{
- 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&);
-};
+ // 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&);
+ };
-} // namespace
+} // namespace detail
-//
// 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 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.
+// 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>
-T log1p(T x)
-{
-#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
- BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized);
+template <class T, class Policy>
+typename tools::promote_args<T>::type log1p(T x, const Policy& pol)
+{ // The function returns the natural logarithm of 1 + x.
+ // A domain error occurs if x < -1. TODO should there be a check?
+ typedef typename tools::promote_args<T>::type result_type;
+ BOOST_MATH_STD_USING
+ using std::abs;
+
+ 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.5L))
+ 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))
+ result_type result = tools::sum_series(s, policies::digits<result_type, Policy>(), max_iter);
#else
- BOOST_ASSERT(std::numeric_limits<T>::is_specialized);
+ result_type zero = 0;
+ result_type result = tools::sum_series(s, policies::digits<result_type, Policy>(), max_iter, zero);
#endif
- T a = std::fabs(x);
- if(a > T(0.5L))
- return std::log(T(1.0) + x);
- if(a < std::numeric_limits<T>::epsilon())
- return x;
- detail::log1p_series<T> s(x);
- return detail::kahan_sum_series(s, std::numeric_limits<T>::digits + 2);
+ policies::check_series_iterations(function, max_iter, pol);
+ return result;
}
+
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
-// these overloads work around a type deduction bug:
+// These overloads work around a type deduction bug:
inline float log1p(float z)
{
return log1p<float>(z);
@@ -110,15 +126,150 @@
#endif
#ifdef BOOST_HAS_LOG1P
-# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
-inline float log1p(float x){ return ::log1pf(x); }
-inline long double log1p(long double x){ return ::log1pl(x); }
+# if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) \
+ || defined(linux) || defined(__linux) || defined(__linux__) \
+ || defined(__hpux)
+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);
+}
+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);
+}
#else
-inline float log1p(float x){ return ::log1p(x); }
+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));
+}
+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 log(u)*(x/(u-1.0));
+}
#endif
-inline double log1p(double x){ return ::log1p(x); }
+
+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.95L))
+ 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::digits<T, Policy>(), max_iter, zero);
+#else
+ T result = boost::math::tools::sum_series(s, policies::digits<T, Policy>(), max_iter);
#endif
+ policies::check_series_iterations(function, max_iter, pol);
+ return result;
+}
+
+template <class T>
+inline T log1pmx(T x)
+{
+ return log1pmx(x, policies::policy<>());
+}
+
+} // namespace math
+} // namespace boost
+
+#endif // BOOST_MATH_LOG1P_INCLUDED
-} } // namespaces
-#endif // BOOST_MATH_HYPOT_INCLUDED
Added: branches/bcbboost/boost/math/special_functions/math_fwd.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/math_fwd.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,916 @@
+// 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
+
+#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);
+
+ template <class T1, class T2, class T3>
+ typename tools::promote_args<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);
+ 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);
+
+ // Fpclassify - classify floating-point as NaN or infinity...
+ template <class T>
+ int fpclassify (T);
+
+ // 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(const T x);
+
+ template<typename T, class Policy>
+ typename tools::promote_args<T>::type asinh(const T x, const Policy&);
+
+ template<typename T>
+ typename tools::promote_args<T>::type acosh(const T x);
+
+ template<typename T, class Policy>
+ typename tools::promote_args<T>::type acosh(const T x, const Policy&);
+
+ template<typename T>
+ typename tools::promote_args<T>::type atanh(const T x);
+
+ template<typename T, class Policy>
+ typename tools::promote_args<T>::type atanh(const 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>
+ T sin_pi(T x, const Policy&);
+
+ template <class T>
+ T sin_pi(T x);
+
+ template <class T, class Policy>
+ T cos_pi(T x, const Policy&);
+
+ template <class T>
+ T 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);
+
+ } // namespace math
+} // namespace boost
+
+#define BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(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()); }\
+ using boost::math::fpclassify;\
+\
+ 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 T sin_pi(T x){ return boost::math::sin_pi(x); }\
+\
+ template <class T>\
+ inline T 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;
+
+#endif // BOOST_MATH_SPECIAL_MATH_FWD_HPP
Added: branches/bcbboost/boost/math/special_functions/powm1.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/powm1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,56 @@
+// (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
+
+#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
+
+
+
+
Added: branches/bcbboost/boost/math/special_functions/sign.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/sign.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,37 @@
+// (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_TOOLS_SIGN_HPP
+#define BOOST_MATH_TOOLS_SIGN_HPP
+
+#include <cmath>
+#include <cstdlib>
+
+namespace boost{ namespace math{
+
+template <class T>
+inline int sign(const T& z)
+{
+ return (z == 0) ? 0 : (z < 0) ? -1 : 1;
+}
+
+template <class T>
+inline int signbit(const T& z)
+{
+ return (z < 0) ? 1 : 0;
+}
+
+template <class T>
+inline T copysign(const T& x, const T& y)
+{
+ return fabs(x) * boost::math::sign(y);
+}
+
+} // namespace math
+} // namespace boost
+
+
+#endif // BOOST_MATH_TOOLS_SIGN_HPP
+
Added: branches/bcbboost/boost/math/special_functions/sin_pi.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/sin_pi.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,53 @@
+// 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
+
+#include <cmath>
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/real_cast.hpp>
+#include <boost/math/constants/constants.hpp>
+
+namespace boost{ namespace math{
+
+template <class T>
+T sin_pi(T x)
+{
+ BOOST_MATH_STD_USING // ADL of std names
+ // 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(tools::real_cast<int>(rem) & 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 ? -rem : rem;
+}
+
+template <class T, class Policy>
+inline T sin_pi(T x, const Policy&)
+{
+ return boost::math::sin_pi(x);
+}
+
+} // namespace math
+} // namespace boost
+#endif
Modified: branches/bcbboost/boost/math/special_functions/sinc.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/sinc.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/sinc.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -11,6 +11,10 @@
#define BOOST_SINC_HPP
+#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 <cmath>
#include <boost/limits.hpp>
#include <string>
@@ -26,6 +30,8 @@
{
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:
@@ -40,7 +46,7 @@
// This is the "Sinus Cardinal" of index Pi.
template<typename T>
- inline T sinc_pi(const T x)
+ inline T sinc_pi_imp(const T x)
{
#ifdef BOOST_NO_STDC_NAMESPACE
using ::abs;
@@ -52,9 +58,8 @@
using ::std::sqrt;
#endif /* BOOST_NO_STDC_NAMESPACE */
- using ::std::numeric_limits;
-
- static T const taylor_0_bound = numeric_limits<T>::epsilon();
+ // 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);
@@ -85,6 +90,21 @@
}
}
+ } // 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 */
@@ -105,7 +125,7 @@
using ::std::numeric_limits;
- static T const taylor_0_bound = numeric_limits<T>::epsilon();
+ 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);
@@ -139,6 +159,12 @@
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 */
}
}
Modified: branches/bcbboost/boost/math/special_functions/sinhc.hpp
==============================================================================
--- branches/bcbboost/boost/math/special_functions/sinhc.hpp (original)
+++ branches/bcbboost/boost/math/special_functions/sinhc.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -11,6 +11,9 @@
#define BOOST_SINHC_HPP
+#include <boost/math/tools/config.hpp>
+#include <boost/math/tools/precision.hpp>
+#include <boost/math/special_functions/math_fwd.hpp>
#include <cmath>
#include <boost/limits.hpp>
#include <string>
@@ -26,6 +29,8 @@
{
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:
@@ -40,7 +45,7 @@
// This is the "Hyperbolic Sinus Cardinal" of index Pi.
template<typename T>
- inline T sinhc_pi(const T x)
+ inline T sinhc_pi_imp(const T x)
{
#ifdef BOOST_NO_STDC_NAMESPACE
using ::abs;
@@ -52,9 +57,7 @@
using ::std::sqrt;
#endif /* BOOST_NO_STDC_NAMESPACE */
- using ::std::numeric_limits;
-
- static T const taylor_0_bound = numeric_limits<T>::epsilon();
+ 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);
@@ -85,6 +88,20 @@
}
}
+ } // 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 */
@@ -105,7 +122,7 @@
using ::std::numeric_limits;
- static T const taylor_0_bound = numeric_limits<T>::epsilon();
+ 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);
Added: branches/bcbboost/boost/math/special_functions/spherical_harmonic.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/spherical_harmonic.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,198 @@
+
+// (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
+
+#include <boost/math/special_functions/legendre.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, pow(fabs(sin_theta), T(m)), pol);
+
+ T prefix = 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, 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 ? -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, 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 ? -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
+
+
Added: branches/bcbboost/boost/math/special_functions/sqrt1pm1.hpp
==============================================================================
--- (empty file)
+++ branches/bcbboost/boost/math/special_functions/sqrt1pm1.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -0,0 +1,43 @@
+// (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
+
+#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
+
+
+
+
Modified: branches/bcbboost/boost/math/tools/config.hpp
==============================================================================
--- /trunk/boost/math/tools/config.hpp (original)
+++ branches/bcbboost/boost/math/tools/config.hpp 2007-10-09 16:49:04 EDT (Tue, 09 Oct 2007)
@@ -1,8 +1,3 @@
-// Copyright (c) 2006-7 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_TOOLS_CONFIG_HPP
#define BOOST_MATH_TOOLS_CONFIG_HPP
@@ -22,20 +17,7 @@
# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
#endif
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
-//
-// Borland post 5.8.2 uses Dinkumware's std C lib which
-// doesn't have true long double precision. Earlier
-// versions are problematic too:
-//
# define BOOST_MATH_NO_REAL_CONCEPT_TESTS
-# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
-#endif
-#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106))
-//
-// Darwin's rather strange "double double" is rather hard to
-// support, it should be possible given enough effort though...
-//
-# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
@@ -126,6 +108,24 @@
{
return (std::max)((std::max)(a, b), (std::max)(c, d));
}
+//
+// We call this short forwarding function so that we can work around a bug
+// on Darwin that causes std::fmod to return a NaN. The test case is:
+// std::fmod(1185.0L, 1.5L);
+//
+template <class T>
+inline T fmod_workaround(T a, T b)
+{
+ BOOST_MATH_STD_USING
+ return fmod(a, b);
+}
+#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106))
+template <>
+inline long double fmod_workaround(long double a, long double b)
+{
+ return ::fmodl(a, b);
+}
+#endif
} // namespace tools
}} // namespace boost namespace math
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_10.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_11.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_12.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_13.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_14.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_15.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_16.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_17.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_18.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_19.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_2.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_20.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_3.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_4.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_5.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_6.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_7.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_8.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner1_9.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_10.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_11.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_12.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_13.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_14.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_15.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_16.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_17.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_18.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_19.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_2.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_20.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_3.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_4.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_5.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_6.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_7.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_8.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner2_9.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_10.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_11.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_12.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_13.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_14.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_15.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_16.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_17.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_18.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_19.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_2.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_20.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_3.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_4.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_5.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_6.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_7.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_8.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/polynomial_horner3_9.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_10.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_11.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_12.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_13.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_14.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_15.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_16.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_17.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_18.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_19.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_2.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_20.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_3.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_4.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_5.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_6.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_7.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_8.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner1_9.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_10.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_11.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_12.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_13.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_14.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_15.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_16.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_17.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_18.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_19.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_2.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_20.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_3.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_4.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_5.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_6.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_7.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_8.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner2_9.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_10.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_11.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_12.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_13.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_14.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_15.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_16.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_17.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_18.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_19.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_2.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_20.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_3.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_4.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_5.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_6.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_7.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_8.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/detail/rational_horner3_9.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/fraction.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/minima.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/polynomial.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/precision.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/promotion.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/rational.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/real_cast.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/remez.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/roots.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/series.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/solve.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/stats.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/test.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/test_data.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/toms748_solve.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/traits.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/user.hpp
==============================================================================
Modified: branches/bcbboost/boost/math/tools/workaround.hpp
==============================================================================
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk