|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r79911 - in trunk/boost/math/distributions: . detail
From: pbristow_at_[hidden]
Date: 2012-08-07 11:53:55
Author: pbristow
Date: 2012-08-07 11:53:54 EDT (Tue, 07 Aug 2012)
New Revision: 79911
URL: http://svn.boost.org/trac/boost/changeset/79911
Log:
Major update to allow df == +infinity.
Text files modified:
trunk/boost/math/distributions/detail/common_error_handling.hpp | 1
trunk/boost/math/distributions/students_t.hpp | 215 ++++++++++++++++++++++++++-------------
2 files changed, 144 insertions(+), 72 deletions(-)
Modified: trunk/boost/math/distributions/detail/common_error_handling.hpp
==============================================================================
--- trunk/boost/math/distributions/detail/common_error_handling.hpp (original)
+++ trunk/boost/math/distributions/detail/common_error_handling.hpp 2012-08-07 11:53:54 EDT (Tue, 07 Aug 2012)
@@ -13,6 +13,7 @@
#include <boost/math/special_functions/fpclassify.hpp>
// using boost::math::isfinite;
+
namespace boost{ namespace math{ namespace detail
{
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-07 11:53:54 EDT (Tue, 07 Aug 2012)
@@ -1,5 +1,7 @@
// Copyright John Maddock 2006.
-// Copyright Paul A. Bristow 2006.
+// Copyright Paul A. Bristow 2006, 2012.
+// Copyright Thomas Mang 2012.
+
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -25,6 +27,20 @@
namespace boost{ namespace math{
+template <class RealType, class Policy>
+inline bool check_df(const char* function, RealType const& df, RealType* result, const Policy& pol)
+{ // df > 0 or +infinity are allowed.
+ // if((df <= 0) || (boost::math::isnan)(df)) // but use signbit to ensure catch -inf and -NaN.
+ if(((boost::math::signbit)(df) != 0) || (boost::math::isnan)(df))
+ { // is bad df <= 0 or NaN or -infinity.
+ *result = policies::raise_domain_error<RealType>(
+ function,
+ "Degrees of freedom argument is %1%, but must be > 0 !", df, pol);
+ return false;
+ }
+ return true;
+} // check_df
+
template <class RealType = double, class Policy = policies::policy<> >
class students_t_distribution
{
@@ -32,16 +48,16 @@
typedef RealType value_type;
typedef Policy policy_type;
- students_t_distribution(RealType i) : m_df(i)
+ students_t_distribution(RealType df) : df_(df)
{ // Constructor.
RealType result;
- detail::check_df(
- "boost::math::students_t_distribution<%1%>::students_t_distribution", m_df, &result, Policy());
+ check_df( // Checks that df > 0 or df == inf.
+ "boost::math::students_t_distribution<%1%>::students_t_distribution", df_, &result, Policy());
} // students_t_distribution
RealType degrees_of_freedom()const
{
- return m_df;
+ return df_;
}
// Parameter estimation:
@@ -53,18 +69,16 @@
RealType hint = 100);
private:
- //
// Data member:
- //
- RealType m_df; // degrees of freedom is a real number.
+ RealType df_; // degrees of freedom is a real number or +infinity.
};
-typedef students_t_distribution<double> students_t;
+typedef students_t_distribution<double> students_t; // Convenience typedef for double version.
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.
+ // NOT including infinity.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
}
@@ -81,81 +95,89 @@
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
+ BOOST_MATH_STD_USING // for ADL of std functions.
- RealType degrees_of_freedom = dist.degrees_of_freedom();
- // 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%)", x, &error_result, Policy()))
return error_result;
+ RealType df = dist.degrees_of_freedom();
+ if(false == check_df( // Check that df > 0 or == +infinity.
+ "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", df, &error_result, Policy()))
+ return error_result;
RealType result;
-
+ if (boost::math::isinf(x))
+ { // +infinity.
+ normal_distribution<RealType, Policy> n(0, 1);
+ RealType result = pdf(n, x);
+ return result;
+ }
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?)
+ if (df > limit)
+ { // Special case for really big degrees_of_freedom > 1 / eps
// - use normal distribution which is much faster and more accurate.
normal_distribution<RealType, Policy> n(0, 1);
result = pdf(n, x);
}
else
{ //
- RealType basem1 = x * x / degrees_of_freedom;
+ RealType basem1 = x * x / df;
if(basem1 < 0.125)
{
- result = exp(-boost::math::log1p(basem1, Policy()) * (1+degrees_of_freedom) / 2);
+ result = exp(-boost::math::log1p(basem1, Policy()) * (1+df) / 2);
}
else
{
- result = pow(1 / (1 + basem1), (degrees_of_freedom + 1) / 2);
+ result = pow(1 / (1 + basem1), (df + 1) / 2);
}
- result /= sqrt(degrees_of_freedom) * boost::math::beta(degrees_of_freedom / 2, RealType(0.5f), Policy());
+ result /= sqrt(df) * boost::math::beta(df / 2, RealType(0.5f), Policy());
}
return result;
} // pdf
template <class RealType, class Policy>
-inline RealType cdf(const students_t_distribution<RealType, Policy>& dist, const RealType& t)
+inline RealType cdf(const students_t_distribution<RealType, Policy>& dist, const RealType& x)
{
- RealType degrees_of_freedom = dist.degrees_of_freedom();
- // Error check:
RealType error_result;
- if(false == detail::check_df(
- "boost::math::cdf(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;
+ RealType df = dist.degrees_of_freedom();
+ // Error check:
- if (t == 0)
- {
- return 0.5;
- }
+ if(false == check_df( // Check that df > 0 or == +infinity.
+ "boost::math::cdf(const students_t_distribution<%1%>&, %1%)", df, &error_result, Policy()))
+ return error_result;
+ if (x == 0)
+ { // Special case with exact result.
+ return static_cast<RealType>(0.5);
+ }
+ if (boost::math::isinf(x))
+ { // +infinity.
+ normal_distribution<RealType, Policy> n(0, 1);
+ RealType result = cdf(n, x);
+ return result;
+ }
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)
+ if (df > 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);
+ RealType result = cdf(n, x);
return result;
}
else
- { // normal case.
-
+ { // normal df 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))
@@ -174,19 +196,19 @@
//
// 1 - x = t^2 / (df + t^2)
//
- RealType t2 = t * t;
+ RealType x2 = x * x;
RealType probability;
- if(degrees_of_freedom > 2 * t2)
+ if(df > 2 * x2)
{
- RealType z = t2 / (degrees_of_freedom + t2);
- probability = ibetac(static_cast<RealType>(0.5), degrees_of_freedom / 2, z, Policy()) / 2;
+ RealType z = x2 / (df + x2);
+ probability = ibetac(static_cast<RealType>(0.5), df / 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;
+ RealType z = df / (df + x2);
+ probability = ibeta(df / 2, static_cast<RealType>(0.5), z, Policy()) / 2;
}
- return (t > 0 ? 1 - probability : probability);
+ return (x > 0 ? 1 - probability : probability);
}
} // cdf
@@ -196,26 +218,23 @@
BOOST_MATH_STD_USING // for ADL of std functions
//
// Obtain parameters:
- //
- RealType degrees_of_freedom = dist.degrees_of_freedom();
RealType probability = p;
- //
+
// Check for domain errors:
- //
+ RealType df = dist.degrees_of_freedom();
static const char* function = "boost::math::quantile(const students_t_distribution<%1%>&, %1%)";
RealType error_result;
- if(false == (detail::check_df(
- function, degrees_of_freedom, &error_result, Policy())
+ if(false == (check_df( // Check that df > 0 or == +infinity.
+ function, df, &error_result, Policy())
&& detail::check_probability(function, probability, &error_result, Policy())))
return error_result;
-
// Special cases, regardless of degrees_of_freedom.
if (probability == 0)
return -policies::raise_overflow_error<RealType>(function, 0, Policy());
if (probability == 1)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
if (probability == static_cast<RealType>(0.5))
- return 0;
+ return 0; //
//
#if 0
// This next block is disabled in favour of a faster method than
@@ -245,7 +264,7 @@
// and a couple of epsilon at double precision and in the central
// region where most use cases will occur...
//
- return boost::math::detail::fast_students_t_quantile(degrees_of_freedom, probability, Policy());
+ return boost::math::detail::fast_students_t_quantile(df, probability, Policy());
} // quantile
template <class RealType, class Policy>
@@ -276,7 +295,9 @@
RealType operator()(const RealType& df)
{
if(df <= tools::min_value<RealType>())
+ { //
return 1;
+ }
students_t_distribution<RealType, Policy> t(df);
RealType qa = quantile(complement(t, alpha));
RealType qb = quantile(complement(t, beta));
@@ -329,13 +350,15 @@
template <class RealType, class Policy>
inline RealType mode(const students_t_distribution<RealType, Policy>& /*dist*/)
{
- return 0;
+ // Assume no checks on degrees of freedom are useful (unlike mean).
+ return 0; // Always zero by definition.
}
template <class RealType, class Policy>
inline RealType median(const students_t_distribution<RealType, Policy>& /*dist*/)
{
- return 0;
+ // Assume no checks on degrees of freedom are useful (unlike mean).
+ return 0; // Always zero by definition.
}
// See section 5.1 on moments at http://en.wikipedia.org/wiki/Student%27s_t-distribution
@@ -344,37 +367,53 @@
inline RealType mean(const students_t_distribution<RealType, Policy>& dist)
{ // Revised for https://svn.boost.org/trac/boost/ticket/7177
RealType df = dist.degrees_of_freedom();
- if((!(boost::math::isfinite)(df)) || (df <= 1) )// Undefined for moment <= 1
- {
+ if(((boost::math::isnan)(df)) || (df <= 1) )
+ { // mean is undefined for moment <= 1!
policies::raise_domain_error<RealType>(
"boost::math::mean(students_t_distribution<%1%> const&, %1%)",
"Mean is undefined for degrees of freedom < 1 but got %1%.", df, Policy());
return std::numeric_limits<RealType>::quiet_NaN();
}
return 0;
-}
+} // mean
template <class RealType, class Policy>
inline RealType variance(const students_t_distribution<RealType, Policy>& dist)
{ // http://en.wikipedia.org/wiki/Student%27s_t-distribution
// 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.
+ if ((boost::math::isnan)(df) || (df <= 2))
+ { // NaN or undefined for <= 2.
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%.",
df, Policy());
return std::numeric_limits<RealType>::quiet_NaN(); // Undefined.
}
- return df / (df - 2);
+ if (boost::math::isinf(df))
+ { // +infinity.
+ return 1;
+ }
+ 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 (df > limit)
+ { // Special case for really big degrees_of_freedom > 1 / eps.
+ return 1;
+ }
+ else
+ {
+ return df / (df - 2);
+ }
} // variance
template <class RealType, class Policy>
inline RealType skewness(const students_t_distribution<RealType, Policy>& dist)
{
RealType df = dist.degrees_of_freedom();
- if( (!(boost::math::isfinite)(df)) || (dist.degrees_of_freedom() <= 3))
+ if( ((boost::math::isnan)(df)) || (dist.degrees_of_freedom() <= 3))
{ // Undefined for moment k = 3.
policies::raise_domain_error<RealType>(
"boost::math::skewness(students_t_distribution<%1%> const&, %1%)",
@@ -382,14 +421,14 @@
dist.degrees_of_freedom(), Policy());
return std::numeric_limits<RealType>::quiet_NaN();
}
- return 0;
-}
+ return 0; // For all valid df, including infinity.
+} // skewness
template <class RealType, class Policy>
inline RealType kurtosis(const students_t_distribution<RealType, Policy>& dist)
{
RealType df = dist.degrees_of_freedom();
- if((!(boost::math::isfinite)(df)) || (df <= 4))
+ if(((boost::math::isnan)(df)) || (df <= 4))
{ // Undefined or infinity for moment k = 4.
policies::raise_domain_error<RealType>(
"boost::math::kurtosis(students_t_distribution<%1%> const&, %1%)",
@@ -397,9 +436,25 @@
df, Policy());
return std::numeric_limits<RealType>::quiet_NaN(); // Undefined.
}
- //return 3 * (df - 2) / (df - 4);
- return 6 / (df - 4) + 3;
-}
+ if (boost::math::isinf(df))
+ { // +infinity.
+ return 3;
+ }
+ 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 (df > limit)
+ { // Special case for really big degrees_of_freedom > 1 / eps.
+ return 3;
+ }
+ else
+ {
+ //return 3 * (df - 2) / (df - 4); re-arranged to
+ return 6 / (df - 4) + 3;
+ }
+} // kurtosis
template <class RealType, class Policy>
inline RealType kurtosis_excess(const students_t_distribution<RealType, Policy>& dist)
@@ -407,7 +462,7 @@
// see http://mathworld.wolfram.com/Kurtosis.html
RealType df = dist.degrees_of_freedom();
- if((!(boost::math::isfinite)(df)) || (df <= 4))
+ if(((boost::math::isnan)(df)) || (df <= 4))
{ // Undefined or infinity for moment k = 4.
policies::raise_domain_error<RealType>(
"boost::math::kurtosis_excess(students_t_distribution<%1%> const&, %1%)",
@@ -415,7 +470,23 @@
df, Policy());
return std::numeric_limits<RealType>::quiet_NaN(); // Undefined.
}
- return 6 / (df - 4);
+ if (boost::math::isinf(df))
+ { // +infinity.
+ return 0;
+ }
+ 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 (df > limit)
+ { // Special case for really big degrees_of_freedom > 1 / eps.
+ return 0;
+ }
+ else
+ {
+ return 6 / (df - 4);
+ }
}
} // namespace math
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