Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r79892 - trunk/boost/math/distributions
From: pbristow_at_[hidden]
Date: 2012-08-06 12:30:12


Author: pbristow
Date: 2012-08-06 12:30:12 EDT (Mon, 06 Aug 2012)
New Revision: 79892
URL: http://svn.boost.org/trac/boost/changeset/79892

Log:
Using the 1/eps to switch to normal distribution.
Text files modified:
   trunk/boost/math/distributions/students_t.hpp | 127 +++++++++++++++++++++++++--------------
   1 files changed, 80 insertions(+), 47 deletions(-)

Modified: trunk/boost/math/distributions/students_t.hpp
==============================================================================
--- trunk/boost/math/distributions/students_t.hpp (original)
+++ trunk/boost/math/distributions/students_t.hpp 2012-08-06 12:30:12 EDT (Mon, 06 Aug 2012)
@@ -14,6 +14,7 @@
 #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x).
 #include <boost/math/distributions/complement.hpp>
 #include <boost/math/distributions/detail/common_error_handling.hpp>
+#include <boost/math/distributions/normal.hpp>
 
 #include <utility>
 
@@ -53,9 +54,9 @@
 
 private:
    //
- // Data members:
+ // Data member:
    //
- RealType m_df; // degrees of freedom are a real number.
+ RealType m_df; // degrees of freedom is a real number.
 };
 
 typedef students_t_distribution<double> students_t;
@@ -63,6 +64,7 @@
 template <class RealType, class Policy>
 inline const std::pair<RealType, RealType> range(const students_t_distribution<RealType, Policy>& /*dist*/)
 { // Range of permissible values for random variable x.
+ // No including infinity.
    using boost::math::tools::max_value;
    return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
 }
@@ -76,32 +78,48 @@
 }
 
 template <class RealType, class Policy>
-inline RealType pdf(const students_t_distribution<RealType, Policy>& dist, const RealType& t)
+inline RealType pdf(const students_t_distribution<RealType, Policy>& dist, const RealType& x)
 {
    BOOST_FPU_EXCEPTION_GUARD
    BOOST_MATH_STD_USING // for ADL of std functions
 
    RealType degrees_of_freedom = dist.degrees_of_freedom();
- // Error check:
+ // common handling Error check is for finite and > 0:
+ // Might conceivably permit df = +infinity too?
    RealType error_result;
    if(false == detail::check_df(
       "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", degrees_of_freedom, &error_result, Policy()))
       return error_result;
    if(false == detail::check_x(
- "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", t, &error_result, Policy()))
+ "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", x, &error_result, Policy()))
       return error_result;
- // Might conceivably permit df = +infinity and use normal distribution.
+
    RealType result;
- RealType basem1 = t * t / degrees_of_freedom;
- if(basem1 < 0.125)
- {
- result = exp(-boost::math::log1p(basem1, Policy()) * (1+degrees_of_freedom) / 2);
+
+ RealType limit = policies::get_epsilon<RealType, Policy>();
+ // Use policies so that if policy requests lower precision,
+ // then get the normal distribution approximation earlier.
+ limit = static_cast<RealType>(1) / limit; // 1/eps
+ // for 64-bit double 1/eps = 4503599627370496
+ if (degrees_of_freedom > limit)
+ { // Special case for really big degrees_of_freedom > 1 / eps (perhaps infinite?)
+ // - use normal distribution which is much faster and more accurate.
+ normal_distribution<RealType, Policy> n(0, 1);
+ result = pdf(n, x);
    }
    else
- {
- result = pow(1 / (1 + basem1), (degrees_of_freedom + 1) / 2);
+ { //
+ RealType basem1 = x * x / degrees_of_freedom;
+ if(basem1 < 0.125)
+ {
+ result = exp(-boost::math::log1p(basem1, Policy()) * (1+degrees_of_freedom) / 2);
+ }
+ else
+ {
+ result = pow(1 / (1 + basem1), (degrees_of_freedom + 1) / 2);
+ }
+ result /= sqrt(degrees_of_freedom) * boost::math::beta(degrees_of_freedom / 2, RealType(0.5f), Policy());
    }
- result /= sqrt(degrees_of_freedom) * boost::math::beta(degrees_of_freedom / 2, RealType(0.5f), Policy());
    return result;
 } // pdf
 
@@ -122,37 +140,54 @@
    {
      return 0.5;
    }
- //
- // Calculate probability of Student's t using the incomplete beta function.
- // probability = ibeta(degrees_of_freedom / 2, 1/2, degrees_of_freedom / (degrees_of_freedom + t*t))
- //
- // However when t is small compared to the degrees of freedom, that formula
- // suffers from rounding error, use the identity formula to work around
- // the problem:
- //
- // I[x](a,b) = 1 - I[1-x](b,a)
- //
- // and:
- //
- // x = df / (df + t^2)
- //
- // so:
- //
- // 1 - x = t^2 / (df + t^2)
- //
- RealType t2 = t * t;
- RealType probability;
- if(degrees_of_freedom > 2 * t2)
- {
- RealType z = t2 / (degrees_of_freedom + t2);
- probability = ibetac(static_cast<RealType>(0.5), degrees_of_freedom / 2, z, Policy()) / 2;
+
+ RealType limit = policies::get_epsilon<RealType, Policy>();
+ // Use policies so that if policy requests lower precision,
+ // then get the normal distribution approximation earlier.
+ limit = static_cast<RealType>(1) / limit; // 1/eps
+ // for 64-bit double 1/eps = 4503599627370496
+ if (degrees_of_freedom > limit)
+ { // Special case for really big degrees_of_freedom > 1 / eps (perhaps infinite?)
+ // - use normal distribution which is much faster and more accurate.
+ normal_distribution<RealType, Policy> n(0, 1);
+ RealType result = cdf(n, t);
+ return result;
    }
    else
- {
- RealType z = degrees_of_freedom / (degrees_of_freedom + t2);
- probability = ibeta(degrees_of_freedom / 2, static_cast<RealType>(0.5), z, Policy()) / 2;
- }
- return (t > 0 ? 1 - probability : probability);
+ { // normal case.
+
+ //
+ // Calculate probability of Student's t using the incomplete beta function.
+ // probability = ibeta(degrees_of_freedom / 2, 1/2, degrees_of_freedom / (degrees_of_freedom + t*t))
+ //
+ // However when t is small compared to the degrees of freedom, that formula
+ // suffers from rounding error, use the identity formula to work around
+ // the problem:
+ //
+ // I[x](a,b) = 1 - I[1-x](b,a)
+ //
+ // and:
+ //
+ // x = df / (df + t^2)
+ //
+ // so:
+ //
+ // 1 - x = t^2 / (df + t^2)
+ //
+ RealType t2 = t * t;
+ RealType probability;
+ if(degrees_of_freedom > 2 * t2)
+ {
+ RealType z = t2 / (degrees_of_freedom + t2);
+ probability = ibetac(static_cast<RealType>(0.5), degrees_of_freedom / 2, z, Policy()) / 2;
+ }
+ else
+ {
+ RealType z = degrees_of_freedom / (degrees_of_freedom + t2);
+ probability = ibeta(degrees_of_freedom / 2, static_cast<RealType>(0.5), z, Policy()) / 2;
+ }
+ return (t > 0 ? 1 - probability : probability);
+ }
 } // cdf
 
 template <class RealType, class Policy>
@@ -182,10 +217,9 @@
    if (probability == static_cast<RealType>(0.5))
      return 0;
    //
- // This next block is disabled in favour of a faster method than
- // incomplete beta inverse, code retained for future reference:
- //
 #if 0
+ // This next block is disabled in favour of a faster method than
+ // incomplete beta inverse, but code retained for future reference:
    //
    // Calculate quantile of Student's t using the incomplete beta function inverse:
    //
@@ -326,8 +360,7 @@
   // Revised for https://svn.boost.org/trac/boost/ticket/7177
   RealType df = dist.degrees_of_freedom();
   if (!(boost::math::isfinite)(df) || (df <= 2))
- { // Infinity or NaN
-
+ { // Infinity or NaN.
      policies::raise_domain_error<RealType>(
       "boost::math::variance(students_t_distribution<%1%> const&, %1%)",
       "variance is undefined for degrees of freedom <= 2, but got %1%.",


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