Imported existing code

This commit is contained in:
Hazim Gazov
2010-04-02 02:48:44 -03:00
parent 48fbc5ae91
commit 7a86d01598
13996 changed files with 2468699 additions and 0 deletions

View File

@@ -0,0 +1,719 @@
// Copyright John Maddock 2007.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <boost/math/tools/real_cast.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/roots.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <ostream>
#include <istream>
#include <boost/config/no_tr1/cmath.hpp>
#include <NTL/RR.h>
#ifndef BOOST_MATH_NTL_RR_HPP
#define BOOST_MATH_NTL_RR_HPP
namespace boost{ namespace math{
namespace ntl
{
class RR;
RR ldexp(RR r, int exp);
RR frexp(RR r, int* exp);
class RR
{
public:
// Constructors:
RR() {}
RR(const ::NTL::RR& c) : m_value(c){}
RR(char c)
{
m_value = c;
}
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
RR(wchar_t c)
{
m_value = c;
}
#endif
RR(unsigned char c)
{
m_value = c;
}
RR(signed char c)
{
m_value = c;
}
RR(unsigned short c)
{
m_value = c;
}
RR(short c)
{
m_value = c;
}
RR(unsigned int c)
{
assign_large_int(c);
}
RR(int c)
{
assign_large_int(c);
}
RR(unsigned long c)
{
assign_large_int(c);
}
RR(long c)
{
assign_large_int(c);
}
#ifdef BOOST_HAS_LONG_LONG
RR(boost::ulong_long_type c)
{
assign_large_int(c);
}
RR(boost::long_long_type c)
{
assign_large_int(c);
}
#endif
RR(float c)
{
m_value = c;
}
RR(double c)
{
m_value = c;
}
RR(long double c)
{
assign_large_real(c);
}
// Assignment:
RR& operator=(char c) { m_value = c; return *this; }
RR& operator=(unsigned char c) { m_value = c; return *this; }
RR& operator=(signed char c) { m_value = c; return *this; }
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
RR& operator=(wchar_t c) { m_value = c; return *this; }
#endif
RR& operator=(short c) { m_value = c; return *this; }
RR& operator=(unsigned short c) { m_value = c; return *this; }
RR& operator=(int c) { assign_large_int(c); return *this; }
RR& operator=(unsigned int c) { assign_large_int(c); return *this; }
RR& operator=(long c) { assign_large_int(c); return *this; }
RR& operator=(unsigned long c) { assign_large_int(c); return *this; }
#ifdef BOOST_HAS_LONG_LONG
RR& operator=(boost::long_long_type c) { assign_large_int(c); return *this; }
RR& operator=(boost::ulong_long_type c) { assign_large_int(c); return *this; }
#endif
RR& operator=(float c) { m_value = c; return *this; }
RR& operator=(double c) { m_value = c; return *this; }
RR& operator=(long double c) { assign_large_real(c); return *this; }
// Access:
NTL::RR& value(){ return m_value; }
NTL::RR const& value()const{ return m_value; }
// Member arithmetic:
RR& operator+=(const RR& other)
{ m_value += other.value(); return *this; }
RR& operator-=(const RR& other)
{ m_value -= other.value(); return *this; }
RR& operator*=(const RR& other)
{ m_value *= other.value(); return *this; }
RR& operator/=(const RR& other)
{ m_value /= other.value(); return *this; }
RR operator-()const
{ return -m_value; }
RR const& operator+()const
{ return *this; }
// RR compatibity:
const ::NTL::ZZ& mantissa() const
{ return m_value.mantissa(); }
long exponent() const
{ return m_value.exponent(); }
static void SetPrecision(long p)
{ ::NTL::RR::SetPrecision(p); }
static long precision()
{ return ::NTL::RR::precision(); }
static void SetOutputPrecision(long p)
{ ::NTL::RR::SetOutputPrecision(p); }
static long OutputPrecision()
{ return ::NTL::RR::OutputPrecision(); }
private:
::NTL::RR m_value;
template <class V>
void assign_large_real(const V& a)
{
using std::frexp;
using std::ldexp;
using std::floor;
if (a == 0) {
clear(m_value);
return;
}
if (a == 1) {
NTL::set(m_value);
return;
}
if (!(boost::math::isfinite)(a))
{
throw std::overflow_error("Cannot construct an instance of NTL::RR with an infinite value.");
}
int e;
long double f, term;
::NTL::RR t;
clear(m_value);
f = frexp(a, &e);
while(f)
{
// extract 30 bits from f:
f = ldexp(f, 30);
term = floor(f);
e -= 30;
conv(t.x, (int)term);
t.e = e;
m_value += t;
f -= term;
}
}
template <class V>
void assign_large_int(V a)
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4146)
#endif
clear(m_value);
int exp = 0;
NTL::RR t;
bool neg = a < V(0) ? true : false;
if(neg)
a = -a;
while(a)
{
t = static_cast<double>(a & 0xffff);
m_value += ldexp(RR(t), exp).value();
a >>= 16;
exp += 16;
}
if(neg)
m_value = -m_value;
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
}
};
// Non-member arithmetic:
inline RR operator+(const RR& a, const RR& b)
{
RR result(a);
result += b;
return result;
}
inline RR operator-(const RR& a, const RR& b)
{
RR result(a);
result -= b;
return result;
}
inline RR operator*(const RR& a, const RR& b)
{
RR result(a);
result *= b;
return result;
}
inline RR operator/(const RR& a, const RR& b)
{
RR result(a);
result /= b;
return result;
}
// Comparison:
inline bool operator == (const RR& a, const RR& b)
{ return a.value() == b.value() ? true : false; }
inline bool operator != (const RR& a, const RR& b)
{ return a.value() != b.value() ? true : false;}
inline bool operator < (const RR& a, const RR& b)
{ return a.value() < b.value() ? true : false; }
inline bool operator <= (const RR& a, const RR& b)
{ return a.value() <= b.value() ? true : false; }
inline bool operator > (const RR& a, const RR& b)
{ return a.value() > b.value() ? true : false; }
inline bool operator >= (const RR& a, const RR& b)
{ return a.value() >= b.value() ? true : false; }
#if 0
// Non-member mixed compare:
template <class T>
inline bool operator == (const T& a, const RR& b)
{
return a == b.value();
}
template <class T>
inline bool operator != (const T& a, const RR& b)
{
return a != b.value();
}
template <class T>
inline bool operator < (const T& a, const RR& b)
{
return a < b.value();
}
template <class T>
inline bool operator > (const T& a, const RR& b)
{
return a > b.value();
}
template <class T>
inline bool operator <= (const T& a, const RR& b)
{
return a <= b.value();
}
template <class T>
inline bool operator >= (const T& a, const RR& b)
{
return a >= b.value();
}
#endif // Non-member mixed compare:
// Non-member functions:
/*
inline RR acos(RR a)
{ return ::NTL::acos(a.value()); }
*/
inline RR cos(RR a)
{ return ::NTL::cos(a.value()); }
/*
inline RR asin(RR a)
{ return ::NTL::asin(a.value()); }
inline RR atan(RR a)
{ return ::NTL::atan(a.value()); }
inline RR atan2(RR a, RR b)
{ return ::NTL::atan2(a.value(), b.value()); }
*/
inline RR ceil(RR a)
{ return ::NTL::ceil(a.value()); }
/*
inline RR fmod(RR a, RR b)
{ return ::NTL::fmod(a.value(), b.value()); }
inline RR cosh(RR a)
{ return ::NTL::cosh(a.value()); }
*/
inline RR exp(RR a)
{ return ::NTL::exp(a.value()); }
inline RR fabs(RR a)
{ return ::NTL::fabs(a.value()); }
inline RR abs(RR a)
{ return ::NTL::abs(a.value()); }
inline RR floor(RR a)
{ return ::NTL::floor(a.value()); }
/*
inline RR modf(RR a, RR* ipart)
{
::NTL::RR ip;
RR result = modf(a.value(), &ip);
*ipart = ip;
return result;
}
inline RR frexp(RR a, int* expon)
{ return ::NTL::frexp(a.value(), expon); }
inline RR ldexp(RR a, int expon)
{ return ::NTL::ldexp(a.value(), expon); }
*/
inline RR log(RR a)
{ return ::NTL::log(a.value()); }
inline RR log10(RR a)
{ return ::NTL::log10(a.value()); }
/*
inline RR tan(RR a)
{ return ::NTL::tan(a.value()); }
*/
inline RR pow(RR a, RR b)
{ return ::NTL::pow(a.value(), b.value()); }
inline RR pow(RR a, int b)
{ return ::NTL::power(a.value(), b); }
inline RR sin(RR a)
{ return ::NTL::sin(a.value()); }
/*
inline RR sinh(RR a)
{ return ::NTL::sinh(a.value()); }
*/
inline RR sqrt(RR a)
{ return ::NTL::sqrt(a.value()); }
/*
inline RR tanh(RR a)
{ return ::NTL::tanh(a.value()); }
*/
inline RR pow(const RR& r, long l)
{
return ::NTL::power(r.value(), l);
}
inline RR tan(const RR& a)
{
return sin(a)/cos(a);
}
inline RR frexp(RR r, int* exp)
{
*exp = r.value().e;
r.value().e = 0;
while(r >= 1)
{
*exp += 1;
r.value().e -= 1;
}
while(r < 0.5)
{
*exp -= 1;
r.value().e += 1;
}
BOOST_ASSERT(r < 1);
BOOST_ASSERT(r >= 0.5);
return r;
}
inline RR ldexp(RR r, int exp)
{
r.value().e += exp;
return r;
}
// Streaming:
template <class charT, class traits>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const RR& a)
{
return os << a.value();
}
template <class charT, class traits>
inline std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, RR& a)
{
::NTL::RR v;
is >> v;
a = v;
return is;
}
} // namespace ntl
namespace tools
{
template<>
inline int digits<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
return ::NTL::RR::precision();
}
template <>
inline float real_cast<float, boost::math::ntl::RR>(boost::math::ntl::RR t)
{
double r;
conv(r, t.value());
return static_cast<float>(r);
}
template <>
inline double real_cast<double, boost::math::ntl::RR>(boost::math::ntl::RR t)
{
double r;
conv(r, t.value());
return r;
}
namespace detail{
template<class I>
void convert_to_long_result(NTL::RR const& r, I& result)
{
result = 0;
I last_result(0);
NTL::RR t(r);
double term;
do
{
conv(term, t);
last_result = result;
result += static_cast<I>(term);
t -= term;
}while(result != last_result);
}
}
template <>
inline long double real_cast<long double, boost::math::ntl::RR>(boost::math::ntl::RR t)
{
long double result(0);
detail::convert_to_long_result(t.value(), result);
return result;
}
template <>
inline boost::math::ntl::RR real_cast<boost::math::ntl::RR, boost::math::ntl::RR>(boost::math::ntl::RR t)
{
return t;
}
template <>
inline unsigned real_cast<unsigned, boost::math::ntl::RR>(boost::math::ntl::RR t)
{
unsigned result;
detail::convert_to_long_result(t.value(), result);
return result;
}
template <>
inline int real_cast<int, boost::math::ntl::RR>(boost::math::ntl::RR t)
{
unsigned result;
detail::convert_to_long_result(t.value(), result);
return result;
}
template <>
inline boost::math::ntl::RR max_value<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
static bool has_init = false;
static NTL::RR val;
if(!has_init)
{
val = 1;
val.e = NTL_OVFBND-20;
has_init = true;
}
return val;
}
template <>
inline boost::math::ntl::RR min_value<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
static bool has_init = false;
static NTL::RR val;
if(!has_init)
{
val = 1;
val.e = -NTL_OVFBND+20;
has_init = true;
}
return val;
}
template <>
inline boost::math::ntl::RR log_max_value<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
static bool has_init = false;
static NTL::RR val;
if(!has_init)
{
val = 1;
val.e = NTL_OVFBND-20;
val = log(val);
has_init = true;
}
return val;
}
template <>
inline boost::math::ntl::RR log_min_value<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
static bool has_init = false;
static NTL::RR val;
if(!has_init)
{
val = 1;
val.e = -NTL_OVFBND+20;
val = log(val);
has_init = true;
}
return val;
}
template <>
inline boost::math::ntl::RR epsilon<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
return ldexp(boost::math::ntl::RR(1), 1-boost::math::policies::digits<boost::math::ntl::RR, boost::math::policies::policy<> >());
}
} // namespace tools
//
// The number of digits precision in RR can vary with each call
// so we need to recalculate these with each call:
//
namespace constants{
template<> inline boost::math::ntl::RR pi<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
NTL::RR result;
ComputePi(result);
return result;
}
template<> inline boost::math::ntl::RR e<boost::math::ntl::RR>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(boost::math::ntl::RR))
{
NTL::RR result;
result = 1;
return exp(result);
}
} // namespace constants
namespace ntl{
//
// These are some fairly brain-dead versions of the math
// functions that NTL fails to provide.
//
//
// Inverse trig functions:
//
struct asin_root
{
asin_root(RR const& target) : t(target){}
std::tr1::tuple<RR, RR, RR> operator()(RR const& p)
{
RR f0 = sin(p);
RR f1 = cos(p);
RR f2 = -f0;
f0 -= t;
return std::tr1::make_tuple(f0, f1, f2);
}
private:
RR t;
};
inline RR asin(RR z)
{
double r;
conv(r, z.value());
return boost::math::tools::halley_iterate(
asin_root(z),
RR(std::asin(r)),
RR(-boost::math::constants::pi<RR>()/2),
RR(boost::math::constants::pi<RR>()/2),
NTL::RR::precision());
}
struct acos_root
{
acos_root(RR const& target) : t(target){}
std::tr1::tuple<RR, RR, RR> operator()(RR const& p)
{
RR f0 = cos(p);
RR f1 = -sin(p);
RR f2 = -f0;
f0 -= t;
return std::tr1::make_tuple(f0, f1, f2);
}
private:
RR t;
};
inline RR acos(RR z)
{
double r;
conv(r, z.value());
return boost::math::tools::halley_iterate(
acos_root(z),
RR(std::acos(r)),
RR(-boost::math::constants::pi<RR>()/2),
RR(boost::math::constants::pi<RR>()/2),
NTL::RR::precision());
}
struct atan_root
{
atan_root(RR const& target) : t(target){}
std::tr1::tuple<RR, RR, RR> operator()(RR const& p)
{
RR c = cos(p);
RR ta = tan(p);
RR f0 = ta - t;
RR f1 = 1 / (c * c);
RR f2 = 2 * ta / (c * c);
return std::tr1::make_tuple(f0, f1, f2);
}
private:
RR t;
};
inline RR atan(RR z)
{
double r;
conv(r, z.value());
return boost::math::tools::halley_iterate(
atan_root(z),
RR(std::atan(r)),
-boost::math::constants::pi<RR>()/2,
boost::math::constants::pi<RR>()/2,
NTL::RR::precision());
}
inline RR sinh(RR z)
{
return (expm1(z.value()) - expm1(-z.value())) / 2;
}
inline RR cosh(RR z)
{
return (exp(z) + exp(-z)) / 2;
}
inline RR tanh(RR z)
{
return sinh(z) / cosh(z);
}
inline RR fmod(RR x, RR y)
{
// This is a really crummy version of fmod, we rely on lots
// of digits to get us out of trouble...
RR factor = floor(x/y);
return x - factor * y;
}
template <class Policy>
inline int iround(RR const& x, const Policy& pol)
{
return tools::real_cast<int>(round(x, pol));
}
template <class Policy>
inline int itrunc(RR const& x, const Policy& pol)
{
return tools::real_cast<int>(trunc(x, pol));
}
} // namespace ntl
} // namespace math
} // namespace boost
#endif // BOOST_MATH_REAL_CONCEPT_HPP

View File

@@ -0,0 +1,16 @@
// Boost common_factor.hpp header file -------------------------------------//
// (C) Copyright Daryle Walker 2001-2002.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_MATH_COMMON_FACTOR_HPP
#define BOOST_MATH_COMMON_FACTOR_HPP
#include <boost/math/common_factor_ct.hpp>
#include <boost/math/common_factor_rt.hpp>
#endif // BOOST_MATH_COMMON_FACTOR_HPP

View File

@@ -0,0 +1,188 @@
// Boost common_factor_ct.hpp header file ----------------------------------//
// (C) Copyright Daryle Walker and Stephen Cleary 2001-2002.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_MATH_COMMON_FACTOR_CT_HPP
#define BOOST_MATH_COMMON_FACTOR_CT_HPP
#include <boost/math_fwd.hpp> // self include
#include <boost/config.hpp> // for BOOST_STATIC_CONSTANT, etc.
namespace boost
{
namespace math
{
// Implementation details --------------------------------------------------//
namespace detail
{
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// Build GCD with Euclid's recursive algorithm
template < unsigned long Value1, unsigned long Value2 >
struct static_gcd_helper_t
{
private:
BOOST_STATIC_CONSTANT( unsigned long, new_value1 = Value2 );
BOOST_STATIC_CONSTANT( unsigned long, new_value2 = Value1 % Value2 );
#ifndef __BORLANDC__
#define BOOST_DETAIL_GCD_HELPER_VAL(Value) static_cast<unsigned long>(Value)
#else
typedef static_gcd_helper_t self_type;
#define BOOST_DETAIL_GCD_HELPER_VAL(Value) (self_type:: Value )
#endif
typedef static_gcd_helper_t< BOOST_DETAIL_GCD_HELPER_VAL(new_value1),
BOOST_DETAIL_GCD_HELPER_VAL(new_value2) > next_step_type;
#undef BOOST_DETAIL_GCD_HELPER_VAL
public:
BOOST_STATIC_CONSTANT( unsigned long, value = next_step_type::value );
};
// Non-recursive case
template < unsigned long Value1 >
struct static_gcd_helper_t< Value1, 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = Value1 );
};
#else
// Use inner class template workaround from Peter Dimov
template < unsigned long Value1 >
struct static_gcd_helper2_t
{
template < unsigned long Value2 >
struct helper
{
BOOST_STATIC_CONSTANT( unsigned long, value
= static_gcd_helper2_t<Value2>::BOOST_NESTED_TEMPLATE
helper<Value1 % Value2>::value );
};
template < >
struct helper< 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = Value1 );
};
};
// Special case
template < >
struct static_gcd_helper2_t< 0UL >
{
template < unsigned long Value2 >
struct helper
{
BOOST_STATIC_CONSTANT( unsigned long, value = Value2 );
};
};
// Build the GCD from the above template(s)
template < unsigned long Value1, unsigned long Value2 >
struct static_gcd_helper_t
{
BOOST_STATIC_CONSTANT( unsigned long, value
= static_gcd_helper2_t<Value1>::BOOST_NESTED_TEMPLATE
helper<Value2>::value );
};
#endif
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
// Build the LCM from the GCD
template < unsigned long Value1, unsigned long Value2 >
struct static_lcm_helper_t
{
typedef static_gcd_helper_t<Value1, Value2> gcd_type;
BOOST_STATIC_CONSTANT( unsigned long, value = Value1 / gcd_type::value
* Value2 );
};
// Special case for zero-GCD values
template < >
struct static_lcm_helper_t< 0UL, 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = 0UL );
};
#else
// Adapt GCD's inner class template workaround for LCM
template < unsigned long Value1 >
struct static_lcm_helper2_t
{
template < unsigned long Value2 >
struct helper
{
typedef static_gcd_helper_t<Value1, Value2> gcd_type;
BOOST_STATIC_CONSTANT( unsigned long, value = Value1
/ gcd_type::value * Value2 );
};
template < >
struct helper< 0UL >
{
BOOST_STATIC_CONSTANT( unsigned long, value = 0UL );
};
};
// Special case
template < >
struct static_lcm_helper2_t< 0UL >
{
template < unsigned long Value2 >
struct helper
{
BOOST_STATIC_CONSTANT( unsigned long, value = 0UL );
};
};
// Build the LCM from the above template(s)
template < unsigned long Value1, unsigned long Value2 >
struct static_lcm_helper_t
{
BOOST_STATIC_CONSTANT( unsigned long, value
= static_lcm_helper2_t<Value1>::BOOST_NESTED_TEMPLATE
helper<Value2>::value );
};
#endif
} // namespace detail
// Compile-time greatest common divisor evaluator class declaration --------//
template < unsigned long Value1, unsigned long Value2 >
struct static_gcd
{
BOOST_STATIC_CONSTANT( unsigned long, value
= (detail::static_gcd_helper_t<Value1, Value2>::value) );
}; // boost::math::static_gcd
// Compile-time least common multiple evaluator class declaration ----------//
template < unsigned long Value1, unsigned long Value2 >
struct static_lcm
{
BOOST_STATIC_CONSTANT( unsigned long, value
= (detail::static_lcm_helper_t<Value1, Value2>::value) );
}; // boost::math::static_lcm
} // namespace math
} // namespace boost
#endif // BOOST_MATH_COMMON_FACTOR_CT_HPP

View File

@@ -0,0 +1,516 @@
// Boost common_factor_rt.hpp header file ----------------------------------//
// (C) Copyright Daryle Walker and Paul Moore 2001-2002. Permission to copy,
// use, modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided "as is"
// without express or implied warranty, and with no claim as to its suitability
// for any purpose.
// boostinspect:nolicense (don't complain about the lack of a Boost license)
// (Paul Moore hasn't been in contact for years, so there's no way to change the
// license.)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_MATH_COMMON_FACTOR_RT_HPP
#define BOOST_MATH_COMMON_FACTOR_RT_HPP
#include <boost/math_fwd.hpp> // self include
#include <boost/config.hpp> // for BOOST_NESTED_TEMPLATE, etc.
#include <boost/limits.hpp> // for std::numeric_limits
#include <boost/detail/workaround.hpp>
namespace boost
{
namespace math
{
// Forward declarations for function templates -----------------------------//
template < typename IntegerType >
IntegerType gcd( IntegerType const &a, IntegerType const &b );
template < typename IntegerType >
IntegerType lcm( IntegerType const &a, IntegerType const &b );
// Greatest common divisor evaluator class declaration ---------------------//
template < typename IntegerType >
class gcd_evaluator
{
public:
// Types
typedef IntegerType result_type, first_argument_type, second_argument_type;
// Function object interface
result_type operator ()( first_argument_type const &a,
second_argument_type const &b ) const;
}; // boost::math::gcd_evaluator
// Least common multiple evaluator class declaration -----------------------//
template < typename IntegerType >
class lcm_evaluator
{
public:
// Types
typedef IntegerType result_type, first_argument_type, second_argument_type;
// Function object interface
result_type operator ()( first_argument_type const &a,
second_argument_type const &b ) const;
}; // boost::math::lcm_evaluator
// Implementation details --------------------------------------------------//
namespace detail
{
// Greatest common divisor for rings (including unsigned integers)
template < typename RingType >
RingType
gcd_euclidean
(
RingType a,
RingType b
)
{
// Avoid repeated construction
#ifndef __BORLANDC__
RingType const zero = static_cast<RingType>( 0 );
#else
RingType zero = static_cast<RingType>( 0 );
#endif
// Reduce by GCD-remainder property [GCD(a,b) == GCD(b,a MOD b)]
while ( true )
{
if ( a == zero )
return b;
b %= a;
if ( b == zero )
return a;
a %= b;
}
}
// Greatest common divisor for (signed) integers
template < typename IntegerType >
inline
IntegerType
gcd_integer
(
IntegerType const & a,
IntegerType const & b
)
{
// Avoid repeated construction
IntegerType const zero = static_cast<IntegerType>( 0 );
IntegerType const result = gcd_euclidean( a, b );
return ( result < zero ) ? -result : result;
}
// Greatest common divisor for unsigned binary integers
template < typename BuiltInUnsigned >
BuiltInUnsigned
gcd_binary
(
BuiltInUnsigned u,
BuiltInUnsigned v
)
{
if ( u && v )
{
// Shift out common factors of 2
unsigned shifts = 0;
while ( !(u & 1u) && !(v & 1u) )
{
++shifts;
u >>= 1;
v >>= 1;
}
// Start with the still-even one, if any
BuiltInUnsigned r[] = { u, v };
unsigned which = static_cast<bool>( u & 1u );
// Whittle down the values via their differences
do
{
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
while ( !(r[ which ] & 1u) )
{
r[ which ] = (r[which] >> 1);
}
#else
// Remove factors of two from the even one
while ( !(r[ which ] & 1u) )
{
r[ which ] >>= 1;
}
#endif
// Replace the larger of the two with their difference
if ( r[!which] > r[which] )
{
which ^= 1u;
}
r[ which ] -= r[ !which ];
}
while ( r[which] );
// Shift-in the common factor of 2 to the residues' GCD
return r[ !which ] << shifts;
}
else
{
// At least one input is zero, return the other
// (adding since zero is the additive identity)
// or zero if both are zero.
return u + v;
}
}
// Least common multiple for rings (including unsigned integers)
template < typename RingType >
inline
RingType
lcm_euclidean
(
RingType const & a,
RingType const & b
)
{
RingType const zero = static_cast<RingType>( 0 );
RingType const temp = gcd_euclidean( a, b );
return ( temp != zero ) ? ( a / temp * b ) : zero;
}
// Least common multiple for (signed) integers
template < typename IntegerType >
inline
IntegerType
lcm_integer
(
IntegerType const & a,
IntegerType const & b
)
{
// Avoid repeated construction
IntegerType const zero = static_cast<IntegerType>( 0 );
IntegerType const result = lcm_euclidean( a, b );
return ( result < zero ) ? -result : result;
}
// Function objects to find the best way of computing GCD or LCM
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template < typename T, bool IsSpecialized, bool IsSigned >
struct gcd_optimal_evaluator_helper_t
{
T operator ()( T const &a, T const &b )
{
return gcd_euclidean( a, b );
}
};
template < typename T >
struct gcd_optimal_evaluator_helper_t< T, true, true >
{
T operator ()( T const &a, T const &b )
{
return gcd_integer( a, b );
}
};
#else
template < bool IsSpecialized, bool IsSigned >
struct gcd_optimal_evaluator_helper2_t
{
template < typename T >
struct helper
{
T operator ()( T const &a, T const &b )
{
return gcd_euclidean( a, b );
}
};
};
template < >
struct gcd_optimal_evaluator_helper2_t< true, true >
{
template < typename T >
struct helper
{
T operator ()( T const &a, T const &b )
{
return gcd_integer( a, b );
}
};
};
template < typename T, bool IsSpecialized, bool IsSigned >
struct gcd_optimal_evaluator_helper_t
: gcd_optimal_evaluator_helper2_t<IsSpecialized, IsSigned>
::BOOST_NESTED_TEMPLATE helper<T>
{
};
#endif
template < typename T >
struct gcd_optimal_evaluator
{
T operator ()( T const &a, T const &b )
{
typedef ::std::numeric_limits<T> limits_type;
typedef gcd_optimal_evaluator_helper_t<T,
limits_type::is_specialized, limits_type::is_signed> helper_type;
helper_type solver;
return solver( a, b );
}
};
#else // BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
template < typename T >
struct gcd_optimal_evaluator
{
T operator ()( T const &a, T const &b )
{
return gcd_integer( a, b );
}
};
#endif
// Specialize for the built-in integers
#define BOOST_PRIVATE_GCD_UF( Ut ) \
template < > struct gcd_optimal_evaluator<Ut> \
{ Ut operator ()( Ut a, Ut b ) const { return gcd_binary( a, b ); } }
BOOST_PRIVATE_GCD_UF( unsigned char );
BOOST_PRIVATE_GCD_UF( unsigned short );
BOOST_PRIVATE_GCD_UF( unsigned );
BOOST_PRIVATE_GCD_UF( unsigned long );
#ifdef BOOST_HAS_LONG_LONG
BOOST_PRIVATE_GCD_UF( boost::ulong_long_type );
#elif defined(BOOST_HAS_MS_INT64)
BOOST_PRIVATE_GCD_UF( unsigned __int64 );
#endif
#undef BOOST_PRIVATE_GCD_UF
#define BOOST_PRIVATE_GCD_SF( St, Ut ) \
template < > struct gcd_optimal_evaluator<St> \
{ St operator ()( St a, St b ) const { Ut const a_abs = \
static_cast<Ut>( a < 0 ? -a : +a ), b_abs = static_cast<Ut>( \
b < 0 ? -b : +b ); return static_cast<St>( \
gcd_optimal_evaluator<Ut>()(a_abs, b_abs) ); } }
BOOST_PRIVATE_GCD_SF( signed char, unsigned char );
BOOST_PRIVATE_GCD_SF( short, unsigned short );
BOOST_PRIVATE_GCD_SF( int, unsigned );
BOOST_PRIVATE_GCD_SF( long, unsigned long );
BOOST_PRIVATE_GCD_SF( char, unsigned char ); // should work even if unsigned
#ifdef BOOST_HAS_LONG_LONG
BOOST_PRIVATE_GCD_SF( boost::long_long_type, boost::ulong_long_type );
#elif defined(BOOST_HAS_MS_INT64)
BOOST_PRIVATE_GCD_SF( __int64, unsigned __int64 );
#endif
#undef BOOST_PRIVATE_GCD_SF
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION
template < typename T, bool IsSpecialized, bool IsSigned >
struct lcm_optimal_evaluator_helper_t
{
T operator ()( T const &a, T const &b )
{
return lcm_euclidean( a, b );
}
};
template < typename T >
struct lcm_optimal_evaluator_helper_t< T, true, true >
{
T operator ()( T const &a, T const &b )
{
return lcm_integer( a, b );
}
};
#else
template < bool IsSpecialized, bool IsSigned >
struct lcm_optimal_evaluator_helper2_t
{
template < typename T >
struct helper
{
T operator ()( T const &a, T const &b )
{
return lcm_euclidean( a, b );
}
};
};
template < >
struct lcm_optimal_evaluator_helper2_t< true, true >
{
template < typename T >
struct helper
{
T operator ()( T const &a, T const &b )
{
return lcm_integer( a, b );
}
};
};
template < typename T, bool IsSpecialized, bool IsSigned >
struct lcm_optimal_evaluator_helper_t
: lcm_optimal_evaluator_helper2_t<IsSpecialized, IsSigned>
::BOOST_NESTED_TEMPLATE helper<T>
{
};
#endif
template < typename T >
struct lcm_optimal_evaluator
{
T operator ()( T const &a, T const &b )
{
typedef ::std::numeric_limits<T> limits_type;
typedef lcm_optimal_evaluator_helper_t<T,
limits_type::is_specialized, limits_type::is_signed> helper_type;
helper_type solver;
return solver( a, b );
}
};
#else // BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
template < typename T >
struct lcm_optimal_evaluator
{
T operator ()( T const &a, T const &b )
{
return lcm_integer( a, b );
}
};
#endif
// Functions to find the GCD or LCM in the best way
template < typename T >
inline
T
gcd_optimal
(
T const & a,
T const & b
)
{
gcd_optimal_evaluator<T> solver;
return solver( a, b );
}
template < typename T >
inline
T
lcm_optimal
(
T const & a,
T const & b
)
{
lcm_optimal_evaluator<T> solver;
return solver( a, b );
}
} // namespace detail
// Greatest common divisor evaluator member function definition ------------//
template < typename IntegerType >
inline
typename gcd_evaluator<IntegerType>::result_type
gcd_evaluator<IntegerType>::operator ()
(
first_argument_type const & a,
second_argument_type const & b
) const
{
return detail::gcd_optimal( a, b );
}
// Least common multiple evaluator member function definition --------------//
template < typename IntegerType >
inline
typename lcm_evaluator<IntegerType>::result_type
lcm_evaluator<IntegerType>::operator ()
(
first_argument_type const & a,
second_argument_type const & b
) const
{
return detail::lcm_optimal( a, b );
}
// Greatest common divisor and least common multiple function definitions --//
template < typename IntegerType >
inline
IntegerType
gcd
(
IntegerType const & a,
IntegerType const & b
)
{
gcd_evaluator<IntegerType> solver;
return solver( a, b );
}
template < typename IntegerType >
inline
IntegerType
lcm
(
IntegerType const & a,
IntegerType const & b
)
{
lcm_evaluator<IntegerType> solver;
return solver( a, b );
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_COMMON_FACTOR_RT_HPP

View File

@@ -0,0 +1,32 @@
// (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_COMPLEX_INCLUDED
#define BOOST_MATH_COMPLEX_INCLUDED
#ifndef BOOST_MATH_COMPLEX_ASIN_INCLUDED
# include <boost/math/complex/asin.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ASINH_INCLUDED
# include <boost/math/complex/asinh.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ACOS_INCLUDED
# include <boost/math/complex/acos.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ACOSH_INCLUDED
# include <boost/math/complex/acosh.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ATAN_INCLUDED
# include <boost/math/complex/atan.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ATANH_INCLUDED
# include <boost/math/complex/atanh.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_FABS_INCLUDED
# include <boost/math/complex/fabs.hpp>
#endif
#endif // BOOST_MATH_COMPLEX_INCLUDED

View File

@@ -0,0 +1,235 @@
// (C) Copyright John Maddock 2005.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_COMPLEX_ACOS_INCLUDED
#define BOOST_MATH_COMPLEX_ACOS_INCLUDED
#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
# include <boost/math/complex/details.hpp>
#endif
#ifndef BOOST_MATH_LOG1P_INCLUDED
# include <boost/math/special_functions/log1p.hpp>
#endif
#include <boost/assert.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::sqrt; using ::fabs; using ::acos; using ::asin; using ::atan; using ::atan2; }
#endif
namespace boost{ namespace math{
template<class T>
std::complex<T> acos(const std::complex<T>& z)
{
//
// This implementation is a transcription of the pseudo-code in:
//
// "Implementing the Complex Arcsine and Arccosine Functions using Exception Handling."
// T E Hull, Thomas F Fairgrieve and Ping Tak Peter Tang.
// ACM Transactions on Mathematical Software, Vol 23, No 3, Sept 1997.
//
//
// These static constants should really be in a maths constants library:
//
static const T one = static_cast<T>(1);
//static const T two = static_cast<T>(2);
static const T half = static_cast<T>(0.5L);
static const T a_crossover = static_cast<T>(1.5L);
static const T b_crossover = static_cast<T>(0.6417L);
static const T s_pi = static_cast<T>(3.141592653589793238462643383279502884197L);
static const T half_pi = static_cast<T>(1.57079632679489661923132169163975144L);
static const T log_two = static_cast<T>(0.69314718055994530941723212145817657L);
static const T quarter_pi = static_cast<T>(0.78539816339744830961566084581987572L);
//
// Get real and imaginary parts, discard the signs as we can
// figure out the sign of the result later:
//
T x = std::fabs(z.real());
T y = std::fabs(z.imag());
T real, imag; // these hold our result
//
// Handle special cases specified by the C99 standard,
// many of these special cases aren't really needed here,
// but doing it this way prevents overflow/underflow arithmetic
// in the main body of the logic, which may trip up some machines:
//
if(std::numeric_limits<T>::has_infinity && (x == std::numeric_limits<T>::infinity()))
{
if(y == std::numeric_limits<T>::infinity())
{
real = quarter_pi;
imag = std::numeric_limits<T>::infinity();
}
else if(detail::test_is_nan(y))
{
return std::complex<T>(y, -std::numeric_limits<T>::infinity());
}
else
{
// y is not infinity or nan:
real = 0;
imag = std::numeric_limits<T>::infinity();
}
}
else if(detail::test_is_nan(x))
{
if(y == std::numeric_limits<T>::infinity())
return std::complex<T>(x, (z.imag() < 0) ? std::numeric_limits<T>::infinity() : -std::numeric_limits<T>::infinity());
return std::complex<T>(x, x);
}
else if(std::numeric_limits<T>::has_infinity && (y == std::numeric_limits<T>::infinity()))
{
real = half_pi;
imag = std::numeric_limits<T>::infinity();
}
else if(detail::test_is_nan(y))
{
return std::complex<T>((x == 0) ? half_pi : y, y);
}
else
{
//
// What follows is the regular Hull et al code,
// begin with the special case for real numbers:
//
if((y == 0) && (x <= one))
return std::complex<T>((x == 0) ? half_pi : std::acos(z.real()));
//
// Figure out if our input is within the "safe area" identified by Hull et al.
// This would be more efficient with portable floating point exception handling;
// fortunately the quantities M and u identified by Hull et al (figure 3),
// match with the max and min methods of numeric_limits<T>.
//
T safe_max = detail::safe_max(static_cast<T>(8));
T safe_min = detail::safe_min(static_cast<T>(4));
T xp1 = one + x;
T xm1 = x - one;
if((x < safe_max) && (x > safe_min) && (y < safe_max) && (y > safe_min))
{
T yy = y * y;
T r = std::sqrt(xp1*xp1 + yy);
T s = std::sqrt(xm1*xm1 + yy);
T a = half * (r + s);
T b = x / a;
if(b <= b_crossover)
{
real = std::acos(b);
}
else
{
T apx = a + x;
if(x <= one)
{
real = std::atan(std::sqrt(half * apx * (yy /(r + xp1) + (s-xm1)))/x);
}
else
{
real = std::atan((y * std::sqrt(half * (apx/(r + xp1) + apx/(s+xm1))))/x);
}
}
if(a <= a_crossover)
{
T am1;
if(x < one)
{
am1 = half * (yy/(r + xp1) + yy/(s - xm1));
}
else
{
am1 = half * (yy/(r + xp1) + (s + xm1));
}
imag = boost::math::log1p(am1 + std::sqrt(am1 * (a + one)));
}
else
{
imag = std::log(a + std::sqrt(a*a - one));
}
}
else
{
//
// This is the Hull et al exception handling code from Fig 6 of their paper:
//
if(y <= (std::numeric_limits<T>::epsilon() * std::fabs(xm1)))
{
if(x < one)
{
real = std::acos(x);
imag = y / std::sqrt(xp1*(one-x));
}
else
{
real = 0;
if(((std::numeric_limits<T>::max)() / xp1) > xm1)
{
// xp1 * xm1 won't overflow:
imag = boost::math::log1p(xm1 + std::sqrt(xp1*xm1));
}
else
{
imag = log_two + std::log(x);
}
}
}
else if(y <= safe_min)
{
// There is an assumption in Hull et al's analysis that
// if we get here then x == 1. This is true for all "good"
// machines where :
//
// E^2 > 8*sqrt(u); with:
//
// E = std::numeric_limits<T>::epsilon()
// u = (std::numeric_limits<T>::min)()
//
// Hull et al provide alternative code for "bad" machines
// but we have no way to test that here, so for now just assert
// on the assumption:
//
BOOST_ASSERT(x == 1);
real = std::sqrt(y);
imag = std::sqrt(y);
}
else if(std::numeric_limits<T>::epsilon() * y - one >= x)
{
real = half_pi;
imag = log_two + std::log(y);
}
else if(x > one)
{
real = std::atan(y/x);
T xoy = x/y;
imag = log_two + std::log(y) + half * boost::math::log1p(xoy*xoy);
}
else
{
real = half_pi;
T a = std::sqrt(one + y*y);
imag = half * boost::math::log1p(static_cast<T>(2)*y*(y+a));
}
}
}
//
// Finish off by working out the sign of the result:
//
if(z.real() < 0)
real = s_pi - real;
if(z.imag() > 0)
imag = -imag;
return std::complex<T>(real, imag);
}
} } // namespaces
#endif // BOOST_MATH_COMPLEX_ACOS_INCLUDED

View File

@@ -0,0 +1,34 @@
// (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_COMPLEX_ACOSH_INCLUDED
#define BOOST_MATH_COMPLEX_ACOSH_INCLUDED
#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
# include <boost/math/complex/details.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ATANH_INCLUDED
# include <boost/math/complex/acos.hpp>
#endif
namespace boost{ namespace math{
template<class T>
inline std::complex<T> acosh(const std::complex<T>& z)
{
//
// We use the relation acosh(z) = +-i acos(z)
// Choosing the sign of multiplier to give real(acosh(z)) >= 0
// as well as compatibility with C99.
//
std::complex<T> result = boost::math::acos(z);
if(!detail::test_is_nan(result.imag()) && result.imag() <= 0)
return detail::mult_i(result);
return detail::mult_minus_i(result);
}
} } // namespaces
#endif // BOOST_MATH_COMPLEX_ACOSH_INCLUDED

View File

@@ -0,0 +1,245 @@
// (C) Copyright John Maddock 2005.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_COMPLEX_ASIN_INCLUDED
#define BOOST_MATH_COMPLEX_ASIN_INCLUDED
#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
# include <boost/math/complex/details.hpp>
#endif
#ifndef BOOST_MATH_LOG1P_INCLUDED
# include <boost/math/special_functions/log1p.hpp>
#endif
#include <boost/assert.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::sqrt; using ::fabs; using ::acos; using ::asin; using ::atan; using ::atan2; }
#endif
namespace boost{ namespace math{
template<class T>
inline std::complex<T> asin(const std::complex<T>& z)
{
//
// This implementation is a transcription of the pseudo-code in:
//
// "Implementing the complex Arcsine and Arccosine Functions using Exception Handling."
// T E Hull, Thomas F Fairgrieve and Ping Tak Peter Tang.
// ACM Transactions on Mathematical Software, Vol 23, No 3, Sept 1997.
//
//
// These static constants should really be in a maths constants library:
//
static const T one = static_cast<T>(1);
//static const T two = static_cast<T>(2);
static const T half = static_cast<T>(0.5L);
static const T a_crossover = static_cast<T>(1.5L);
static const T b_crossover = static_cast<T>(0.6417L);
//static const T pi = static_cast<T>(3.141592653589793238462643383279502884197L);
static const T half_pi = static_cast<T>(1.57079632679489661923132169163975144L);
static const T log_two = static_cast<T>(0.69314718055994530941723212145817657L);
static const T quarter_pi = static_cast<T>(0.78539816339744830961566084581987572L);
//
// Get real and imaginary parts, discard the signs as we can
// figure out the sign of the result later:
//
T x = std::fabs(z.real());
T y = std::fabs(z.imag());
T real, imag; // our results
//
// Begin by handling the special cases for infinities and nan's
// specified in C99, most of this is handled by the regular logic
// below, but handling it as a special case prevents overflow/underflow
// arithmetic which may trip up some machines:
//
if(detail::test_is_nan(x))
{
if(detail::test_is_nan(y))
return std::complex<T>(x, x);
if(std::numeric_limits<T>::has_infinity && (y == std::numeric_limits<T>::infinity()))
{
real = x;
imag = std::numeric_limits<T>::infinity();
}
else
return std::complex<T>(x, x);
}
else if(detail::test_is_nan(y))
{
if(x == 0)
{
real = 0;
imag = y;
}
else if(std::numeric_limits<T>::has_infinity && (x == std::numeric_limits<T>::infinity()))
{
real = y;
imag = std::numeric_limits<T>::infinity();
}
else
return std::complex<T>(y, y);
}
else if(std::numeric_limits<T>::has_infinity && (x == std::numeric_limits<T>::infinity()))
{
if(y == std::numeric_limits<T>::infinity())
{
real = quarter_pi;
imag = std::numeric_limits<T>::infinity();
}
else
{
real = half_pi;
imag = std::numeric_limits<T>::infinity();
}
}
else if(std::numeric_limits<T>::has_infinity && (y == std::numeric_limits<T>::infinity()))
{
real = 0;
imag = std::numeric_limits<T>::infinity();
}
else
{
//
// special case for real numbers:
//
if((y == 0) && (x <= one))
return std::complex<T>(std::asin(z.real()));
//
// Figure out if our input is within the "safe area" identified by Hull et al.
// This would be more efficient with portable floating point exception handling;
// fortunately the quantities M and u identified by Hull et al (figure 3),
// match with the max and min methods of numeric_limits<T>.
//
T safe_max = detail::safe_max(static_cast<T>(8));
T safe_min = detail::safe_min(static_cast<T>(4));
T xp1 = one + x;
T xm1 = x - one;
if((x < safe_max) && (x > safe_min) && (y < safe_max) && (y > safe_min))
{
T yy = y * y;
T r = std::sqrt(xp1*xp1 + yy);
T s = std::sqrt(xm1*xm1 + yy);
T a = half * (r + s);
T b = x / a;
if(b <= b_crossover)
{
real = std::asin(b);
}
else
{
T apx = a + x;
if(x <= one)
{
real = std::atan(x/std::sqrt(half * apx * (yy /(r + xp1) + (s-xm1))));
}
else
{
real = std::atan(x/(y * std::sqrt(half * (apx/(r + xp1) + apx/(s+xm1)))));
}
}
if(a <= a_crossover)
{
T am1;
if(x < one)
{
am1 = half * (yy/(r + xp1) + yy/(s - xm1));
}
else
{
am1 = half * (yy/(r + xp1) + (s + xm1));
}
imag = boost::math::log1p(am1 + std::sqrt(am1 * (a + one)));
}
else
{
imag = std::log(a + std::sqrt(a*a - one));
}
}
else
{
//
// This is the Hull et al exception handling code from Fig 3 of their paper:
//
if(y <= (std::numeric_limits<T>::epsilon() * std::fabs(xm1)))
{
if(x < one)
{
real = std::asin(x);
imag = y / std::sqrt(xp1*xm1);
}
else
{
real = half_pi;
if(((std::numeric_limits<T>::max)() / xp1) > xm1)
{
// xp1 * xm1 won't overflow:
imag = boost::math::log1p(xm1 + std::sqrt(xp1*xm1));
}
else
{
imag = log_two + std::log(x);
}
}
}
else if(y <= safe_min)
{
// There is an assumption in Hull et al's analysis that
// if we get here then x == 1. This is true for all "good"
// machines where :
//
// E^2 > 8*sqrt(u); with:
//
// E = std::numeric_limits<T>::epsilon()
// u = (std::numeric_limits<T>::min)()
//
// Hull et al provide alternative code for "bad" machines
// but we have no way to test that here, so for now just assert
// on the assumption:
//
BOOST_ASSERT(x == 1);
real = half_pi - std::sqrt(y);
imag = std::sqrt(y);
}
else if(std::numeric_limits<T>::epsilon() * y - one >= x)
{
real = x/y; // This can underflow!
imag = log_two + std::log(y);
}
else if(x > one)
{
real = std::atan(x/y);
T xoy = x/y;
imag = log_two + std::log(y) + half * boost::math::log1p(xoy*xoy);
}
else
{
T a = std::sqrt(one + y*y);
real = x/a; // This can underflow!
imag = half * boost::math::log1p(static_cast<T>(2)*y*(y+a));
}
}
}
//
// Finish off by working out the sign of the result:
//
if(z.real() < 0)
real = -real;
if(z.imag() < 0)
imag = -imag;
return std::complex<T>(real, imag);
}
} } // namespaces
#endif // BOOST_MATH_COMPLEX_ASIN_INCLUDED

View File

@@ -0,0 +1,32 @@
// (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_COMPLEX_ASINH_INCLUDED
#define BOOST_MATH_COMPLEX_ASINH_INCLUDED
#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
# include <boost/math/complex/details.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ASIN_INCLUDED
# include <boost/math/complex/asin.hpp>
#endif
namespace boost{ namespace math{
template<class T>
inline std::complex<T> asinh(const std::complex<T>& x)
{
//
// We use asinh(z) = i asin(-i z);
// Note that C99 defines this the other way around (which is
// to say asin is specified in terms of asinh), this is consistent
// with C99 though:
//
return ::boost::math::detail::mult_i(::boost::math::asin(::boost::math::detail::mult_minus_i(x)));
}
} } // namespaces
#endif // BOOST_MATH_COMPLEX_ASINH_INCLUDED

View File

@@ -0,0 +1,36 @@
// (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_COMPLEX_ATAN_INCLUDED
#define BOOST_MATH_COMPLEX_ATAN_INCLUDED
#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
# include <boost/math/complex/details.hpp>
#endif
#ifndef BOOST_MATH_COMPLEX_ATANH_INCLUDED
# include <boost/math/complex/atanh.hpp>
#endif
namespace boost{ namespace math{
template<class T>
std::complex<T> atan(const std::complex<T>& x)
{
//
// We're using the C99 definition here; atan(z) = -i atanh(iz):
//
if(x.real() == 0)
{
if(x.imag() == 1)
return std::complex<T>(0, std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : static_cast<T>(HUGE_VAL));
if(x.imag() == -1)
return std::complex<T>(0, std::numeric_limits<T>::has_infinity ? -std::numeric_limits<T>::infinity() : -static_cast<T>(HUGE_VAL));
}
return ::boost::math::detail::mult_minus_i(::boost::math::atanh(::boost::math::detail::mult_i(x)));
}
} } // namespaces
#endif // BOOST_MATH_COMPLEX_ATAN_INCLUDED

View File

@@ -0,0 +1,245 @@
// (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_COMPLEX_ATANH_INCLUDED
#define BOOST_MATH_COMPLEX_ATANH_INCLUDED
#ifndef BOOST_MATH_COMPLEX_DETAILS_INCLUDED
# include <boost/math/complex/details.hpp>
#endif
#ifndef BOOST_MATH_LOG1P_INCLUDED
# include <boost/math/special_functions/log1p.hpp>
#endif
#include <boost/assert.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::sqrt; using ::fabs; using ::acos; using ::asin; using ::atan; using ::atan2; }
#endif
namespace boost{ namespace math{
template<class T>
std::complex<T> atanh(const std::complex<T>& z)
{
//
// References:
//
// Eric W. Weisstein. "Inverse Hyperbolic Tangent."
// From MathWorld--A Wolfram Web Resource.
// http://mathworld.wolfram.com/InverseHyperbolicTangent.html
//
// Also: The Wolfram Functions Site,
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/
//
// Also "Abramowitz and Stegun. Handbook of Mathematical Functions."
// at : http://jove.prohosting.com/~skripty/toc.htm
//
static const T half_pi = static_cast<T>(1.57079632679489661923132169163975144L);
static const T pi = static_cast<T>(3.141592653589793238462643383279502884197L);
static const T one = static_cast<T>(1.0L);
static const T two = static_cast<T>(2.0L);
static const T four = static_cast<T>(4.0L);
static const T zero = static_cast<T>(0);
static const T a_crossover = static_cast<T>(0.3L);
T x = std::fabs(z.real());
T y = std::fabs(z.imag());
T real, imag; // our results
T safe_upper = detail::safe_max(two);
T safe_lower = detail::safe_min(static_cast<T>(2));
//
// Begin by handling the special cases specified in C99:
//
if(detail::test_is_nan(x))
{
if(detail::test_is_nan(y))
return std::complex<T>(x, x);
else if(std::numeric_limits<T>::has_infinity && (y == std::numeric_limits<T>::infinity()))
return std::complex<T>(0, ((z.imag() < 0) ? -half_pi : half_pi));
else
return std::complex<T>(x, x);
}
else if(detail::test_is_nan(y))
{
if(x == 0)
return std::complex<T>(x, y);
if(std::numeric_limits<T>::has_infinity && (x == std::numeric_limits<T>::infinity()))
return std::complex<T>(0, y);
else
return std::complex<T>(y, y);
}
else if((x > safe_lower) && (x < safe_upper) && (y > safe_lower) && (y < safe_upper))
{
T xx = x*x;
T yy = y*y;
T x2 = x * two;
///
// The real part is given by:
//
// real(atanh(z)) == log((1 + x^2 + y^2 + 2x) / (1 + x^2 + y^2 - 2x))
//
// However, when x is either large (x > 1/E) or very small
// (x < E) then this effectively simplifies
// to log(1), leading to wildly inaccurate results.
// By dividing the above (top and bottom) by (1 + x^2 + y^2) we get:
//
// real(atanh(z)) == log((1 + (2x / (1 + x^2 + y^2))) / (1 - (-2x / (1 + x^2 + y^2))))
//
// which is much more sensitive to the value of x, when x is not near 1
// (remember we can compute log(1+x) for small x very accurately).
//
// The cross-over from one method to the other has to be determined
// experimentally, the value used below appears correct to within a
// factor of 2 (and there are larger errors from other parts
// of the input domain anyway).
//
T alpha = two*x / (one + xx + yy);
if(alpha < a_crossover)
{
real = boost::math::log1p(alpha) - boost::math::log1p(-alpha);
}
else
{
T xm1 = x - one;
real = boost::math::log1p(x2 + xx + yy) - std::log(xm1*xm1 + yy);
}
real /= four;
if(z.real() < 0)
real = -real;
imag = std::atan2((y * two), (one - xx - yy));
imag /= two;
if(z.imag() < 0)
imag = -imag;
}
else
{
//
// This section handles exception cases that would normally cause
// underflow or overflow in the main formulas.
//
// Begin by working out the real part, we need to approximate
// alpha = 2x / (1 + x^2 + y^2)
// without either overflow or underflow in the squared terms.
//
T alpha = 0;
if(x >= safe_upper)
{
// this is really a test for infinity,
// but we may not have the necessary numeric_limits support:
if((x > (std::numeric_limits<T>::max)()) || (y > (std::numeric_limits<T>::max)()))
{
alpha = 0;
}
else if(y >= safe_upper)
{
// Big x and y: divide alpha through by x*y:
alpha = (two/y) / (x/y + y/x);
}
else if(y > one)
{
// Big x: divide through by x:
alpha = two / (x + y*y/x);
}
else
{
// Big x small y, as above but neglect y^2/x:
alpha = two/x;
}
}
else if(y >= safe_upper)
{
if(x > one)
{
// Big y, medium x, divide through by y:
alpha = (two*x/y) / (y + x*x/y);
}
else
{
// Small x and y, whatever alpha is, it's too small to calculate:
alpha = 0;
}
}
else
{
// one or both of x and y are small, calculate divisor carefully:
T div = one;
if(x > safe_lower)
div += x*x;
if(y > safe_lower)
div += y*y;
alpha = two*x/div;
}
if(alpha < a_crossover)
{
real = boost::math::log1p(alpha) - boost::math::log1p(-alpha);
}
else
{
// We can only get here as a result of small y and medium sized x,
// we can simply neglect the y^2 terms:
BOOST_ASSERT(x >= safe_lower);
BOOST_ASSERT(x <= safe_upper);
//BOOST_ASSERT(y <= safe_lower);
T xm1 = x - one;
real = std::log(1 + two*x + x*x) - std::log(xm1*xm1);
}
real /= four;
if(z.real() < 0)
real = -real;
//
// Now handle imaginary part, this is much easier,
// if x or y are large, then the formula:
// atan2(2y, 1 - x^2 - y^2)
// evaluates to +-(PI - theta) where theta is negligible compared to PI.
//
if((x >= safe_upper) || (y >= safe_upper))
{
imag = pi;
}
else if(x <= safe_lower)
{
//
// If both x and y are small then atan(2y),
// otherwise just x^2 is negligible in the divisor:
//
if(y <= safe_lower)
imag = std::atan2(two*y, one);
else
{
if((y == zero) && (x == zero))
imag = 0;
else
imag = std::atan2(two*y, one - y*y);
}
}
else
{
//
// y^2 is negligible:
//
if((y == zero) && (x == one))
imag = 0;
else
imag = std::atan2(two*y, 1 - x*x);
}
imag /= two;
if(z.imag() < 0)
imag = -imag;
}
return std::complex<T>(real, imag);
}
} } // namespaces
#endif // BOOST_MATH_COMPLEX_ATANH_INCLUDED

View File

@@ -0,0 +1,104 @@
// (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_COMPLEX_DETAILS_INCLUDED
#define BOOST_MATH_COMPLEX_DETAILS_INCLUDED
//
// This header contains all the support code that is common to the
// inverse trig complex functions, it also contains all the includes
// that we need to implement all these functions.
//
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/config/no_tr1/complex.hpp>
#include <boost/limits.hpp>
#include <math.h> // isnan where available
#include <boost/config/no_tr1/cmath.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std{ using ::sqrt; }
#endif
namespace boost{ namespace math{ namespace detail{
template <class T>
inline bool test_is_nan(T t)
{
// Comparisons with Nan's always fail:
return std::numeric_limits<T>::has_infinity && (!(t <= std::numeric_limits<T>::infinity()) || !(t >= -std::numeric_limits<T>::infinity()));
}
#ifdef isnan
template<> inline bool test_is_nan<float>(float t) { return isnan(t); }
template<> inline bool test_is_nan<double>(double t) { return isnan(t); }
template<> inline bool test_is_nan<long double>(long double t) { return isnan(t); }
#endif
template <class T>
inline T mult_minus_one(const T& t)
{
return test_is_nan(t) ? t : -t;
}
template <class T>
inline std::complex<T> mult_i(const std::complex<T>& t)
{
return std::complex<T>(mult_minus_one(t.imag()), t.real());
}
template <class T>
inline std::complex<T> mult_minus_i(const std::complex<T>& t)
{
return std::complex<T>(t.imag(), mult_minus_one(t.real()));
}
template <class T>
inline T safe_max(T t)
{
return std::sqrt((std::numeric_limits<T>::max)()) / t;
}
inline long double safe_max(long double t)
{
// long double sqrt often returns infinity due to
// insufficient internal precision:
return std::sqrt((std::numeric_limits<double>::max)()) / t;
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// workaround for type deduction bug:
inline float safe_max(float t)
{
return std::sqrt((std::numeric_limits<float>::max)()) / t;
}
inline double safe_max(double t)
{
return std::sqrt((std::numeric_limits<double>::max)()) / t;
}
#endif
template <class T>
inline T safe_min(T t)
{
return std::sqrt((std::numeric_limits<T>::min)()) * t;
}
inline long double safe_min(long double t)
{
// long double sqrt often returns zero due to
// insufficient internal precision:
return std::sqrt((std::numeric_limits<double>::min)()) * t;
}
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
// type deduction workaround:
inline double safe_min(double t)
{
return std::sqrt((std::numeric_limits<double>::min)()) * t;
}
inline float safe_min(float t)
{
return std::sqrt((std::numeric_limits<float>::min)()) * t;
}
#endif
} } } // namespaces
#endif // BOOST_MATH_COMPLEX_DETAILS_INCLUDED

View File

@@ -0,0 +1,23 @@
// (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_COMPLEX_FABS_INCLUDED
#define BOOST_MATH_COMPLEX_FABS_INCLUDED
#ifndef BOOST_MATH_HYPOT_INCLUDED
# include <boost/math/special_functions/hypot.hpp>
#endif
namespace boost{ namespace math{
template<class T>
inline T fabs(const std::complex<T>& z)
{
return ::boost::math::hypot(z.real(), z.imag());
}
} } // namespaces
#endif // BOOST_MATH_COMPLEX_FABS_INCLUDED

View File

@@ -0,0 +1,204 @@
// 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)
// distributions.hpp provides definitions of the concept of a distribution
// and non-member accessor functions that must be implemented by all distributions.
// This is used to verify that
// all the features of a distributions have been fully implemented.
#ifndef BOOST_MATH_DISTRIBUTION_CONCEPT_HPP
#define BOOST_MATH_DISTRIBUTION_CONCEPT_HPP
#include <boost/math/distributions/complement.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4100)
#pragma warning(disable: 4510)
#pragma warning(disable: 4610)
#endif
#include <boost/concept_check.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <utility>
namespace boost{
namespace math{
namespace concepts
{
// Begin by defining a concept archetype
// for a distribution class:
//
template <class RealType>
class distribution_archetype
{
public:
typedef RealType value_type;
distribution_archetype(const distribution_archetype&); // Copy constructible.
distribution_archetype& operator=(const distribution_archetype&); // Assignable.
// There is no default constructor,
// but we need a way to instantiate the archetype:
static distribution_archetype& get_object()
{
// will never get caled:
return *reinterpret_cast<distribution_archetype*>(0);
}
}; // template <class RealType>class distribution_archetype
// Non-member accessor functions:
// (This list defines the functions that must be implemented by all distributions).
template <class RealType>
RealType pdf(const distribution_archetype<RealType>& dist, const RealType& x);
template <class RealType>
RealType cdf(const distribution_archetype<RealType>& dist, const RealType& x);
template <class RealType>
RealType quantile(const distribution_archetype<RealType>& dist, const RealType& p);
template <class RealType>
RealType cdf(const complemented2_type<distribution_archetype<RealType>, RealType>& c);
template <class RealType>
RealType quantile(const complemented2_type<distribution_archetype<RealType>, RealType>& c);
template <class RealType>
RealType mean(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType standard_deviation(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType variance(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType hazard(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType chf(const distribution_archetype<RealType>& dist);
// http://en.wikipedia.org/wiki/Characteristic_function_%28probability_theory%29
template <class RealType>
RealType coefficient_of_variation(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType mode(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType skewness(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType kurtosis_excess(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType kurtosis(const distribution_archetype<RealType>& dist);
template <class RealType>
RealType median(const distribution_archetype<RealType>& dist);
template <class RealType>
std::pair<RealType, RealType> range(const distribution_archetype<RealType>& dist);
template <class RealType>
std::pair<RealType, RealType> support(const distribution_archetype<RealType>& dist);
//
// Next comes the concept checks for verifying that a class
// fullfils the requirements of a Distribution:
//
template <class Distribution>
struct DistributionConcept
{
void constraints()
{
function_requires<CopyConstructibleConcept<Distribution> >();
function_requires<AssignableConcept<Distribution> >();
typedef typename Distribution::value_type value_type;
const Distribution& dist = DistributionConcept<Distribution>::get_object();
value_type x = 0;
// The result values are ignored in all these checks.
value_type v = cdf(dist, x);
v = cdf(complement(dist, x));
v = pdf(dist, x);
v = quantile(dist, x);
v = quantile(complement(dist, x));
v = mean(dist);
v = mode(dist);
v = standard_deviation(dist);
v = variance(dist);
v = hazard(dist, x);
v = chf(dist, x);
v = coefficient_of_variation(dist);
v = skewness(dist);
v = kurtosis(dist);
v = kurtosis_excess(dist);
v = median(dist);
std::pair<value_type, value_type> pv;
pv = range(dist);
pv = support(dist);
float f = 1;
v = cdf(dist, f);
v = cdf(complement(dist, f));
v = pdf(dist, f);
v = quantile(dist, f);
v = quantile(complement(dist, f));
v = hazard(dist, f);
v = chf(dist, f);
double d = 1;
v = cdf(dist, d);
v = cdf(complement(dist, d));
v = pdf(dist, d);
v = quantile(dist, d);
v = quantile(complement(dist, d));
v = hazard(dist, d);
v = chf(dist, d);
long double ld = 1;
v = cdf(dist, ld);
v = cdf(complement(dist, ld));
v = pdf(dist, ld);
v = quantile(dist, ld);
v = quantile(complement(dist, ld));
v = hazard(dist, ld);
v = chf(dist, ld);
int i = 1;
v = cdf(dist, i);
v = cdf(complement(dist, i));
v = pdf(dist, i);
v = quantile(dist, i);
v = quantile(complement(dist, i));
v = hazard(dist, i);
v = chf(dist, i);
unsigned long li = 1;
v = cdf(dist, li);
v = cdf(complement(dist, li));
v = pdf(dist, li);
v = quantile(dist, li);
v = quantile(complement(dist, li));
v = hazard(dist, li);
v = chf(dist, li);
}
private:
static Distribution& get_object()
{
// will never get called:
static char buf[sizeof(Distribution)];
return * reinterpret_cast<Distribution*>(buf);
}
}; // struct DistributionConcept
} // namespace concepts
} // namespace math
} // namespace boost
#endif // BOOST_MATH_DISTRIBUTION_CONCEPT_HPP

View File

@@ -0,0 +1,441 @@
// 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)
// Test real concept.
// real_concept is an archetype for User defined Real types.
// This file defines the features, constructors, operators, functions...
// that are essential to use mathematical and statistical functions.
// The template typename "RealType" is used where this type
// (as well as the normal built-in types, float, double & long double)
// can be used.
// That this is the minimum set is confirmed by use as a type
// in tests of all functions & distributions, for example:
// test_spots(0.F); & test_spots(0.); for float and double, but also
// test_spots(boost::math::concepts::real_concept(0.));
// NTL quad_float type is an example of a type meeting the requirements,
// but note minor additions are needed - see ntl.diff and documentation
// "Using With NTL - a High-Precision Floating-Point Library".
#ifndef BOOST_MATH_REAL_CONCEPT_HPP
#define BOOST_MATH_REAL_CONCEPT_HPP
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/special_functions/modf.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/policy.hpp>
#if defined(__SGI_STL_PORT)
# include <boost/math/tools/real_cast.hpp>
#endif
#include <ostream>
#include <istream>
#include <boost/config/no_tr1/cmath.hpp>
#include <math.h> // fmodl
#if defined(__SGI_STL_PORT) || defined(_RWSTD_VER) || defined(__LIBCOMO__)
# include <cstdio>
#endif
namespace boost{ namespace math{
namespace concepts
{
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
typedef double real_concept_base_type;
#else
typedef long double real_concept_base_type;
#endif
class real_concept
{
public:
// Constructors:
real_concept() : m_value(0){}
real_concept(char c) : m_value(c){}
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
real_concept(wchar_t c) : m_value(c){}
#endif
real_concept(unsigned char c) : m_value(c){}
real_concept(signed char c) : m_value(c){}
real_concept(unsigned short c) : m_value(c){}
real_concept(short c) : m_value(c){}
real_concept(unsigned int c) : m_value(c){}
real_concept(int c) : m_value(c){}
real_concept(unsigned long c) : m_value(c){}
real_concept(long c) : m_value(c){}
#if defined(__DECCXX) || defined(__SUNPRO_CC)
real_concept(unsigned long long c) : m_value(static_cast<real_concept_base_type>(c)){}
real_concept(long long c) : m_value(static_cast<real_concept_base_type>(c)){}
#elif defined(BOOST_HAS_LONG_LONG)
real_concept(boost::ulong_long_type c) : m_value(static_cast<real_concept_base_type>(c)){}
real_concept(boost::long_long_type c) : m_value(static_cast<real_concept_base_type>(c)){}
#elif defined(BOOST_HAS_MS_INT64)
real_concept(unsigned __int64 c) : m_value(static_cast<real_concept_base_type>(c)){}
real_concept(__int64 c) : m_value(static_cast<real_concept_base_type>(c)){}
#endif
real_concept(float c) : m_value(c){}
real_concept(double c) : m_value(c){}
real_concept(long double c) : m_value(c){}
// Assignment:
real_concept& operator=(char c) { m_value = c; return *this; }
real_concept& operator=(unsigned char c) { m_value = c; return *this; }
real_concept& operator=(signed char c) { m_value = c; return *this; }
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
real_concept& operator=(wchar_t c) { m_value = c; return *this; }
#endif
real_concept& operator=(short c) { m_value = c; return *this; }
real_concept& operator=(unsigned short c) { m_value = c; return *this; }
real_concept& operator=(int c) { m_value = c; return *this; }
real_concept& operator=(unsigned int c) { m_value = c; return *this; }
real_concept& operator=(long c) { m_value = c; return *this; }
real_concept& operator=(unsigned long c) { m_value = c; return *this; }
#ifdef BOOST_HAS_LONG_LONG
real_concept& operator=(boost::long_long_type c) { m_value = static_cast<real_concept_base_type>(c); return *this; }
real_concept& operator=(boost::ulong_long_type c) { m_value = static_cast<real_concept_base_type>(c); return *this; }
#endif
real_concept& operator=(float c) { m_value = c; return *this; }
real_concept& operator=(double c) { m_value = c; return *this; }
real_concept& operator=(long double c) { m_value = c; return *this; }
// Access:
real_concept_base_type value()const{ return m_value; }
// Member arithmetic:
real_concept& operator+=(const real_concept& other)
{ m_value += other.value(); return *this; }
real_concept& operator-=(const real_concept& other)
{ m_value -= other.value(); return *this; }
real_concept& operator*=(const real_concept& other)
{ m_value *= other.value(); return *this; }
real_concept& operator/=(const real_concept& other)
{ m_value /= other.value(); return *this; }
real_concept operator-()const
{ return -m_value; }
real_concept const& operator+()const
{ return *this; }
real_concept& operator++()
{ ++m_value; return *this; }
real_concept& operator--()
{ --m_value; return *this; }
private:
real_concept_base_type m_value;
};
// Non-member arithmetic:
inline real_concept operator+(const real_concept& a, const real_concept& b)
{
real_concept result(a);
result += b;
return result;
}
inline real_concept operator-(const real_concept& a, const real_concept& b)
{
real_concept result(a);
result -= b;
return result;
}
inline real_concept operator*(const real_concept& a, const real_concept& b)
{
real_concept result(a);
result *= b;
return result;
}
inline real_concept operator/(const real_concept& a, const real_concept& b)
{
real_concept result(a);
result /= b;
return result;
}
// Comparison:
inline bool operator == (const real_concept& a, const real_concept& b)
{ return a.value() == b.value(); }
inline bool operator != (const real_concept& a, const real_concept& b)
{ return a.value() != b.value();}
inline bool operator < (const real_concept& a, const real_concept& b)
{ return a.value() < b.value(); }
inline bool operator <= (const real_concept& a, const real_concept& b)
{ return a.value() <= b.value(); }
inline bool operator > (const real_concept& a, const real_concept& b)
{ return a.value() > b.value(); }
inline bool operator >= (const real_concept& a, const real_concept& b)
{ return a.value() >= b.value(); }
// Non-member functions:
inline real_concept acos(real_concept a)
{ return std::acos(a.value()); }
inline real_concept cos(real_concept a)
{ return std::cos(a.value()); }
inline real_concept asin(real_concept a)
{ return std::asin(a.value()); }
inline real_concept atan(real_concept a)
{ return std::atan(a.value()); }
inline real_concept atan2(real_concept a, real_concept b)
{ return std::atan2(a.value(), b.value()); }
inline real_concept ceil(real_concept a)
{ return std::ceil(a.value()); }
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
// I've seen std::fmod(long double) crash on some platforms
// so use fmodl instead:
#ifdef _WIN32_WCE
//
// Ugly workaround for macro fmodl:
//
inline long double call_fmodl(long double a, long double b)
{ return fmodl(a, b); }
inline real_concept fmod(real_concept a, real_concept b)
{ return call_fmodl(a.value(), b.value()); }
#else
inline real_concept fmod(real_concept a, real_concept b)
{ return fmodl(a.value(), b.value()); }
#endif
#endif
inline real_concept cosh(real_concept a)
{ return std::cosh(a.value()); }
inline real_concept exp(real_concept a)
{ return std::exp(a.value()); }
inline real_concept fabs(real_concept a)
{ return std::fabs(a.value()); }
inline real_concept abs(real_concept a)
{ return std::abs(a.value()); }
inline real_concept floor(real_concept a)
{ return std::floor(a.value()); }
inline real_concept modf(real_concept a, real_concept* ipart)
{
real_concept_base_type ip;
real_concept_base_type result = std::modf(a.value(), &ip);
*ipart = ip;
return result;
}
inline real_concept frexp(real_concept a, int* expon)
{ return std::frexp(a.value(), expon); }
inline real_concept ldexp(real_concept a, int expon)
{ return std::ldexp(a.value(), expon); }
inline real_concept log(real_concept a)
{ return std::log(a.value()); }
inline real_concept log10(real_concept a)
{ return std::log10(a.value()); }
inline real_concept tan(real_concept a)
{ return std::tan(a.value()); }
inline real_concept pow(real_concept a, real_concept b)
{ return std::pow(a.value(), b.value()); }
#if !defined(__SUNPRO_CC)
inline real_concept pow(real_concept a, int b)
{ return std::pow(a.value(), b); }
#else
inline real_concept pow(real_concept a, int b)
{ return std::pow(a.value(), static_cast<real_concept_base_type>(b)); }
#endif
inline real_concept sin(real_concept a)
{ return std::sin(a.value()); }
inline real_concept sinh(real_concept a)
{ return std::sinh(a.value()); }
inline real_concept sqrt(real_concept a)
{ return std::sqrt(a.value()); }
inline real_concept tanh(real_concept a)
{ return std::tanh(a.value()); }
//
// Conversion and truncation routines:
//
template <class Policy>
inline int iround(const concepts::real_concept& v, const Policy& pol)
{ return boost::math::iround(v.value(), pol); }
inline int iround(const concepts::real_concept& v)
{ return boost::math::iround(v.value(), policies::policy<>()); }
template <class Policy>
inline long lround(const concepts::real_concept& v, const Policy& pol)
{ return boost::math::lround(v.value(), pol); }
inline long lround(const concepts::real_concept& v)
{ return boost::math::lround(v.value(), policies::policy<>()); }
#ifdef BOOST_HAS_LONG_LONG
template <class Policy>
inline boost::long_long_type llround(const concepts::real_concept& v, const Policy& pol)
{ return boost::math::llround(v.value(), pol); }
inline boost::long_long_type llround(const concepts::real_concept& v)
{ return boost::math::llround(v.value(), policies::policy<>()); }
#endif
template <class Policy>
inline int itrunc(const concepts::real_concept& v, const Policy& pol)
{ return boost::math::itrunc(v.value(), pol); }
inline int itrunc(const concepts::real_concept& v)
{ return boost::math::itrunc(v.value(), policies::policy<>()); }
template <class Policy>
inline long ltrunc(const concepts::real_concept& v, const Policy& pol)
{ return boost::math::ltrunc(v.value(), pol); }
inline long ltrunc(const concepts::real_concept& v)
{ return boost::math::ltrunc(v.value(), policies::policy<>()); }
#ifdef BOOST_HAS_LONG_LONG
template <class Policy>
inline boost::long_long_type lltrunc(const concepts::real_concept& v, const Policy& pol)
{ return boost::math::lltrunc(v.value(), pol); }
inline boost::long_long_type lltrunc(const concepts::real_concept& v)
{ return boost::math::lltrunc(v.value(), policies::policy<>()); }
#endif
// Streaming:
template <class charT, class traits>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const real_concept& a)
{
return os << a.value();
}
template <class charT, class traits>
inline std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, real_concept& a)
{
#if defined(BOOST_MSVC) && defined(__SGI_STL_PORT)
//
// STLPort 5.1.4 has a problem reading long doubles from strings,
// see http://sourceforge.net/tracker/index.php?func=detail&aid=1811043&group_id=146814&atid=766244
//
double v;
is >> v;
a = v;
return is;
#elif defined(__SGI_STL_PORT) || defined(_RWSTD_VER) || defined(__LIBCOMO__)
std::string s;
real_concept_base_type d;
is >> s;
std::sscanf(s.c_str(), "%Lf", &d);
a = d;
return is;
#else
real_concept_base_type v;
is >> v;
a = v;
return is;
#endif
}
} // namespace concepts
namespace tools
{
template <>
inline concepts::real_concept max_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
{
return max_value<concepts::real_concept_base_type>();
}
template <>
inline concepts::real_concept min_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
{
return min_value<concepts::real_concept_base_type>();
}
template <>
inline concepts::real_concept log_max_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
{
return log_max_value<concepts::real_concept_base_type>();
}
template <>
inline concepts::real_concept log_min_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
{
return log_min_value<concepts::real_concept_base_type>();
}
template <>
inline concepts::real_concept epsilon<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
{
#ifdef __SUNPRO_CC
return std::numeric_limits<concepts::real_concept_base_type>::epsilon();
#else
return tools::epsilon<concepts::real_concept_base_type>();
#endif
}
template <>
inline int digits<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
{
// Assume number of significand bits is same as real_concept_base_type,
// unless std::numeric_limits<T>::is_specialized to provide digits.
return tools::digits<concepts::real_concept_base_type>();
// Note that if numeric_limits real concept is NOT specialized to provide digits10
// (or max_digits10) then the default precision of 6 decimal digits will be used
// by Boost test (giving misleading error messages like
// "difference between {9.79796} and {9.79796} exceeds 5.42101e-19%"
// and by Boost lexical cast and serialization causing loss of accuracy.
}
} // namespace tools
#if defined(__SGI_STL_PORT)
//
// We shouldn't really need these type casts any more, but there are some
// STLport iostream bugs we work around by using them....
//
namespace tools
{
// real_cast converts from T to integer and narrower floating-point types.
// Convert from T to integer types.
template <>
inline unsigned int real_cast<unsigned int, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<unsigned int>(r.value());
}
template <>
inline int real_cast<int, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<int>(r.value());
}
template <>
inline long real_cast<long, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<long>(r.value());
}
// Converts from T to narrower floating-point types, float, double & long double.
template <>
inline float real_cast<float, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<float>(r.value());
}
template <>
inline double real_cast<double, concepts::real_concept>(concepts::real_concept r)
{
return static_cast<double>(r.value());
}
template <>
inline long double real_cast<long double, concepts::real_concept>(concepts::real_concept r)
{
return r.value();
}
} // STLPort
#endif
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
//
// For some strange reason ADL sometimes fails to find the
// correct overloads, unless we bring these declarations into scope:
//
using concepts::itrunc;
using concepts::iround;
#endif
} // namespace math
} // namespace boost
#endif // BOOST_MATH_REAL_CONCEPT_HPP

View File

@@ -0,0 +1,380 @@
// 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)
// std_real_concept is an archetype for built-in Real types.
// The main purpose in providing this type is to verify
// that std lib functions are found via a using declaration
// bringing those functions into the current scope, and not
// just because they happen to be in global scope.
//
// If ::pow is found rather than std::pow say, then the code
// will silently compile, but truncation of long doubles to
// double will cause a significant loss of precision.
// A template instantiated with std_real_concept will *only*
// compile if it std::whatever is in scope.
#include <boost/config.hpp>
#include <boost/limits.hpp>
#include <boost/math/policies/policy.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <ostream>
#include <istream>
#include <boost/config/no_tr1/cmath.hpp>
#include <math.h> // fmodl
#ifndef BOOST_MATH_STD_REAL_CONCEPT_HPP
#define BOOST_MATH_STD_REAL_CONCEPT_HPP
namespace boost{ namespace math{
namespace concepts
{
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
typedef double std_real_concept_base_type;
#else
typedef long double std_real_concept_base_type;
#endif
class std_real_concept
{
public:
// Constructors:
std_real_concept() : m_value(0){}
std_real_concept(char c) : m_value(c){}
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
std_real_concept(wchar_t c) : m_value(c){}
#endif
std_real_concept(unsigned char c) : m_value(c){}
std_real_concept(signed char c) : m_value(c){}
std_real_concept(unsigned short c) : m_value(c){}
std_real_concept(short c) : m_value(c){}
std_real_concept(unsigned int c) : m_value(c){}
std_real_concept(int c) : m_value(c){}
std_real_concept(unsigned long c) : m_value(c){}
std_real_concept(long c) : m_value(c){}
#if defined(__DECCXX) || defined(__SUNPRO_CC)
std_real_concept(unsigned long long c) : m_value(static_cast<std_real_concept_base_type>(c)){}
std_real_concept(long long c) : m_value(static_cast<std_real_concept_base_type>(c)){}
#elif defined(BOOST_HAS_LONG_LONG)
std_real_concept(boost::ulong_long_type c) : m_value(static_cast<std_real_concept_base_type>(c)){}
std_real_concept(boost::long_long_type c) : m_value(static_cast<std_real_concept_base_type>(c)){}
#endif
std_real_concept(float c) : m_value(c){}
std_real_concept(double c) : m_value(c){}
std_real_concept(long double c) : m_value(c){}
// Assignment:
std_real_concept& operator=(char c) { m_value = c; return *this; }
std_real_concept& operator=(unsigned char c) { m_value = c; return *this; }
std_real_concept& operator=(signed char c) { m_value = c; return *this; }
#ifndef BOOST_NO_INTRINSIC_WCHAR_T
std_real_concept& operator=(wchar_t c) { m_value = c; return *this; }
#endif
std_real_concept& operator=(short c) { m_value = c; return *this; }
std_real_concept& operator=(unsigned short c) { m_value = c; return *this; }
std_real_concept& operator=(int c) { m_value = c; return *this; }
std_real_concept& operator=(unsigned int c) { m_value = c; return *this; }
std_real_concept& operator=(long c) { m_value = c; return *this; }
std_real_concept& operator=(unsigned long c) { m_value = c; return *this; }
#if defined(__DECCXX) || defined(__SUNPRO_CC)
std_real_concept& operator=(unsigned long long c) { m_value = static_cast<std_real_concept_base_type>(c); return *this; }
std_real_concept& operator=(long long c) { m_value = static_cast<std_real_concept_base_type>(c); return *this; }
#elif defined(BOOST_HAS_LONG_LONG)
std_real_concept& operator=(boost::long_long_type c) { m_value = static_cast<std_real_concept_base_type>(c); return *this; }
std_real_concept& operator=(boost::ulong_long_type c) { m_value = static_cast<std_real_concept_base_type>(c); return *this; }
#endif
std_real_concept& operator=(float c) { m_value = c; return *this; }
std_real_concept& operator=(double c) { m_value = c; return *this; }
std_real_concept& operator=(long double c) { m_value = c; return *this; }
// Access:
std_real_concept_base_type value()const{ return m_value; }
// Member arithmetic:
std_real_concept& operator+=(const std_real_concept& other)
{ m_value += other.value(); return *this; }
std_real_concept& operator-=(const std_real_concept& other)
{ m_value -= other.value(); return *this; }
std_real_concept& operator*=(const std_real_concept& other)
{ m_value *= other.value(); return *this; }
std_real_concept& operator/=(const std_real_concept& other)
{ m_value /= other.value(); return *this; }
std_real_concept operator-()const
{ return -m_value; }
std_real_concept const& operator+()const
{ return *this; }
private:
std_real_concept_base_type m_value;
};
// Non-member arithmetic:
inline std_real_concept operator+(const std_real_concept& a, const std_real_concept& b)
{
std_real_concept result(a);
result += b;
return result;
}
inline std_real_concept operator-(const std_real_concept& a, const std_real_concept& b)
{
std_real_concept result(a);
result -= b;
return result;
}
inline std_real_concept operator*(const std_real_concept& a, const std_real_concept& b)
{
std_real_concept result(a);
result *= b;
return result;
}
inline std_real_concept operator/(const std_real_concept& a, const std_real_concept& b)
{
std_real_concept result(a);
result /= b;
return result;
}
// Comparison:
inline bool operator == (const std_real_concept& a, const std_real_concept& b)
{ return a.value() == b.value(); }
inline bool operator != (const std_real_concept& a, const std_real_concept& b)
{ return a.value() != b.value();}
inline bool operator < (const std_real_concept& a, const std_real_concept& b)
{ return a.value() < b.value(); }
inline bool operator <= (const std_real_concept& a, const std_real_concept& b)
{ return a.value() <= b.value(); }
inline bool operator > (const std_real_concept& a, const std_real_concept& b)
{ return a.value() > b.value(); }
inline bool operator >= (const std_real_concept& a, const std_real_concept& b)
{ return a.value() >= b.value(); }
} // namespace concepts
} // namespace math
} // namespace boost
namespace std{
// Non-member functions:
inline boost::math::concepts::std_real_concept acos(boost::math::concepts::std_real_concept a)
{ return std::acos(a.value()); }
inline boost::math::concepts::std_real_concept cos(boost::math::concepts::std_real_concept a)
{ return std::cos(a.value()); }
inline boost::math::concepts::std_real_concept asin(boost::math::concepts::std_real_concept a)
{ return std::asin(a.value()); }
inline boost::math::concepts::std_real_concept atan(boost::math::concepts::std_real_concept a)
{ return std::atan(a.value()); }
inline boost::math::concepts::std_real_concept atan2(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b)
{ return std::atan2(a.value(), b.value()); }
inline boost::math::concepts::std_real_concept ceil(boost::math::concepts::std_real_concept a)
{ return std::ceil(a.value()); }
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
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()); }
#else
inline boost::math::concepts::std_real_concept fmod(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b)
{ return std::fmod(a.value(), b.value()); }
#endif
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)
{ return std::exp(a.value()); }
inline boost::math::concepts::std_real_concept fabs(boost::math::concepts::std_real_concept a)
{ return std::fabs(a.value()); }
inline boost::math::concepts::std_real_concept abs(boost::math::concepts::std_real_concept a)
{ return std::abs(a.value()); }
inline boost::math::concepts::std_real_concept floor(boost::math::concepts::std_real_concept a)
{ return std::floor(a.value()); }
inline boost::math::concepts::std_real_concept modf(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept* ipart)
{
boost::math::concepts::std_real_concept_base_type ip;
boost::math::concepts::std_real_concept_base_type result = std::modf(a.value(), &ip);
*ipart = ip;
return result;
}
inline boost::math::concepts::std_real_concept frexp(boost::math::concepts::std_real_concept a, int* expon)
{ return std::frexp(a.value(), expon); }
inline boost::math::concepts::std_real_concept ldexp(boost::math::concepts::std_real_concept a, int expon)
{ return std::ldexp(a.value(), expon); }
inline boost::math::concepts::std_real_concept log(boost::math::concepts::std_real_concept a)
{ return std::log(a.value()); }
inline boost::math::concepts::std_real_concept log10(boost::math::concepts::std_real_concept a)
{ return std::log10(a.value()); }
inline boost::math::concepts::std_real_concept tan(boost::math::concepts::std_real_concept a)
{ return std::tan(a.value()); }
inline boost::math::concepts::std_real_concept pow(boost::math::concepts::std_real_concept a, boost::math::concepts::std_real_concept b)
{ return std::pow(a.value(), b.value()); }
#if !defined(__SUNPRO_CC)
inline boost::math::concepts::std_real_concept pow(boost::math::concepts::std_real_concept a, int b)
{ return std::pow(a.value(), b); }
#else
inline boost::math::concepts::std_real_concept pow(boost::math::concepts::std_real_concept a, int b)
{ return std::pow(a.value(), static_cast<long double>(b)); }
#endif
inline boost::math::concepts::std_real_concept sin(boost::math::concepts::std_real_concept a)
{ return std::sin(a.value()); }
inline boost::math::concepts::std_real_concept sinh(boost::math::concepts::std_real_concept a)
{ return std::sinh(a.value()); }
inline boost::math::concepts::std_real_concept sqrt(boost::math::concepts::std_real_concept a)
{ return std::sqrt(a.value()); }
inline boost::math::concepts::std_real_concept tanh(boost::math::concepts::std_real_concept a)
{ return std::tanh(a.value()); }
} // namespace std
namespace boost{ namespace math{ namespace concepts{
//
// Conversion and truncation routines:
//
template <class Policy>
inline int iround(const concepts::std_real_concept& v, const Policy& pol)
{
return boost::math::iround(v.value(), pol);
}
inline int iround(const concepts::std_real_concept& v)
{
return boost::math::iround(v.value(), policies::policy<>());
}
template <class Policy>
inline long lround(const concepts::std_real_concept& v, const Policy& pol)
{
return boost::math::lround(v.value(), pol);
}
inline long lround(const concepts::std_real_concept& v)
{
return boost::math::lround(v.value(), policies::policy<>());
}
#ifdef BOOST_HAS_LONG_LONG
template <class Policy>
inline boost::long_long_type llround(const concepts::std_real_concept& v, const Policy& pol)
{
return boost::math::llround(v.value(), pol);
}
inline boost::long_long_type llround(const concepts::std_real_concept& v)
{
return boost::math::llround(v.value(), policies::policy<>());
}
#endif
template <class Policy>
inline int itrunc(const concepts::std_real_concept& v, const Policy& pol)
{
return boost::math::itrunc(v.value(), pol);
}
inline int itrunc(const concepts::std_real_concept& v)
{
return boost::math::itrunc(v.value(), policies::policy<>());
}
template <class Policy>
inline long ltrunc(const concepts::std_real_concept& v, const Policy& pol)
{
return boost::math::ltrunc(v.value(), pol);
}
inline long ltrunc(const concepts::std_real_concept& v)
{
return boost::math::ltrunc(v.value(), policies::policy<>());
}
#ifdef BOOST_HAS_LONG_LONG
template <class Policy>
inline boost::long_long_type lltrunc(const concepts::std_real_concept& v, const Policy& pol)
{
return boost::math::lltrunc(v.value(), pol);
}
inline boost::long_long_type lltrunc(const concepts::std_real_concept& v)
{
return boost::math::lltrunc(v.value(), policies::policy<>());
}
#endif
// Streaming:
template <class charT, class traits>
inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& os, const std_real_concept& a)
{
return os << a.value();
}
template <class charT, class traits>
inline std::basic_istream<charT, traits>& operator>>(std::basic_istream<charT, traits>& is, std_real_concept& a)
{
std_real_concept_base_type v;
is >> v;
a = v;
return is;
}
} // namespace concepts
}}
#include <boost/math/tools/precision.hpp>
namespace boost{ namespace math{
namespace tools
{
template <>
inline concepts::std_real_concept max_value<concepts::std_real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept))
{
return max_value<concepts::std_real_concept_base_type>();
}
template <>
inline concepts::std_real_concept min_value<concepts::std_real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept))
{
return min_value<concepts::std_real_concept_base_type>();
}
template <>
inline concepts::std_real_concept log_max_value<concepts::std_real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept))
{
return log_max_value<concepts::std_real_concept_base_type>();
}
template <>
inline concepts::std_real_concept log_min_value<concepts::std_real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept))
{
return log_min_value<concepts::std_real_concept_base_type>();
}
template <>
inline concepts::std_real_concept epsilon(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept))
{
return tools::epsilon<concepts::std_real_concept_base_type>();
}
template <>
inline int digits<concepts::std_real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept))
{ // Assume number of significand bits is same as std_real_concept_base_type,
// unless std::numeric_limits<T>::is_specialized to provide digits.
return digits<concepts::std_real_concept_base_type>();
}
} // namespace tools
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1310)
using concepts::itrunc;
using concepts::ltrunc;
using concepts::lltrunc;
using concepts::iround;
using concepts::lround;
using concepts::llround;
#endif
} // namespace math
} // namespace boost
#endif // BOOST_MATH_STD_REAL_CONCEPT_HPP

View File

@@ -0,0 +1,75 @@
// Copyright John Maddock 2005-2006.
// Copyright Paul A. Bristow 2006-7.
// 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_CONSTANTS_CONSTANTS_INCLUDED
#define BOOST_MATH_CONSTANTS_CONSTANTS_INCLUDED
#include <boost/math/tools/config.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable: 4127 4701)
#endif
#include <boost/lexical_cast.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
namespace boost{ namespace math
{
namespace constants
{
// To permit other calculations at about 100 decimal digits with NTL::RR type,
// it is obviously necessary to define constants to this accuracy.
// However, some compilers do not accept decimal digits strings as long as this.
// So the constant is split into two parts, with the 1st containing at least
// long double precision, and the 2nd zero if not needed or known.
// The 3rd part permits an exponent to be provided if necessary (use zero if none) -
// the other two parameters may only contain decimal digits (and sign and decimal point),
// and may NOT include an exponent like 1.234E99.
// The second digit string is only used if T is a User-Defined Type,
// when the constant is converted to a long string literal and lexical_casted to type T.
// (This is necessary because you can't use a numeric constant
// since even a long double might not have enough digits).
#define BOOST_DEFINE_MATH_CONSTANT(name, x, y, exp)\
template <class T> inline T name(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T))\
{\
static const T result = ::boost::lexical_cast<T>(BOOST_STRINGIZE(BOOST_JOIN(BOOST_JOIN(x, y), BOOST_JOIN(e, exp))));\
return result;\
}\
template <> inline float name<float>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(float))\
{ return BOOST_JOIN(BOOST_JOIN(x, BOOST_JOIN(e, exp)), F); }\
template <> inline double name<double>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(double))\
{ return BOOST_JOIN(x, BOOST_JOIN(e, exp)); }\
template <> inline long double name<long double>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(long double))\
{ return BOOST_JOIN(BOOST_JOIN(x, BOOST_JOIN(e, exp)), L); }
BOOST_DEFINE_MATH_CONSTANT(pi, 3.141592653589793238462643383279502884197169399375105820974944, 59230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196, 0)
BOOST_DEFINE_MATH_CONSTANT(root_pi, 1.7724538509055160272981674833411451827975, 0, 0)
BOOST_DEFINE_MATH_CONSTANT(root_half_pi, 1.253314137315500251207882642405522626503, 0, 0)
BOOST_DEFINE_MATH_CONSTANT(root_two_pi, 2.506628274631000502415765284811045253007, 0, 0)
BOOST_DEFINE_MATH_CONSTANT(root_ln_four, 1.1774100225154746910115693264596996377473856893858205385225257565000, 2658854698492680841813836877081, 0)
BOOST_DEFINE_MATH_CONSTANT(e, 2.7182818284590452353602874713526624977572470936999595749669676, 27724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011, 0)
BOOST_DEFINE_MATH_CONSTANT(half, 0.5, 0, 0)
BOOST_DEFINE_MATH_CONSTANT(euler, 0.577215664901532860606512090082402431042159335939923598805, 76723488486, 0)
BOOST_DEFINE_MATH_CONSTANT(root_two, 1.414213562373095048801688724209698078569671875376948073, 17667973799073247846210703885038753432764157273501384623091229702492483605585073721264412149709993583141322266592750559275579995050115278206, 0)
BOOST_DEFINE_MATH_CONSTANT(ln_two, 0.693147180559945309417232121458176568075500134360255254, 120680009493393621969694715605863326996418687, 0)
BOOST_DEFINE_MATH_CONSTANT(ln_ln_two, -0.36651292058166432701243915823266946945426344783710526305367771367056, 16153193527385494558228566989083583025230453648347655663425171940646634, 0)
BOOST_DEFINE_MATH_CONSTANT(third, 0.3333333333333333333333333333333333333333333333333333333333333333333333, 3333333333333333333333333333333333333333333333333333333333333333333333333, 0)
BOOST_DEFINE_MATH_CONSTANT(twothirds, 0.66666666666666666666666666666666666666666666666666666666666666666666, 66666666666666666666666666666666666666666666666666666666666666666666667, 0)
BOOST_DEFINE_MATH_CONSTANT(pi_minus_three, 0.141592653589793238462643383279502884197169399375105820974944, 59230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196, 0)
BOOST_DEFINE_MATH_CONSTANT(four_minus_pi, 0.85840734641020676153735661672049711580283060062489417902505540769218359, 0, 0)
BOOST_DEFINE_MATH_CONSTANT(pow23_four_minus_pi, 0.79531676737159754434839533505680658072763917332771320544530223438582161, 0, 0)
BOOST_DEFINE_MATH_CONSTANT(exp_minus_half, 0.6065306597126334236037995349911804534419181354871869556828921587350565194137, 484239986476115079894560, 0)
} // namespace constants
} // namespace math
} // namespace boost
#endif // BOOST_MATH_CONSTANTS_CONSTANTS_INCLUDED

View File

@@ -0,0 +1,43 @@
// 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/non_central_chi_squared.hpp>
#include <boost/math/distributions/non_central_beta.hpp>
#include <boost/math/distributions/non_central_f.hpp>
#include <boost/math/distributions/non_central_t.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>
#include <boost/math/distributions/find_scale.hpp>
#include <boost/math/distributions/find_location.hpp>
#endif // BOOST_MATH_DISTRIBUTIONS_HPP

View File

@@ -0,0 +1,325 @@
// boost\math\distributions\bernoulli.hpp
// 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)
// http://en.wikipedia.org/wiki/bernoulli_distribution
// http://mathworld.wolfram.com/BernoulliDistribution.html
// bernoulli distribution is the discrete probability distribution of
// the number (k) of successes, in a single Bernoulli trials.
// It is a version of the binomial distribution when n = 1.
// But note that the bernoulli distribution
// (like others including the poisson, binomial & negative binomial)
// is strictly defined as a discrete function: only integral values of k are envisaged.
// However because of the method of calculation using a continuous gamma function,
// it is convenient to treat it as if a continous function,
// and permit non-integral values of k.
// To enforce the strict mathematical model, users should use floor or ceil functions
// on k outside this function to ensure that k is integral.
#ifndef BOOST_MATH_SPECIAL_BERNOULLI_HPP
#define BOOST_MATH_SPECIAL_BERNOULLI_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/distributions/complement.hpp> // complements
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
#include <utility>
namespace boost
{
namespace math
{
namespace bernoulli_detail
{
// Common error checking routines for bernoulli distribution functions:
template <class RealType, class Policy>
inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& /* pol */)
{
if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
{
*result = policies::raise_domain_error<RealType>(
function,
"Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, Policy());
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_dist(const char* function, const RealType& p, RealType* result, const Policy& /* pol */)
{
return check_success_fraction(function, p, result, Policy());
}
template <class RealType, class Policy>
inline bool check_dist_and_k(const char* function, const RealType& p, RealType k, RealType* result, const Policy& pol)
{
if(check_dist(function, p, result, Policy()) == false)
{
return false;
}
if(!(boost::math::isfinite)(k) || !((k == 0) || (k == 1)))
{
*result = policies::raise_domain_error<RealType>(
function,
"Number of successes argument is %1%, but must be 0 or 1 !", k, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_dist_and_prob(const char* function, RealType p, RealType prob, RealType* result, const Policy& /* pol */)
{
if(check_dist(function, p, result, Policy()) && detail::check_probability(function, prob, result, Policy()) == false)
{
return false;
}
return true;
}
} // namespace bernoulli_detail
template <class RealType = double, class Policy = policies::policy<> >
class bernoulli_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
bernoulli_distribution(RealType p = 0.5) : m_p(p)
{ // Default probability = half suits 'fair' coin tossing
// where probability of heads == probability of tails.
RealType result; // of checks.
bernoulli_detail::check_dist(
"boost::math::bernoulli_distribution<%1%>::bernoulli_distribution",
m_p,
&result, Policy());
} // bernoulli_distribution constructor.
RealType success_fraction() const
{ // Probability.
return m_p;
}
private:
RealType m_p; // success_fraction
}; // template <class RealType> class bernoulli_distribution
typedef bernoulli_distribution<double> bernoulli;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const bernoulli_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable k = {0, 1}.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, 1);
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const bernoulli_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable k = {0, 1}.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
return std::pair<RealType, RealType>(0, 1);
}
template <class RealType, class Policy>
inline RealType mean(const bernoulli_distribution<RealType, Policy>& dist)
{ // Mean of bernoulli distribution = p (n = 1).
return dist.success_fraction();
} // mean
// Rely on dereived_accessors quantile(half)
//template <class RealType>
//inline RealType median(const bernoulli_distribution<RealType, Policy>& dist)
//{ // Median of bernoulli distribution is not defined.
// return tools::domain_error<RealType>(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
//} // median
template <class RealType, class Policy>
inline RealType variance(const bernoulli_distribution<RealType, Policy>& dist)
{ // Variance of bernoulli distribution =p * q.
return dist.success_fraction() * (1 - dist.success_fraction());
} // variance
template <class RealType, class Policy>
RealType pdf(const bernoulli_distribution<RealType, Policy>& dist, const RealType& k)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
// Error check:
RealType result; // of checks.
if(false == bernoulli_detail::check_dist_and_k(
"boost::math::pdf(bernoulli_distribution<%1%>, %1%)",
dist.success_fraction(), // 0 to 1
k, // 0 or 1
&result, Policy()))
{
return result;
}
// Assume k is integral.
if (k == 0)
{
return 1 - dist.success_fraction(); // 1 - p
}
else // k == 1
{
return dist.success_fraction(); // p
}
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const bernoulli_distribution<RealType, Policy>& dist, const RealType& k)
{ // Cumulative Distribution Function Bernoulli.
RealType p = dist.success_fraction();
// Error check:
RealType result;
if(false == bernoulli_detail::check_dist_and_k(
"boost::math::cdf(bernoulli_distribution<%1%>, %1%)",
p,
k,
&result, Policy()))
{
return result;
}
if (k == 0)
{
return 1 - p;
}
else
{ // k == 1
return 1;
}
} // bernoulli cdf
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<bernoulli_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function bernoulli.
RealType const& k = c.param;
bernoulli_distribution<RealType, Policy> const& dist = c.dist;
RealType p = dist.success_fraction();
// Error checks:
RealType result;
if(false == bernoulli_detail::check_dist_and_k(
"boost::math::cdf(bernoulli_distribution<%1%>, %1%)",
p,
k,
&result, Policy()))
{
return result;
}
if (k == 0)
{
return p;
}
else
{ // k == 1
return 0;
}
} // bernoulli cdf complement
template <class RealType, class Policy>
inline RealType quantile(const bernoulli_distribution<RealType, Policy>& dist, const RealType& p)
{ // Quantile or Percent Point Bernoulli function.
// Return the number of expected successes k either 0 or 1.
// for a given probability p.
RealType result; // of error checks:
if(false == bernoulli_detail::check_dist_and_prob(
"boost::math::quantile(bernoulli_distribution<%1%>, %1%)",
dist.success_fraction(),
p,
&result, Policy()))
{
return result;
}
if (p <= (1 - dist.success_fraction()))
{ // p <= pdf(dist, 0) == cdf(dist, 0)
return 0;
}
else
{
return 1;
}
} // quantile
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<bernoulli_distribution<RealType, Policy>, RealType>& c)
{ // Quantile or Percent Point bernoulli function.
// Return the number of expected successes k for a given
// complement of the probability q.
//
// Error checks:
RealType q = c.param;
const bernoulli_distribution<RealType, Policy>& dist = c.dist;
RealType result;
if(false == bernoulli_detail::check_dist_and_prob(
"boost::math::quantile(bernoulli_distribution<%1%>, %1%)",
dist.success_fraction(),
q,
&result, Policy()))
{
return result;
}
if (q <= 1 - dist.success_fraction())
{ // // q <= cdf(complement(dist, 0)) == pdf(dist, 0)
return 1;
}
else
{
return 0;
}
} // quantile complemented.
template <class RealType, class Policy>
inline RealType mode(const bernoulli_distribution<RealType, Policy>& dist)
{
return static_cast<RealType>((dist.success_fraction() <= 0.5) ? 0 : 1); // p = 0.5 can be 0 or 1
}
template <class RealType, class Policy>
inline RealType skewness(const bernoulli_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING; // Aid ADL for sqrt.
RealType p = dist.success_fraction();
return (1 - 2 * p) / sqrt(p * (1 - p));
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const bernoulli_distribution<RealType, Policy>& dist)
{
RealType p = dist.success_fraction();
// Note Wolfram says this is kurtosis in text, but gamma2 is the kurtosis excess,
// and Wikipedia also says this is the kurtosis excess formula.
// return (6 * p * p - 6 * p + 1) / (p * (1 - p));
// But Wolfram kurtosis article gives this simpler formula for kurtosis excess:
return 1 / (1 - p) + 1/p -6;
}
template <class RealType, class Policy>
inline RealType kurtosis(const bernoulli_distribution<RealType, Policy>& dist)
{
RealType p = dist.success_fraction();
return 1 / (1 - p) + 1/p -6 + 3;
// Simpler than:
// return (6 * p * p - 6 * p + 1) / (p * (1 - p)) + 3;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_MATH_SPECIAL_BERNOULLI_HPP

View File

@@ -0,0 +1,544 @@
// boost\math\distributions\beta.hpp
// Copyright John Maddock 2006.
// Copyright Paul A. Bristow 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)
// http://en.wikipedia.org/wiki/Beta_distribution
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366h.htm
// http://mathworld.wolfram.com/BetaDistribution.html
// The Beta Distribution is a continuous probability distribution.
// The beta distribution is used to model events which are constrained to take place
// within an interval defined by maxima and minima,
// so is used extensively in PERT and other project management systems
// to describe the time to completion.
// The cdf of the beta distribution is used as a convenient way
// of obtaining the sum over a set of binomial outcomes.
// The beta distribution is also used in Bayesian statistics.
#ifndef BOOST_MATH_DIST_BETA_HPP
#define BOOST_MATH_DIST_BETA_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/beta.hpp> // for beta.
#include <boost/math/distributions/complement.hpp> // complements.
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
#include <boost/math/tools/roots.hpp> // for root finding.
#if defined (BOOST_MSVC)
# pragma warning(push)
# pragma warning(disable: 4702) // unreachable code
// in domain_error_imp in error_handling
#endif
#include <utility>
namespace boost
{
namespace math
{
namespace beta_detail
{
// Common error checking routines for beta distribution functions:
template <class RealType, class Policy>
inline bool check_alpha(const char* function, const RealType& alpha, RealType* result, const Policy& pol)
{
if(!(boost::math::isfinite)(alpha) || (alpha <= 0))
{
*result = policies::raise_domain_error<RealType>(
function,
"Alpha argument is %1%, but must be > 0 !", alpha, pol);
return false;
}
return true;
} // bool check_alpha
template <class RealType, class Policy>
inline bool check_beta(const char* function, const RealType& beta, RealType* result, const Policy& pol)
{
if(!(boost::math::isfinite)(beta) || (beta <= 0))
{
*result = policies::raise_domain_error<RealType>(
function,
"Beta argument is %1%, but must be > 0 !", beta, pol);
return false;
}
return true;
} // bool check_beta
template <class RealType, class Policy>
inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol)
{
if((p < 0) || (p > 1) || !(boost::math::isfinite)(p))
{
*result = policies::raise_domain_error<RealType>(
function,
"Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol);
return false;
}
return true;
} // bool check_prob
template <class RealType, class Policy>
inline bool check_x(const char* function, const RealType& x, RealType* result, const Policy& pol)
{
if(!(boost::math::isfinite)(x) || (x < 0) || (x > 1))
{
*result = policies::raise_domain_error<RealType>(
function,
"x argument is %1%, but must be >= 0 and <= 1 !", x, pol);
return false;
}
return true;
} // bool check_x
template <class RealType, class Policy>
inline bool check_dist(const char* function, const RealType& alpha, const RealType& beta, RealType* result, const Policy& pol)
{ // Check both alpha and beta.
return check_alpha(function, alpha, result, pol)
&& check_beta(function, beta, result, pol);
} // bool check_dist
template <class RealType, class Policy>
inline bool check_dist_and_x(const char* function, const RealType& alpha, const RealType& beta, RealType x, RealType* result, const Policy& pol)
{
return check_dist(function, alpha, beta, result, pol)
&& check_x(function, x, result, pol);
} // bool check_dist_and_x
template <class RealType, class Policy>
inline bool check_dist_and_prob(const char* function, const RealType& alpha, const RealType& beta, RealType p, RealType* result, const Policy& pol)
{
return check_dist(function, alpha, beta, result, pol)
&& check_prob(function, p, result, pol);
} // bool check_dist_and_prob
template <class RealType, class Policy>
inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol)
{
if(!(boost::math::isfinite)(mean) || (mean <= 0))
{
*result = policies::raise_domain_error<RealType>(
function,
"mean argument is %1%, but must be > 0 !", mean, pol);
return false;
}
return true;
} // bool check_mean
template <class RealType, class Policy>
inline bool check_variance(const char* function, const RealType& variance, RealType* result, const Policy& pol)
{
if(!(boost::math::isfinite)(variance) || (variance <= 0))
{
*result = policies::raise_domain_error<RealType>(
function,
"variance argument is %1%, but must be > 0 !", variance, pol);
return false;
}
return true;
} // bool check_variance
} // namespace beta_detail
// typedef beta_distribution<double> beta;
// is deliberately NOT included to avoid a name clash with the beta function.
// Use beta_distribution<> mybeta(...) to construct type double.
template <class RealType = double, class Policy = policies::policy<> >
class beta_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
beta_distribution(RealType alpha = 1, RealType beta = 1) : m_alpha(alpha), m_beta(beta)
{
RealType result;
beta_detail::check_dist(
"boost::math::beta_distribution<%1%>::beta_distribution",
m_alpha,
m_beta,
&result, Policy());
} // beta_distribution constructor.
// Accessor functions:
RealType alpha() const
{
return m_alpha;
}
RealType beta() const
{ // .
return m_beta;
}
// Estimation of the alpha & beta parameters.
// http://en.wikipedia.org/wiki/Beta_distribution
// gives formulae in section on parameter estimation.
// Also NIST EDA page 3 & 4 give the same.
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366h.htm
// http://www.epi.ucdavis.edu/diagnostictests/betabuster.html
static RealType find_alpha(
RealType mean, // Expected value of mean.
RealType variance) // Expected value of variance.
{
static const char* function = "boost::math::beta_distribution<%1%>::find_alpha";
RealType result; // of error checks.
if(false ==
beta_detail::check_mean(
function, mean, &result, Policy())
&&
beta_detail::check_variance(
function, variance, &result, Policy())
)
{
return result;
}
return mean * (( (mean * (1 - mean)) / variance)- 1);
} // RealType find_alpha
static RealType find_beta(
RealType mean, // Expected value of mean.
RealType variance) // Expected value of variance.
{
static const char* function = "boost::math::beta_distribution<%1%>::find_beta";
RealType result; // of error checks.
if(false ==
beta_detail::check_mean(
function, mean, &result, Policy())
&&
beta_detail::check_variance(
function, variance, &result, Policy())
)
{
return result;
}
return (1 - mean) * (((mean * (1 - mean)) /variance)-1);
} // RealType find_beta
// Estimate alpha & beta from either alpha or beta, and x and probability.
// Uses for these parameter estimators are unclear.
static RealType find_alpha(
RealType beta, // from beta.
RealType x, // x.
RealType probability) // cdf
{
static const char* function = "boost::math::beta_distribution<%1%>::find_alpha";
RealType result; // of error checks.
if(false ==
beta_detail::check_prob(
function, probability, &result, Policy())
&&
beta_detail::check_beta(
function, beta, &result, Policy())
&&
beta_detail::check_x(
function, x, &result, Policy())
)
{
return result;
}
return ibeta_inva(beta, x, probability, Policy());
} // RealType find_alpha(beta, a, probability)
static RealType find_beta(
// ibeta_invb(T b, T x, T p); (alpha, x, cdf,)
RealType alpha, // alpha.
RealType x, // probability x.
RealType probability) // probability cdf.
{
static const char* function = "boost::math::beta_distribution<%1%>::find_beta";
RealType result; // of error checks.
if(false ==
beta_detail::check_prob(
function, probability, &result, Policy())
&&
beta_detail::check_alpha(
function, alpha, &result, Policy())
&&
beta_detail::check_x(
function, x, &result, Policy())
)
{
return result;
}
return ibeta_invb(alpha, x, probability, Policy());
} // RealType find_beta(alpha, x, probability)
private:
RealType m_alpha; // Two parameters of the beta distribution.
RealType m_beta;
}; // template <class RealType, class Policy> class beta_distribution
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const beta_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, 1);
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const beta_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
return std::pair<RealType, RealType>(0, 1);
}
template <class RealType, class Policy>
inline RealType mean(const beta_distribution<RealType, Policy>& dist)
{ // Mean of beta distribution = np.
return dist.alpha() / (dist.alpha() + dist.beta());
} // mean
template <class RealType, class Policy>
inline RealType variance(const beta_distribution<RealType, Policy>& dist)
{ // Variance of beta distribution = np(1-p).
RealType a = dist.alpha();
RealType b = dist.beta();
return (a * b) / ((a + b ) * (a + b) * (a + b + 1));
} // variance
template <class RealType, class Policy>
inline RealType mode(const beta_distribution<RealType, Policy>& dist)
{
static const char* function = "boost::math::mode(beta_distribution<%1%> const&)";
RealType result;
if ((dist.alpha() <= 1))
{
result = policies::raise_domain_error<RealType>(
function,
"mode undefined for alpha = %1%, must be > 1!", dist.alpha(), Policy());
return result;
}
if ((dist.beta() <= 1))
{
result = policies::raise_domain_error<RealType>(
function,
"mode undefined for beta = %1%, must be > 1!", dist.beta(), Policy());
return result;
}
RealType a = dist.alpha();
RealType b = dist.beta();
return (a-1) / (a + b - 2);
} // mode
//template <class RealType, class Policy>
//inline RealType median(const beta_distribution<RealType, Policy>& dist)
//{ // Median of beta distribution is not defined.
// return tools::domain_error<RealType>(function, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
//} // median
//But WILL be provided by the derived accessor as quantile(0.5).
template <class RealType, class Policy>
inline RealType skewness(const beta_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // ADL of std functions.
RealType a = dist.alpha();
RealType b = dist.beta();
return (2 * (b-a) * sqrt(a + b + 1)) / ((a + b + 2) * sqrt(a * b));
} // skewness
template <class RealType, class Policy>
inline RealType kurtosis_excess(const beta_distribution<RealType, Policy>& dist)
{
RealType a = dist.alpha();
RealType b = dist.beta();
RealType a_2 = a * a;
RealType n = 6 * (a_2 * a - a_2 * (2 * b - 1) + b * b * (b + 1) - 2 * a * b * (b + 2));
RealType d = a * b * (a + b + 2) * (a + b + 3);
return n / d;
} // kurtosis_excess
template <class RealType, class Policy>
inline RealType kurtosis(const beta_distribution<RealType, Policy>& dist)
{
return 3 + kurtosis_excess(dist);
} // kurtosis
template <class RealType, class Policy>
inline RealType pdf(const beta_distribution<RealType, Policy>& dist, const RealType& x)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
static const char* function = "boost::math::pdf(beta_distribution<%1%> const&, %1%)";
BOOST_MATH_STD_USING // for ADL of std functions
RealType a = dist.alpha();
RealType b = dist.beta();
// Argument checks:
RealType result;
if(false == beta_detail::check_dist_and_x(
function,
a, b, x,
&result, Policy()))
{
return result;
}
using boost::math::beta;
return ibeta_derivative(a, b, x, Policy());
} // pdf
template <class RealType, class Policy>
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
static const char* function = "boost::math::cdf(beta_distribution<%1%> const&, %1%)";
RealType a = dist.alpha();
RealType b = dist.beta();
// Argument checks:
RealType result;
if(false == beta_detail::check_dist_and_x(
function,
a, b, x,
&result, Policy()))
{
return result;
}
// Special cases:
if (x == 0)
{
return 0;
}
else if (x == 1)
{
return 1;
}
return ibeta(a, b, x, Policy());
} // beta cdf
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<beta_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function beta.
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(beta_distribution<%1%> const&, %1%)";
RealType const& x = c.param;
beta_distribution<RealType, Policy> const& dist = c.dist;
RealType a = dist.alpha();
RealType b = dist.beta();
// Argument checks:
RealType result;
if(false == beta_detail::check_dist_and_x(
function,
a, b, x,
&result, Policy()))
{
return result;
}
if (x == 0)
{
return 1;
}
else if (x == 1)
{
return 0;
}
// Calculate cdf beta using the incomplete beta function.
// Use of ibeta here prevents cancellation errors in calculating
// 1 - x if x is very small, perhaps smaller than machine epsilon.
return ibetac(a, b, x, Policy());
} // beta cdf
template <class RealType, class Policy>
inline RealType quantile(const beta_distribution<RealType, Policy>& dist, const RealType& p)
{ // Quantile or Percent Point beta function or
// Inverse Cumulative probability distribution function CDF.
// Return x (0 <= x <= 1),
// for a given probability p (0 <= p <= 1).
// These functions take a probability as an argument
// and return a value such that the probability that a random variable x
// will be less than or equal to that value
// is whatever probability you supplied as an argument.
static const char* function = "boost::math::quantile(beta_distribution<%1%> const&, %1%)";
RealType result; // of argument checks:
RealType a = dist.alpha();
RealType b = dist.beta();
if(false == beta_detail::check_dist_and_prob(
function,
a, b, p,
&result, Policy()))
{
return result;
}
// Special cases:
if (p == 0)
{
return 0;
}
if (p == 1)
{
return 1;
}
return ibeta_inv(a, b, p, static_cast<RealType*>(0), Policy());
} // quantile
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<beta_distribution<RealType, Policy>, RealType>& c)
{ // Complement Quantile or Percent Point beta function .
// Return the number of expected x for a given
// complement of the probability q.
static const char* function = "boost::math::quantile(beta_distribution<%1%> const&, %1%)";
//
// Error checks:
RealType q = c.param;
const beta_distribution<RealType, Policy>& dist = c.dist;
RealType result;
RealType a = dist.alpha();
RealType b = dist.beta();
if(false == beta_detail::check_dist_and_prob(
function,
a,
b,
q,
&result, Policy()))
{
return result;
}
// Special cases:
if(q == 1)
{
return 0;
}
if(q == 0)
{
return 1;
}
return ibetac_inv(a, b, q, static_cast<RealType*>(0), Policy());
} // Quantile Complement
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#if defined (BOOST_MSVC)
# pragma warning(pop)
#endif
#endif // BOOST_MATH_DIST_BETA_HPP

View File

@@ -0,0 +1,724 @@
// boost\math\distributions\binomial.hpp
// 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)
// http://en.wikipedia.org/wiki/binomial_distribution
// Binomial distribution is the discrete probability distribution of
// the number (k) of successes, in a sequence of
// n independent (yes or no, success or failure) Bernoulli trials.
// It expresses the probability of a number of events occurring in a fixed time
// if these events occur with a known average rate (probability of success),
// and are independent of the time since the last event.
// The number of cars that pass through a certain point on a road during a given period of time.
// The number of spelling mistakes a secretary makes while typing a single page.
// The number of phone calls at a call center per minute.
// The number of times a web server is accessed per minute.
// The number of light bulbs that burn out in a certain amount of time.
// The number of roadkill found per unit length of road
// http://en.wikipedia.org/wiki/binomial_distribution
// Given a sample of N measured values k[i],
// we wish to estimate the value of the parameter x (mean)
// of the binomial population from which the sample was drawn.
// To calculate the maximum likelihood value = 1/N sum i = 1 to N of k[i]
// Also may want a function for EXACTLY k.
// And probability that there are EXACTLY k occurrences is
// exp(-x) * pow(x, k) / factorial(k)
// where x is expected occurrences (mean) during the given interval.
// For example, if events occur, on average, every 4 min,
// and we are interested in number of events occurring in 10 min,
// then x = 10/4 = 2.5
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366i.htm
// The binomial distribution is used when there are
// exactly two mutually exclusive outcomes of a trial.
// These outcomes are appropriately labeled "success" and "failure".
// The binomial distribution is used to obtain
// the probability of observing x successes in N trials,
// with the probability of success on a single trial denoted by p.
// The binomial distribution assumes that p is fixed for all trials.
// P(x, p, n) = n!/(x! * (n-x)!) * p^x * (1-p)^(n-x)
// http://mathworld.wolfram.com/BinomialCoefficient.html
// The binomial coefficient (n; k) is the number of ways of picking
// k unordered outcomes from n possibilities,
// also known as a combination or combinatorial number.
// The symbols _nC_k and (n; k) are used to denote a binomial coefficient,
// and are sometimes read as "n choose k."
// (n; k) therefore gives the number of k-subsets possible out of a set of n distinct items.
// For example:
// The 2-subsets of {1,2,3,4} are the six pairs {1,2}, {1,3}, {1,4}, {2,3}, {2,4}, and {3,4}, so (4; 2)==6.
// http://functions.wolfram.com/GammaBetaErf/Binomial/ for evaluation.
// But note that the binomial distribution
// (like others including the poisson, negative binomial & Bernoulli)
// is strictly defined as a discrete function: only integral values of k are envisaged.
// However because of the method of calculation using a continuous gamma function,
// it is convenient to treat it as if a continous function,
// and permit non-integral values of k.
// To enforce the strict mathematical model, users should use floor or ceil functions
// on k outside this function to ensure that k is integral.
#ifndef BOOST_MATH_SPECIAL_BINOMIAL_HPP
#define BOOST_MATH_SPECIAL_BINOMIAL_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/beta.hpp> // for incomplete beta.
#include <boost/math/distributions/complement.hpp> // complements
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/distributions/detail/inv_discrete_quantile.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
#include <boost/math/tools/roots.hpp> // for root finding.
#include <utility>
namespace boost
{
namespace math
{
template <class RealType, class Policy>
class binomial_distribution;
namespace binomial_detail{
// common error checking routines for binomial distribution functions:
template <class RealType, class Policy>
inline bool check_N(const char* function, const RealType& N, RealType* result, const Policy& pol)
{
if((N < 0) || !(boost::math::isfinite)(N))
{
*result = policies::raise_domain_error<RealType>(
function,
"Number of Trials argument is %1%, but must be >= 0 !", N, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
{
if((p < 0) || (p > 1) || !(boost::math::isfinite)(p))
{
*result = policies::raise_domain_error<RealType>(
function,
"Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_dist(const char* function, const RealType& N, const RealType& p, RealType* result, const Policy& pol)
{
return check_success_fraction(
function, p, result, pol)
&& check_N(
function, N, result, pol);
}
template <class RealType, class Policy>
inline bool check_dist_and_k(const char* function, const RealType& N, const RealType& p, RealType k, RealType* result, const Policy& pol)
{
if(check_dist(function, N, p, result, pol) == false)
return false;
if((k < 0) || !(boost::math::isfinite)(k))
{
*result = policies::raise_domain_error<RealType>(
function,
"Number of Successes argument is %1%, but must be >= 0 !", k, pol);
return false;
}
if(k > N)
{
*result = policies::raise_domain_error<RealType>(
function,
"Number of Successes argument is %1%, but must be <= Number of Trials !", k, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_dist_and_prob(const char* function, const RealType& N, RealType p, RealType prob, RealType* result, const Policy& pol)
{
if(check_dist(function, N, p, result, pol) && detail::check_probability(function, prob, result, pol) == false)
return false;
return true;
}
template <class T, class Policy>
T inverse_binomial_cornish_fisher(T n, T sf, T p, T q, const Policy& pol)
{
BOOST_MATH_STD_USING
// mean:
T m = n * sf;
// standard deviation:
T sigma = sqrt(n * sf * (1 - sf));
// skewness
T sk = (1 - 2 * sf) / sigma;
// kurtosis:
// T k = (1 - 6 * sf * (1 - sf) ) / (n * sf * (1 - sf));
// 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(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 sqrt(tools::min_value<T>());
if(w > n)
return n;
return w;
}
template <class RealType, class Policy>
RealType quantile_imp(const binomial_distribution<RealType, Policy>& dist, const RealType& p, const RealType& q)
{ // Quantile or Percent Point Binomial function.
// Return the number of expected successes k,
// for a given probability p.
//
// Error checks:
BOOST_MATH_STD_USING // ADL of std names
RealType result;
RealType trials = dist.trials();
RealType success_fraction = dist.success_fraction();
if(false == binomial_detail::check_dist_and_prob(
"boost::math::quantile(binomial_distribution<%1%> const&, %1%)",
trials,
success_fraction,
p,
&result, Policy()))
{
return result;
}
// Special cases:
//
if(p == 0)
{ // There may actually be no answer to this question,
// since the probability of zero successes may be non-zero,
// but zero is the best we can do:
return 0;
}
if(p == 1)
{ // Probability of n or fewer successes is always one,
// so n is the most sensible answer here:
return trials;
}
if (p <= pow(1 - success_fraction, trials))
{ // p <= pdf(dist, 0) == cdf(dist, 0)
return 0; // So the only reasonable result is zero.
} // And root finder would fail otherwise.
// Solve for quantile numerically:
//
RealType guess = binomial_detail::inverse_binomial_cornish_fisher(trials, success_fraction, p, q, Policy());
RealType factor = 8;
if(trials > 100)
factor = 1.01f; // guess is pretty accurate
else if((trials > 10) && (trials - 1 > guess) && (guess > 3))
factor = 1.15f; // less accurate but OK.
else if(trials < 10)
{
// pretty inaccurate guess in this area:
if(guess > trials / 64)
{
guess = trials / 4;
factor = 2;
}
else
guess = trials / 1024;
}
else
factor = 2; // trials largish, but in far tails.
typedef typename Policy::discrete_quantile_type discrete_quantile_type;
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
return detail::inverse_discrete_quantile(
dist,
p,
q,
guess,
factor,
RealType(1),
discrete_quantile_type(),
max_iter);
} // quantile
}
template <class RealType = double, class Policy = policies::policy<> >
class binomial_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
binomial_distribution(RealType n = 1, RealType p = 0.5) : m_n(n), m_p(p)
{ // Default n = 1 is the Bernoulli distribution
// with equal probability of 'heads' or 'tails.
RealType r;
binomial_detail::check_dist(
"boost::math::binomial_distribution<%1%>::binomial_distribution",
m_n,
m_p,
&r, Policy());
} // binomial_distribution constructor.
RealType success_fraction() const
{ // Probability.
return m_p;
}
RealType trials() const
{ // Total number of trials.
return m_n;
}
enum interval_type{
clopper_pearson_exact_interval,
jeffreys_prior_interval
};
//
// Estimation of the success fraction parameter.
// The best estimate is actually simply successes/trials,
// these functions are used
// to obtain confidence intervals for the success fraction.
//
static RealType find_lower_bound_on_p(
RealType trials,
RealType successes,
RealType probability,
interval_type t = clopper_pearson_exact_interval)
{
static const char* function = "boost::math::binomial_distribution<%1%>::find_lower_bound_on_p";
// Error checks:
RealType result;
if(false == binomial_detail::check_dist_and_k(
function, trials, RealType(0), successes, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
function, trials, RealType(0), probability, &result, Policy()))
{ return result; }
if(successes == 0)
return 0;
// NOTE!!! The Clopper Pearson formula uses "successes" not
// "successes+1" as usual to get the lower bound,
// see http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
return (t == clopper_pearson_exact_interval) ? ibeta_inv(successes, trials - successes + 1, probability, static_cast<RealType*>(0), Policy())
: ibeta_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast<RealType*>(0), Policy());
}
static RealType find_upper_bound_on_p(
RealType trials,
RealType successes,
RealType probability,
interval_type t = clopper_pearson_exact_interval)
{
static const char* function = "boost::math::binomial_distribution<%1%>::find_upper_bound_on_p";
// Error checks:
RealType result;
if(false == binomial_detail::check_dist_and_k(
function, trials, RealType(0), successes, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
function, trials, RealType(0), probability, &result, Policy()))
{ return result; }
if(trials == successes)
return 1;
return (t == clopper_pearson_exact_interval) ? ibetac_inv(successes + 1, trials - successes, probability, static_cast<RealType*>(0), Policy())
: ibetac_inv(successes + 0.5f, trials - successes + 0.5f, probability, static_cast<RealType*>(0), Policy());
}
// Estimate number of trials parameter:
//
// "How many trials do I need to be P% sure of seeing k events?"
// or
// "How many trials can I have to be P% sure of seeing fewer than k events?"
//
static RealType find_minimum_number_of_trials(
RealType k, // number of events
RealType p, // success fraction
RealType alpha) // risk level
{
static const char* function = "boost::math::binomial_distribution<%1%>::find_minimum_number_of_trials";
// Error checks:
RealType result;
if(false == binomial_detail::check_dist_and_k(
function, k, p, k, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
function, k, p, alpha, &result, Policy()))
{ return result; }
result = ibetac_invb(k + 1, p, alpha, Policy()); // returns n - k
return result + k;
}
static RealType find_maximum_number_of_trials(
RealType k, // number of events
RealType p, // success fraction
RealType alpha) // risk level
{
static const char* function = "boost::math::binomial_distribution<%1%>::find_maximum_number_of_trials";
// Error checks:
RealType result;
if(false == binomial_detail::check_dist_and_k(
function, k, p, k, &result, Policy())
&&
binomial_detail::check_dist_and_prob(
function, k, p, alpha, &result, Policy()))
{ return result; }
result = ibeta_invb(k + 1, p, alpha, Policy()); // returns n - k
return result + k;
}
private:
RealType m_n; // Not sure if this shouldn't be an int?
RealType m_p; // success_fraction
}; // template <class RealType, class Policy> class binomial_distribution
typedef binomial_distribution<> binomial;
// typedef binomial_distribution<double> binomial;
// IS now included since no longer a name clash with function binomial.
//typedef binomial_distribution<double> binomial; // Reserved name of type double.
template <class RealType, class Policy>
const std::pair<RealType, RealType> range(const binomial_distribution<RealType, Policy>& dist)
{ // Range of permissible values for random variable k.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(static_cast<RealType>(0), dist.trials());
}
template <class RealType, class Policy>
const std::pair<RealType, RealType> support(const binomial_distribution<RealType, Policy>& dist)
{ // Range of supported values for random variable k.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
return std::pair<RealType, RealType>(0, dist.trials());
}
template <class RealType, class Policy>
inline RealType mean(const binomial_distribution<RealType, Policy>& dist)
{ // Mean of Binomial distribution = np.
return dist.trials() * dist.success_fraction();
} // mean
template <class RealType, class Policy>
inline RealType variance(const binomial_distribution<RealType, Policy>& dist)
{ // Variance of Binomial distribution = np(1-p).
return dist.trials() * dist.success_fraction() * (1 - dist.success_fraction());
} // variance
template <class RealType, class Policy>
RealType pdf(const binomial_distribution<RealType, Policy>& dist, const RealType& k)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
BOOST_MATH_STD_USING // for ADL of std functions
RealType n = dist.trials();
// Error check:
RealType result;
if(false == binomial_detail::check_dist_and_k(
"boost::math::pdf(binomial_distribution<%1%> const&, %1%)",
n,
dist.success_fraction(),
k,
&result, Policy()))
{
return result;
}
// Special cases of success_fraction, regardless of k successes and regardless of n trials.
if (dist.success_fraction() == 0)
{ // probability of zero successes is 1:
return static_cast<RealType>(k == 0 ? 1 : 0);
}
if (dist.success_fraction() == 1)
{ // probability of n successes is 1:
return static_cast<RealType>(k == n ? 1 : 0);
}
// k argument may be integral, signed, or unsigned, or floating point.
// If necessary, it has already been promoted from an integral type.
if (n == 0)
{
return 1; // Probability = 1 = certainty.
}
if (k == 0)
{ // binomial coeffic (n 0) = 1,
// n ^ 0 = 1
return pow(1 - dist.success_fraction(), n);
}
if (k == n)
{ // binomial coeffic (n n) = 1,
// n ^ 0 = 1
return pow(dist.success_fraction(), k); // * pow((1 - dist.success_fraction()), (n - k)) = 1
}
// Probability of getting exactly k successes
// if C(n, k) is the binomial coefficient then:
//
// f(k; n,p) = C(n, k) * p^k * (1-p)^(n-k)
// = (n!/(k!(n-k)!)) * p^k * (1-p)^(n-k)
// = (tgamma(n+1) / (tgamma(k+1)*tgamma(n-k+1))) * p^k * (1-p)^(n-k)
// = p^k (1-p)^(n-k) / (beta(k+1, n-k+1) * (n+1))
// = ibeta_derivative(k+1, n-k+1, p) / (n+1)
//
using boost::math::ibeta_derivative; // a, b, x
return ibeta_derivative(k+1, n-k+1, dist.success_fraction(), Policy()) / (n+1);
} // pdf
template <class RealType, class Policy>
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.
// If necessary, it has already been promoted from an integral type.
// Returns the sum of the terms 0 through k of the Binomial Probability Density/Mass:
//
// i=k
// -- ( n ) i n-i
// > | | p (1-p)
// -- ( i )
// i=0
// The terms are not summed directly instead
// the incomplete beta integral is employed,
// according to the formula:
// P = I[1-p]( n-k, k+1).
// = 1 - I[p](k + 1, n - k)
BOOST_MATH_STD_USING // for ADL of std functions
RealType n = dist.trials();
RealType p = dist.success_fraction();
// Error check:
RealType result;
if(false == binomial_detail::check_dist_and_k(
"boost::math::cdf(binomial_distribution<%1%> const&, %1%)",
n,
p,
k,
&result, Policy()))
{
return result;
}
if (k == n)
{
return 1;
}
// Special cases, regardless of k.
if (p == 0)
{ // This need explanation:
// the pdf is zero for all cases except when k == 0.
// For zero p the probability of zero successes is one.
// Therefore the cdf is always 1:
// the probability of k or *fewer* successes is always 1
// if there are never any successes!
return 1;
}
if (p == 1)
{ // This is correct but needs explanation:
// when k = 1
// all the cdf and pdf values are zero *except* when k == n,
// and that case has been handled above already.
return 0;
}
//
// P = I[1-p](n - k, k + 1)
// = 1 - I[p](k + 1, n - k)
// Use of ibetac here prevents cancellation errors in calculating
// 1-p if p is very small, perhaps smaller than machine epsilon.
//
// Note that we do not use a finite sum here, since the incomplete
// beta uses a finite sum internally for integer arguments, so
// we'll just let it take care of the necessary logic.
//
return ibetac(k + 1, n - k, p, Policy());
} // binomial cdf
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<binomial_distribution<RealType, Policy>, RealType>& c)
{ // Complemented 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.
// If necessary, it has already been promoted from an integral type.
// Returns the sum of the terms k+1 through n of the Binomial Probability Density/Mass:
//
// i=n
// -- ( n ) i n-i
// > | | p (1-p)
// -- ( i )
// i=k+1
// The terms are not summed directly instead
// the incomplete beta integral is employed,
// according to the formula:
// Q = 1 -I[1-p]( n-k, k+1).
// = I[p](k + 1, n - k)
BOOST_MATH_STD_USING // for ADL of std functions
RealType const& k = c.param;
binomial_distribution<RealType, Policy> const& dist = c.dist;
RealType n = dist.trials();
RealType p = dist.success_fraction();
// Error checks:
RealType result;
if(false == binomial_detail::check_dist_and_k(
"boost::math::cdf(binomial_distribution<%1%> const&, %1%)",
n,
p,
k,
&result, Policy()))
{
return result;
}
if (k == n)
{ // Probability of greater than n successes is necessarily zero:
return 0;
}
// Special cases, regardless of k.
if (p == 0)
{
// This need explanation: the pdf is zero for all
// cases except when k == 0. For zero p the probability
// of zero successes is one. Therefore the cdf is always
// 1: the probability of *more than* k successes is always 0
// if there are never any successes!
return 0;
}
if (p == 1)
{
// This needs explanation, when p = 1
// we always have n successes, so the probability
// of more than k successes is 1 as long as k < n.
// The k == n case has already been handled above.
return 1;
}
//
// Calculate cdf binomial using the incomplete beta function.
// Q = 1 -I[1-p](n - k, k + 1)
// = I[p](k + 1, n - k)
// Use of ibeta here prevents cancellation errors in calculating
// 1-p if p is very small, perhaps smaller than machine epsilon.
//
// Note that we do not use a finite sum here, since the incomplete
// beta uses a finite sum internally for integer arguments, so
// we'll just let it take care of the necessary logic.
//
return ibeta(k + 1, n - k, p, Policy());
} // binomial cdf
template <class RealType, class Policy>
inline RealType quantile(const binomial_distribution<RealType, Policy>& dist, const RealType& p)
{
return binomial_detail::quantile_imp(dist, p, 1-p);
} // quantile
template <class RealType, class Policy>
RealType quantile(const complemented2_type<binomial_distribution<RealType, Policy>, RealType>& c)
{
return binomial_detail::quantile_imp(c.dist, 1-c.param, c.param);
} // quantile
template <class RealType, class Policy>
inline RealType mode(const binomial_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // ADL of std functions.
RealType p = dist.success_fraction();
RealType n = dist.trials();
return floor(p * (n + 1));
}
template <class RealType, class Policy>
inline RealType median(const binomial_distribution<RealType, Policy>& dist)
{ // Bounds for the median of the negative binomial distribution
// VAN DE VEN R. ; WEBER N. C. ;
// Univ. Sydney, school mathematics statistics, Sydney N.S.W. 2006, AUSTRALIE
// Metrika (Metrika) ISSN 0026-1335 CODEN MTRKA8
// 1993, vol. 40, no3-4, pp. 185-189 (4 ref.)
// Bounds for median and 50 percetage point of binomial and negative binomial distribution
// Metrika, ISSN 0026-1335 (Print) 1435-926X (Online)
// Volume 41, Number 1 / December, 1994, DOI 10.1007/BF01895303
BOOST_MATH_STD_USING // ADL of std functions.
RealType p = dist.success_fraction();
RealType n = dist.trials();
// Wikipedia says one of floor(np) -1, floor (np), floor(np) +1
return floor(p * n); // Chose the middle value.
}
template <class RealType, class Policy>
inline RealType skewness(const binomial_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // ADL of std functions.
RealType p = dist.success_fraction();
RealType n = dist.trials();
return (1 - 2 * p) / sqrt(n * p * (1 - p));
}
template <class RealType, class Policy>
inline RealType kurtosis(const binomial_distribution<RealType, Policy>& dist)
{
RealType p = dist.success_fraction();
RealType n = dist.trials();
return 3 - 6 / n + 1 / (n * p * (1 - p));
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const binomial_distribution<RealType, Policy>& dist)
{
RealType p = dist.success_fraction();
RealType q = 1 - p;
RealType n = dist.trials();
return (1 - 6 * p * q) / (n * p * q);
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_MATH_SPECIAL_BINOMIAL_HPP

View File

@@ -0,0 +1,347 @@
// Copyright John Maddock 2006, 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_STATS_CAUCHY_HPP
#define BOOST_STATS_CAUCHY_HPP
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant
#endif
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#include <utility>
namespace boost{ namespace math
{
template <class RealType, class Policy>
class cauchy_distribution;
namespace detail
{
template <class RealType, class Policy>
RealType cdf_imp(const cauchy_distribution<RealType, Policy>& dist, const RealType& x, bool complement)
{
//
// This calculates the cdf of the Cauchy distribution and/or its complement.
//
// The usual formula for the Cauchy cdf is:
//
// cdf = 0.5 + atan(x)/pi
//
// But that suffers from cancellation error as x -> -INF.
//
// Recall that for x < 0:
//
// atan(x) = -pi/2 - atan(1/x)
//
// Substituting into the above we get:
//
// CDF = -atan(1/x) ; x < 0
//
// So the proceedure is to calculate the cdf for -fabs(x)
// using the above formula, and then subtract from 1 when required
// to get the result.
//
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(cauchy<%1%>&, %1%)";
RealType result;
RealType location = dist.location();
RealType scale = dist.scale();
if(false == detail::check_location(function, location, &result, Policy()))
{
return result;
}
if(false == detail::check_scale(function, scale, &result, Policy()))
{
return result;
}
if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
{ // cdf +infinity is unity.
return static_cast<RealType>((complement) ? 0 : 1);
}
if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
{ // cdf -infinity is zero.
return static_cast<RealType>((complement) ? 1 : 0);
}
if(false == detail::check_x(function, x, &result, Policy()))
{ // Catches x == NaN
return result;
}
RealType mx = -fabs((x - location) / scale); // scale is > 0
if(mx > -tools::epsilon<RealType>() / 8)
{ // special case first: x extremely close to location.
return 0.5;
}
result = -atan(1 / mx) / constants::pi<RealType>();
return (((x > location) != complement) ? 1 - result : result);
} // cdf
template <class RealType, class Policy>
RealType quantile_imp(
const cauchy_distribution<RealType, Policy>& dist,
const RealType& p,
bool complement)
{
// This routine implements the quantile for the Cauchy distribution,
// the value p may be the probability, or its complement if complement=true.
//
// The procedure first performs argument reduction on p to avoid error
// when calculating the tangent, then calulates the distance from the
// mid-point of the distribution. This is either added or subtracted
// from the location parameter depending on whether `complement` is true.
//
static const char* function = "boost::math::quantile(cauchy<%1%>&, %1%)";
BOOST_MATH_STD_USING // for ADL of std functions
RealType result;
RealType location = dist.location();
RealType scale = dist.scale();
if(false == detail::check_location(function, location, &result, Policy()))
{
return result;
}
if(false == detail::check_scale(function, scale, &result, Policy()))
{
return result;
}
if(false == detail::check_probability(function, p, &result, Policy()))
{
return result;
}
// Special cases:
if(p == 1)
{
return (complement ? -1 : 1) * policies::raise_overflow_error<RealType>(function, 0, Policy());
}
if(p == 0)
{
return (complement ? 1 : -1) * policies::raise_overflow_error<RealType>(function, 0, Policy());
}
RealType P = p - floor(p); // argument reduction of p:
if(P > 0.5)
{
P = P - 1;
}
if(P == 0.5) // special case:
{
return location;
}
result = -scale / tan(constants::pi<RealType>() * P);
return complement ? location - result : location + result;
} // quantile
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class cauchy_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
cauchy_distribution(RealType location = 0, RealType scale = 1)
: m_a(location), m_hg(scale)
{
static const char* function = "boost::math::cauchy_distribution<%1%>::cauchy_distribution";
RealType result;
detail::check_location(function, location, &result, Policy());
detail::check_scale(function, scale, &result, Policy());
} // cauchy_distribution
RealType location()const
{
return m_a;
}
RealType scale()const
{
return m_hg;
}
private:
RealType m_a; // The location, this is the median of the distribution.
RealType m_hg; // The scale )or shape), this is the half width at half height.
};
typedef cauchy_distribution<double> cauchy;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const cauchy_distribution<RealType, Policy>&)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + infinity.
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const cauchy_distribution<RealType, Policy>& )
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
return std::pair<RealType, RealType>(-tools::max_value<RealType>(), tools::max_value<RealType>()); // - to + infinity.
}
template <class RealType, class Policy>
inline RealType pdf(const cauchy_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::pdf(cauchy<%1%>&, %1%)";
RealType result;
RealType location = dist.location();
RealType scale = dist.scale();
if(false == detail::check_scale("boost::math::pdf(cauchy<%1%>&, %1%)", scale, &result, Policy()))
{
return result;
}
if(false == detail::check_location("boost::math::pdf(cauchy<%1%>&, %1%)", location, &result, Policy()))
{
return result;
}
if((boost::math::isinf)(x))
{
return 0; // pdf + and - infinity is zero.
}
// These produce MSVC 4127 warnings, so the above used instead.
//if(std::numeric_limits<RealType>::has_infinity && abs(x) == std::numeric_limits<RealType>::infinity())
//{ // pdf + and - infinity is zero.
// return 0;
//}
if(false == detail::check_x(function, x, &result, Policy()))
{ // Catches x = NaN
return result;
}
RealType xs = (x - location) / scale;
result = 1 / (constants::pi<RealType>() * scale * (1 + xs * xs));
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const cauchy_distribution<RealType, Policy>& dist, const RealType& x)
{
return detail::cdf_imp(dist, x, false);
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const cauchy_distribution<RealType, Policy>& dist, const RealType& p)
{
return detail::quantile_imp(dist, p, false);
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<cauchy_distribution<RealType, Policy>, RealType>& c)
{
return detail::cdf_imp(c.dist, c.param, true);
} // cdf complement
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<cauchy_distribution<RealType, Policy>, RealType>& c)
{
return detail::quantile_imp(c.dist, c.param, true);
} // quantile complement
template <class RealType, class Policy>
inline RealType mean(const cauchy_distribution<RealType, Policy>&)
{ // There is no mean:
typedef typename Policy::assert_undefined_type assert_type;
BOOST_STATIC_ASSERT(assert_type::value == 0);
return policies::raise_domain_error<RealType>(
"boost::math::mean(cauchy<%1%>&)",
"The Cauchy distribution does not have a mean: "
"the only possible return value is %1%.",
std::numeric_limits<RealType>::quiet_NaN(), Policy());
}
template <class RealType, class Policy>
inline RealType variance(const cauchy_distribution<RealType, Policy>& /*dist*/)
{
// There is no variance:
typedef typename Policy::assert_undefined_type assert_type;
BOOST_STATIC_ASSERT(assert_type::value == 0);
return policies::raise_domain_error<RealType>(
"boost::math::variance(cauchy<%1%>&)",
"The Cauchy distribution does not have a variance: "
"the only possible return value is %1%.",
std::numeric_limits<RealType>::quiet_NaN(), Policy());
}
template <class RealType, class Policy>
inline RealType mode(const cauchy_distribution<RealType, Policy>& dist)
{
return dist.location();
}
template <class RealType, class Policy>
inline RealType median(const cauchy_distribution<RealType, Policy>& dist)
{
return dist.location();
}
template <class RealType, class Policy>
inline RealType skewness(const cauchy_distribution<RealType, Policy>& /*dist*/)
{
// There is no skewness:
typedef typename Policy::assert_undefined_type assert_type;
BOOST_STATIC_ASSERT(assert_type::value == 0);
return policies::raise_domain_error<RealType>(
"boost::math::skewness(cauchy<%1%>&)",
"The Cauchy distribution does not have a skewness: "
"the only possible return value is %1%.",
std::numeric_limits<RealType>::quiet_NaN(), Policy()); // infinity?
}
template <class RealType, class Policy>
inline RealType kurtosis(const cauchy_distribution<RealType, Policy>& /*dist*/)
{
// There is no kurtosis:
typedef typename Policy::assert_undefined_type assert_type;
BOOST_STATIC_ASSERT(assert_type::value == 0);
return policies::raise_domain_error<RealType>(
"boost::math::kurtosis(cauchy<%1%>&)",
"The Cauchy distribution does not have a kurtosis: "
"the only possible return value is %1%.",
std::numeric_limits<RealType>::quiet_NaN(), Policy());
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const cauchy_distribution<RealType, Policy>& /*dist*/)
{
// There is no kurtosis excess:
typedef typename Policy::assert_undefined_type assert_type;
BOOST_STATIC_ASSERT(assert_type::value == 0);
return policies::raise_domain_error<RealType>(
"boost::math::kurtosis_excess(cauchy<%1%>&)",
"The Cauchy distribution does not have a kurtosis: "
"the only possible return value is %1%.",
std::numeric_limits<RealType>::quiet_NaN(), Policy());
}
} // namespace math
} // namespace boost
#ifdef _MSC_VER
#pragma warning(pop)
#endif
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_CAUCHY_HPP

View File

@@ -0,0 +1,338 @@
// Copyright John Maddock 2006, 2007.
// Copyright Paul A. Bristow 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP
#define BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/gamma.hpp> // for incomplete beta.
#include <boost/math/distributions/complement.hpp> // complements
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp>
#include <utility>
namespace boost{ namespace math{
template <class RealType = double, class Policy = policies::policy<> >
class chi_squared_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
chi_squared_distribution(RealType i) : m_df(i)
{
RealType result;
detail::check_df(
"boost::math::chi_squared_distribution<%1%>::chi_squared_distribution", m_df, &result, Policy());
} // chi_squared_distribution
RealType degrees_of_freedom()const
{
return m_df;
}
// Parameter estimation:
static RealType find_degrees_of_freedom(
RealType difference_from_variance,
RealType alpha,
RealType beta,
RealType variance,
RealType hint = 100);
private:
//
// Data member:
//
RealType m_df; // degrees of freedom are a real number.
}; // class chi_squared_distribution
typedef chi_squared_distribution<double> chi_squared;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const chi_squared_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>()); // 0 to + infinity.
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const chi_squared_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
return std::pair<RealType, RealType>(0, tools::max_value<RealType>()); // 0 to + infinity.
}
template <class RealType, class Policy>
RealType pdf(const chi_squared_distribution<RealType, Policy>& dist, const RealType& chi_square)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType degrees_of_freedom = dist.degrees_of_freedom();
// Error check:
RealType error_result;
static const char* function = "boost::math::pdf(const chi_squared_distribution<%1%>&, %1%)";
if(false == detail::check_df(
function, degrees_of_freedom, &error_result, Policy()))
return error_result;
if((chi_square < 0) || !(boost::math::isfinite)(chi_square))
{
return policies::raise_domain_error<RealType>(
function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy());
}
if(chi_square == 0)
{
// Handle special cases:
if(degrees_of_freedom < 2)
{
return policies::raise_overflow_error<RealType>(
function, 0, Policy());
}
else if(degrees_of_freedom == 2)
{
return 0.5f;
}
else
{
return 0;
}
}
return gamma_p_derivative(degrees_of_freedom / 2, chi_square / 2, Policy()) / 2;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const chi_squared_distribution<RealType, Policy>& dist, const RealType& chi_square)
{
RealType degrees_of_freedom = dist.degrees_of_freedom();
// Error check:
RealType error_result;
static const char* function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)";
if(false == detail::check_df(
function, degrees_of_freedom, &error_result, Policy()))
return error_result;
if((chi_square < 0) || !(boost::math::isfinite)(chi_square))
{
return policies::raise_domain_error<RealType>(
function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy());
}
return boost::math::gamma_p(degrees_of_freedom / 2, chi_square / 2, Policy());
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const chi_squared_distribution<RealType, Policy>& dist, const RealType& p)
{
RealType degrees_of_freedom = dist.degrees_of_freedom();
static const char* function = "boost::math::quantile(const chi_squared_distribution<%1%>&, %1%)";
// Error check:
RealType error_result;
if(false == detail::check_df(
function, degrees_of_freedom, &error_result, Policy())
&& detail::check_probability(
function, p, &error_result, Policy()))
return error_result;
return 2 * boost::math::gamma_p_inv(degrees_of_freedom / 2, p, Policy());
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<chi_squared_distribution<RealType, Policy>, RealType>& c)
{
RealType const& degrees_of_freedom = c.dist.degrees_of_freedom();
RealType const& chi_square = c.param;
static const char* function = "boost::math::cdf(const chi_squared_distribution<%1%>&, %1%)";
// Error check:
RealType error_result;
if(false == detail::check_df(
function, degrees_of_freedom, &error_result, Policy()))
return error_result;
if((chi_square < 0) || !(boost::math::isfinite)(chi_square))
{
return policies::raise_domain_error<RealType>(
function, "Chi Square parameter was %1%, but must be > 0 !", chi_square, Policy());
}
return boost::math::gamma_q(degrees_of_freedom / 2, chi_square / 2, Policy());
}
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<chi_squared_distribution<RealType, Policy>, RealType>& c)
{
RealType const& degrees_of_freedom = c.dist.degrees_of_freedom();
RealType const& q = c.param;
static const char* function = "boost::math::quantile(const chi_squared_distribution<%1%>&, %1%)";
// Error check:
RealType error_result;
if(false == detail::check_df(
function, degrees_of_freedom, &error_result, Policy())
&& detail::check_probability(
function, q, &error_result, Policy()))
return error_result;
return 2 * boost::math::gamma_q_inv(degrees_of_freedom / 2, q, Policy());
}
template <class RealType, class Policy>
inline RealType mean(const chi_squared_distribution<RealType, Policy>& dist)
{ // Mean of Chi-Squared distribution = v.
return dist.degrees_of_freedom();
} // mean
template <class RealType, class Policy>
inline RealType variance(const chi_squared_distribution<RealType, Policy>& dist)
{ // Variance of Chi-Squared distribution = 2v.
return 2 * dist.degrees_of_freedom();
} // variance
template <class RealType, class Policy>
inline RealType mode(const chi_squared_distribution<RealType, Policy>& dist)
{
RealType df = dist.degrees_of_freedom();
static const char* function = "boost::math::mode(const chi_squared_distribution<%1%>&)";
// Most sources only define mode for df >= 2,
// but for 0 <= df <= 2, the pdf maximum actually occurs at random variate = 0;
// So one could extend the definition of mode thus:
//if(df < 0)
//{
// return policies::raise_domain_error<RealType>(
// function,
// "Chi-Squared distribution only has a mode for degrees of freedom >= 0, but got degrees of freedom = %1%.",
// df, Policy());
//}
//return (df <= 2) ? 0 : df - 2;
if(df < 2)
return policies::raise_domain_error<RealType>(
function,
"Chi-Squared distribution only has a mode for degrees of freedom >= 2, but got degrees of freedom = %1%.",
df, Policy());
return df - 2;
}
//template <class RealType, class Policy>
//inline RealType median(const chi_squared_distribution<RealType, Policy>& dist)
//{ // Median is given by Quantile[dist, 1/2]
// RealType df = dist.degrees_of_freedom();
// if(df <= 1)
// return tools::domain_error<RealType>(
// BOOST_CURRENT_FUNCTION,
// "The Chi-Squared distribution only has a mode for degrees of freedom >= 2, but got degrees of freedom = %1%.",
// df);
// return df - RealType(2)/3;
//}
// Now implemented via quantile(half) in derived accessors.
template <class RealType, class Policy>
inline RealType skewness(const chi_squared_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // For ADL
RealType df = dist.degrees_of_freedom();
return sqrt (8 / df); // == 2 * sqrt(2 / df);
}
template <class RealType, class Policy>
inline RealType kurtosis(const chi_squared_distribution<RealType, Policy>& dist)
{
RealType df = dist.degrees_of_freedom();
return 3 + 12 / df;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const chi_squared_distribution<RealType, Policy>& dist)
{
RealType df = dist.degrees_of_freedom();
return 12 / df;
}
//
// Parameter estimation comes last:
//
namespace detail
{
template <class RealType, class Policy>
struct df_estimator
{
df_estimator(RealType a, RealType b, RealType variance, RealType delta)
: alpha(a), beta(b), ratio(delta/variance) {}
RealType operator()(const RealType& df)
{
if(df <= tools::min_value<RealType>())
return 1;
chi_squared_distribution<RealType, Policy> cs(df);
RealType result;
if(ratio > 0)
{
RealType r = 1 + ratio;
result = cdf(cs, quantile(complement(cs, alpha)) / r) - beta;
}
else
{
RealType r = 1 + ratio;
result = cdf(complement(cs, quantile(cs, alpha) / r)) - beta;
}
return result;
}
private:
RealType alpha, beta, ratio;
};
} // namespace detail
template <class RealType, class Policy>
RealType chi_squared_distribution<RealType, Policy>::find_degrees_of_freedom(
RealType difference_from_variance,
RealType alpha,
RealType beta,
RealType variance,
RealType hint)
{
static const char* function = "boost::math::chi_squared_distribution<%1%>::find_degrees_of_freedom(%1%,%1%,%1%,%1%,%1%)";
// Check for domain errors:
RealType error_result;
if(false == detail::check_probability(
function, alpha, &error_result, Policy())
&& detail::check_probability(function, beta, &error_result, Policy()))
return error_result;
if(hint <= 0)
hint = 1;
detail::df_estimator<RealType, Policy> f(alpha, beta, variance, difference_from_variance);
tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
std::pair<RealType, RealType> r = tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy());
RealType result = r.first + (r.second - r.first) / 2;
if(max_iter >= policies::get_max_root_iterations<Policy>())
{
policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
" either there is no answer to how many degrees of freedom are required"
" or the answer is infinite. Current best guess is %1%", result, Policy());
}
return result;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_MATH_DISTRIBUTIONS_CHI_SQUARED_HPP

View File

@@ -0,0 +1,195 @@
// (C) Copyright John Maddock 2006.
// (C) Copyright Paul A. Bristow 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_STATS_COMPLEMENT_HPP
#define BOOST_STATS_COMPLEMENT_HPP
//
// This code really defines our own tuple type.
// It would be nice to reuse std::tr1::tuple
// while retaining our own type safety, but it's
// not clear if that's possible. In any case this
// code is *very* lightweight.
//
namespace boost{ namespace math{
template <class Dist, class RealType>
struct complemented2_type
{
complemented2_type(
const Dist& d,
const RealType& p1)
: dist(d),
param(p1) {}
const Dist& dist;
const RealType& param;
private:
complemented2_type& operator=(const complemented2_type&);
};
template <class Dist, class RealType1, class RealType2>
struct complemented3_type
{
complemented3_type(
const Dist& d,
const RealType1& p1,
const RealType2& p2)
: dist(d),
param1(p1),
param2(p2) {}
const Dist& dist;
const RealType1& param1;
const RealType2& param2;
private:
complemented3_type& operator=(const complemented3_type&);
};
template <class Dist, class RealType1, class RealType2, class RealType3>
struct complemented4_type
{
complemented4_type(
const Dist& d,
const RealType1& p1,
const RealType2& p2,
const RealType3& p3)
: dist(d),
param1(p1),
param2(p2),
param3(p3) {}
const Dist& dist;
const RealType1& param1;
const RealType2& param2;
const RealType3& param3;
private:
complemented4_type& operator=(const complemented4_type&);
};
template <class Dist, class RealType1, class RealType2, class RealType3, class RealType4>
struct complemented5_type
{
complemented5_type(
const Dist& d,
const RealType1& p1,
const RealType2& p2,
const RealType3& p3,
const RealType4& p4)
: dist(d),
param1(p1),
param2(p2),
param3(p3),
param4(p4) {}
const Dist& dist;
const RealType1& param1;
const RealType2& param2;
const RealType3& param3;
const RealType4& param4;
private:
complemented5_type& operator=(const complemented5_type&);
};
template <class Dist, class RealType1, class RealType2, class RealType3, class RealType4, class RealType5>
struct complemented6_type
{
complemented6_type(
const Dist& d,
const RealType1& p1,
const RealType2& p2,
const RealType3& p3,
const RealType4& p4,
const RealType5& p5)
: dist(d),
param1(p1),
param2(p2),
param3(p3),
param4(p4),
param5(p5) {}
const Dist& dist;
const RealType1& param1;
const RealType2& param2;
const RealType3& param3;
const RealType4& param4;
const RealType5& param5;
private:
complemented6_type& operator=(const complemented6_type&);
};
template <class Dist, class RealType1, class RealType2, class RealType3, class RealType4, class RealType5, class RealType6>
struct complemented7_type
{
complemented7_type(
const Dist& d,
const RealType1& p1,
const RealType2& p2,
const RealType3& p3,
const RealType4& p4,
const RealType5& p5,
const RealType6& p6)
: dist(d),
param1(p1),
param2(p2),
param3(p3),
param4(p4),
param5(p5),
param6(p6) {}
const Dist& dist;
const RealType1& param1;
const RealType2& param2;
const RealType3& param3;
const RealType4& param4;
const RealType5& param5;
const RealType6& param6;
private:
complemented7_type& operator=(const complemented7_type&);
};
template <class Dist, class RealType>
inline complemented2_type<Dist, RealType> complement(const Dist& d, const RealType& r)
{
return complemented2_type<Dist, RealType>(d, r);
}
template <class Dist, class RealType1, class RealType2>
inline complemented3_type<Dist, RealType1, RealType2> complement(const Dist& d, const RealType1& r1, const RealType2& r2)
{
return complemented3_type<Dist, RealType1, RealType2>(d, r1, r2);
}
template <class Dist, class RealType1, class RealType2, class RealType3>
inline complemented4_type<Dist, RealType1, RealType2, RealType3> complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3)
{
return complemented4_type<Dist, RealType1, RealType2, RealType3>(d, r1, r2, r3);
}
template <class Dist, class RealType1, class RealType2, class RealType3, class RealType4>
inline complemented5_type<Dist, RealType1, RealType2, RealType3, RealType4> complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3, const RealType4& r4)
{
return complemented5_type<Dist, RealType1, RealType2, RealType3, RealType4>(d, r1, r2, r3, r4);
}
template <class Dist, class RealType1, class RealType2, class RealType3, class RealType4, class RealType5>
inline complemented6_type<Dist, RealType1, RealType2, RealType3, RealType4, RealType5> complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3, const RealType4& r4, const RealType5& r5)
{
return complemented6_type<Dist, RealType1, RealType2, RealType3, RealType4, RealType5>(d, r1, r2, r3, r4, r5);
}
template <class Dist, class RealType1, class RealType2, class RealType3, class RealType4, class RealType5, class RealType6>
inline complemented7_type<Dist, RealType1, RealType2, RealType3, RealType4, RealType5, RealType6> complement(const Dist& d, const RealType1& r1, const RealType2& r2, const RealType3& r3, const RealType4& r4, const RealType5& r5, const RealType6& r6)
{
return complemented7_type<Dist, RealType1, RealType2, RealType3, RealType4, RealType5, RealType6>(d, r1, r2, r3, r4, r5, r6);
}
} // namespace math
} // namespace boost
#endif // BOOST_STATS_COMPLEMENT_HPP

View File

@@ -0,0 +1,157 @@
// 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)
#ifndef BOOST_MATH_DISTRIBUTIONS_COMMON_ERROR_HANDLING_HPP
#define BOOST_MATH_DISTRIBUTIONS_COMMON_ERROR_HANDLING_HPP
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
// using boost::math::isfinite;
namespace boost{ namespace math{ namespace detail
{
template <class RealType, class Policy>
inline bool check_probability(const char* function, RealType const& prob, RealType* result, const Policy& pol)
{
if((prob < 0) || (prob > 1) || !(boost::math::isfinite)(prob))
{
*result = policies::raise_domain_error<RealType>(
function,
"Probability argument is %1%, but must be >= 0 and <= 1 !", prob, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_df(const char* function, RealType const& df, RealType* result, const Policy& pol)
{
if((df <= 0) || !(boost::math::isfinite)(df))
{
*result = policies::raise_domain_error<RealType>(
function,
"Degrees of freedom argument is %1%, but must be > 0 !", df, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_scale(
const char* function,
RealType scale,
RealType* result,
const Policy& pol)
{
if((scale <= 0) || !(boost::math::isfinite)(scale))
{ // Assume scale == 0 is NOT valid for any distribution.
*result = policies::raise_domain_error<RealType>(
function,
"Scale parameter is %1%, but must be > 0 !", scale, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_location(
const char* function,
RealType location,
RealType* result,
const Policy& pol)
{
if(!(boost::math::isfinite)(location))
{
*result = policies::raise_domain_error<RealType>(
function,
"Location parameter is %1%, but must be finite!", location, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_x(
const char* function,
RealType x,
RealType* result,
const Policy& pol)
{
if(!(boost::math::isfinite)(x))
{
*result = policies::raise_domain_error<RealType>(
function,
"Random variate x is %1%, but must be finite!", x, pol);
return false;
}
return true;
// Note that this test catches both infinity and NaN.
// Some special cases permit x to be infinite, so these must be tested 1st,
// leaving this test to catch any NaNs. see Normal and cauchy for example.
}
template <class RealType, class Policy>
inline bool check_positive_x(
const char* function,
RealType x,
RealType* result,
const Policy& pol)
{
if(!(boost::math::isfinite)(x) || (x < 0))
{
*result = policies::raise_domain_error<RealType>(
function,
"Random variate x is %1%, but must be finite and >= 0!", x, pol);
return false;
}
return true;
// Note that this test catches both infinity and NaN.
// Some special cases permit x to be infinite, so these must be tested 1st,
// leaving this test to catch any NaNs. see Normal and cauchy for example.
}
template <class RealType, class Policy>
inline bool check_non_centrality(
const char* function,
RealType ncp,
RealType* result,
const Policy& pol)
{
if((ncp < 0) || !(boost::math::isfinite)(ncp))
{ // Assume scale == 0 is NOT valid for any distribution.
*result = policies::raise_domain_error<RealType>(
function,
"Non centrality parameter is %1%, but must be > 0 !", ncp, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_finite(
const char* function,
RealType x,
RealType* result,
const Policy& pol)
{
if(!(boost::math::isfinite)(x))
{ // Assume scale == 0 is NOT valid for any distribution.
*result = policies::raise_domain_error<RealType>(
function,
"Parameter is %1%, but must be finite !", x, pol);
return false;
}
return true;
}
} // namespace detail
} // namespace math
} // namespace boost
#endif // BOOST_MATH_DISTRIBUTIONS_COMMON_ERROR_HANDLING_HPP

View File

@@ -0,0 +1,163 @@
// 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_STATS_DERIVED_HPP
#define BOOST_STATS_DERIVED_HPP
// This file implements various common properties of distributions
// that can be implemented in terms of other properties:
// variance OR standard deviation (see note below),
// hazard, cumulative hazard (chf), coefficient_of_variation.
//
// Note that while both variance and standard_deviation are provided
// here, each distribution MUST SPECIALIZE AT LEAST ONE OF THESE
// otherwise these two versions will just call each other over and over
// until stack space runs out ...
// Of course there may be more efficient means of implementing these
// that are specific to a particular distribution, but these generic
// versions give these properties "for free" with most distributions.
//
// In order to make use of this header, it must be included AT THE END
// of the distribution header, AFTER the distribution and its core
// property accessors have been defined: this is so that compilers
// that implement 2-phase lookup and early-type-checking of templates
// can find the definitions refered to herein.
//
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4723) // potential divide by 0
// Suppressing spurious warning in coefficient_of_variation
#endif
namespace boost{ namespace math{
template <class Distribution>
typename Distribution::value_type variance(const Distribution& dist);
template <class Distribution>
inline typename Distribution::value_type standard_deviation(const Distribution& dist)
{
BOOST_MATH_STD_USING // ADL of sqrt.
return sqrt(variance(dist));
}
template <class Distribution>
inline typename Distribution::value_type variance(const Distribution& dist)
{
typename Distribution::value_type result = standard_deviation(dist);
return result * result;
}
template <class Distribution, class RealType>
inline typename Distribution::value_type hazard(const Distribution& dist, const RealType& x)
{ // hazard function
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda362.htm#HAZ
typedef typename Distribution::value_type value_type;
typedef typename Distribution::policy_type policy_type;
value_type p = cdf(complement(dist, x));
value_type d = pdf(dist, x);
if(d > p * tools::max_value<value_type>())
return policies::raise_overflow_error<value_type>(
"boost::math::hazard(const Distribution&, %1%)", 0, policy_type());
if(d == 0)
{
// This protects against 0/0, but is it the right thing to do?
return 0;
}
return d / p;
}
template <class Distribution, class RealType>
inline typename Distribution::value_type chf(const Distribution& dist, const RealType& x)
{ // cumulative hazard function.
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda362.htm#HAZ
BOOST_MATH_STD_USING
return -log(cdf(complement(dist, x)));
}
template <class Distribution>
inline typename Distribution::value_type coefficient_of_variation(const Distribution& dist)
{
typedef typename Distribution::value_type value_type;
typedef typename Distribution::policy_type policy_type;
using std::abs;
value_type m = mean(dist);
value_type d = standard_deviation(dist);
if((abs(m) < 1) && (d > abs(m) * tools::max_value<value_type>()))
{ // Checks too that m is not zero,
return policies::raise_overflow_error<value_type>("boost::math::coefficient_of_variation(const Distribution&, %1%)", 0, policy_type());
}
return d / m; // so MSVC warning on zerodivide is spurious, and suppressed.
}
//
// Next follow overloads of some of the standard accessors with mixed
// argument types. We just use a typecast to forward on to the "real"
// implementation with all arguments of the same type:
//
template <class Distribution, class RealType>
inline typename Distribution::value_type pdf(const Distribution& dist, const RealType& x)
{
typedef typename Distribution::value_type value_type;
return pdf(dist, static_cast<value_type>(x));
}
template <class Distribution, class RealType>
inline typename Distribution::value_type cdf(const Distribution& dist, const RealType& x)
{
typedef typename Distribution::value_type value_type;
return cdf(dist, static_cast<value_type>(x));
}
template <class Distribution, class RealType>
inline typename Distribution::value_type quantile(const Distribution& dist, const RealType& x)
{
typedef typename Distribution::value_type value_type;
return quantile(dist, static_cast<value_type>(x));
}
/*
template <class Distribution, class RealType>
inline typename Distribution::value_type chf(const Distribution& dist, const RealType& x)
{
typedef typename Distribution::value_type value_type;
return chf(dist, static_cast<value_type>(x));
}
*/
template <class Distribution, class RealType>
inline typename Distribution::value_type cdf(const complemented2_type<Distribution, RealType>& c)
{
typedef typename Distribution::value_type value_type;
return cdf(complement(c.dist, static_cast<value_type>(c.param)));
}
template <class Distribution, class RealType>
inline typename Distribution::value_type quantile(const complemented2_type<Distribution, RealType>& c)
{
typedef typename Distribution::value_type value_type;
return quantile(complement(c.dist, static_cast<value_type>(c.param)));
}
template <class Dist>
inline typename Dist::value_type median(const Dist& d)
{ // median - default definition for those distributions for which a
// simple closed form is not known,
// and for which a domain_error and/or NaN generating function is NOT defined.
typedef typename Dist::value_type value_type;
return quantile(d, static_cast<value_type>(0.5f));
}
} // namespace math
} // namespace boost
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
#endif // BOOST_STATS_DERIVED_HPP

View File

@@ -0,0 +1,149 @@
// Copyright John Maddock 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
#define BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP
#include <boost/math/tools/minima.hpp> // function minimization for mode
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/distributions/fwd.hpp>
namespace boost{ namespace math{ namespace detail{
template <class Dist>
struct pdf_minimizer
{
pdf_minimizer(const Dist& d)
: dist(d) {}
typename Dist::value_type operator()(const typename Dist::value_type& x)
{
return -pdf(dist, x);
}
private:
Dist dist;
};
template <class Dist>
typename Dist::value_type generic_find_mode(const Dist& dist, typename Dist::value_type guess, const char* function, typename Dist::value_type step = 0)
{
BOOST_MATH_STD_USING
typedef typename Dist::value_type value_type;
typedef typename Dist::policy_type policy_type;
//
// Need to begin by bracketing the maxima of the PDF:
//
value_type maxval;
value_type upper_bound = guess;
value_type lower_bound;
value_type v = pdf(dist, guess);
if(v == 0)
{
//
// Oops we don't know how to handle this, or even in which
// direction we should move in, treat as an evaluation error:
//
policies::raise_evaluation_error(
function,
"Could not locate a starting location for the search for the mode, original guess was %1%", guess, policy_type());
}
do
{
maxval = v;
if(step != 0)
upper_bound += step;
else
upper_bound *= 2;
v = pdf(dist, upper_bound);
}while(maxval < v);
lower_bound = upper_bound;
do
{
maxval = v;
if(step != 0)
lower_bound -= step;
else
lower_bound /= 2;
v = pdf(dist, lower_bound);
}while(maxval < v);
boost::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
value_type result = tools::brent_find_minima(
pdf_minimizer<Dist>(dist),
lower_bound,
upper_bound,
policies::digits<value_type, policy_type>(),
max_iter).first;
if(max_iter >= policies::get_max_root_iterations<policy_type>())
{
return policies::raise_evaluation_error<value_type>(
function,
"Unable to locate solution in a reasonable time:"
" either there is no answer to the mode of the distribution"
" or the answer is infinite. Current best guess is %1%", result, policy_type());
}
return result;
}
//
// As above,but confined to the interval [0,1]:
//
template <class Dist>
typename Dist::value_type generic_find_mode_01(const Dist& dist, typename Dist::value_type guess, const char* function)
{
BOOST_MATH_STD_USING
typedef typename Dist::value_type value_type;
typedef typename Dist::policy_type policy_type;
//
// Need to begin by bracketing the maxima of the PDF:
//
value_type maxval;
value_type upper_bound = guess;
value_type lower_bound;
value_type v = pdf(dist, guess);
do
{
maxval = v;
upper_bound = 1 - (1 - upper_bound) / 2;
if(upper_bound == 1)
return 1;
v = pdf(dist, upper_bound);
}while(maxval < v);
lower_bound = upper_bound;
do
{
maxval = v;
lower_bound /= 2;
if(lower_bound < tools::min_value<value_type>())
return 0;
v = pdf(dist, lower_bound);
}while(maxval < v);
boost::uintmax_t max_iter = policies::get_max_root_iterations<policy_type>();
value_type result = tools::brent_find_minima(
pdf_minimizer<Dist>(dist),
lower_bound,
upper_bound,
policies::digits<value_type, policy_type>(),
max_iter).first;
if(max_iter >= policies::get_max_root_iterations<policy_type>())
{
return policies::raise_evaluation_error<value_type>(
function,
"Unable to locate solution in a reasonable time:"
" either there is no answer to the mode of the distribution"
" or the answer is infinite. Current best guess is %1%", result, policy_type());
}
return result;
}
}}} // namespaces
#endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_MODE_HPP

View File

@@ -0,0 +1,91 @@
// Copyright John Maddock 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_DISTIBUTIONS_DETAIL_GENERIC_QUANTILE_HPP
#define BOOST_MATH_DISTIBUTIONS_DETAIL_GENERIC_QUANTILE_HPP
namespace boost{ namespace math{ namespace detail{
template <class Dist>
struct generic_quantile_finder
{
typedef typename Dist::value_type value_type;
typedef typename Dist::policy_type policy_type;
generic_quantile_finder(const Dist& d, value_type t, bool c)
: dist(d), target(t), comp(c) {}
value_type operator()(const value_type& x)
{
return comp ?
target - cdf(complement(dist, x))
: cdf(dist, x) - target;
}
private:
Dist dist;
value_type target;
bool comp;
};
template <class T, class Policy>
inline T check_range_result(const T& x, const Policy& pol, const char* function)
{
if((x >= 0) && (x < tools::min_value<T>()))
return policies::raise_underflow_error<T>(function, 0, pol);
if(x <= -tools::max_value<T>())
return -policies::raise_overflow_error<T>(function, 0, pol);
if(x >= tools::max_value<T>())
return policies::raise_overflow_error<T>(function, 0, pol);
return x;
}
template <class Dist>
typename Dist::value_type generic_quantile(const Dist& dist, const typename Dist::value_type& p, const typename Dist::value_type& guess, bool comp, const char* function)
{
typedef typename Dist::value_type value_type;
typedef typename Dist::policy_type policy_type;
typedef typename policies::normalise<
policy_type,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
//
// Special cases first:
//
if(p == 0)
{
return comp
? check_range_result(range(dist).second, forwarding_policy(), function)
: check_range_result(range(dist).first, forwarding_policy(), function);
}
if(p == 1)
{
return !comp
? check_range_result(range(dist).second, forwarding_policy(), function)
: check_range_result(range(dist).first, forwarding_policy(), function);
}
generic_quantile_finder<Dist> f(dist, p, comp);
tools::eps_tolerance<value_type> tol(policies::digits<value_type, forwarding_policy>() - 3);
boost::uintmax_t max_iter = policies::get_max_root_iterations<forwarding_policy>();
std::pair<value_type, value_type> ir = tools::bracket_and_solve_root(
f, guess, value_type(2), true, tol, max_iter, forwarding_policy());
value_type result = ir.first + (ir.second - ir.first) / 2;
if(max_iter >= policies::get_max_root_iterations<forwarding_policy>())
{
policies::raise_evaluation_error<value_type>(function, "Unable to locate solution in a reasonable time:"
" either there is no answer to quantile"
" or the answer is infinite. Current best guess is %1%", result, forwarding_policy());
}
return result;
}
}}} // namespaces
#endif // BOOST_MATH_DISTIBUTIONS_DETAIL_GENERIC_QUANTILE_HPP

View File

@@ -0,0 +1,481 @@
// Copyright John Maddock 2007.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
#define BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE
#include <algorithm>
namespace boost{ namespace math{ namespace detail{
//
// Functor for root finding algorithm:
//
template <class Dist>
struct distribution_quantile_finder
{
typedef typename Dist::value_type value_type;
typedef typename Dist::policy_type policy_type;
distribution_quantile_finder(const Dist d, value_type p, value_type q)
: dist(d), target(p < q ? p : q), comp(p < q ? false : true) {}
value_type operator()(value_type const& x)
{
return comp ? target - cdf(complement(dist, x)) : cdf(dist, x) - target;
}
private:
Dist dist;
value_type target;
bool comp;
};
//
// The purpose of adjust_bounds, is to toggle the last bit of the
// range so that both ends round to the same integer, if possible.
// If they do both round the same then we terminate the search
// for the root *very* quickly when finding an integer result.
// At the point that this function is called we know that "a" is
// below the root and "b" above it, so this change can not result
// in the root no longer being bracketed.
//
template <class Real, class Tol>
void adjust_bounds(Real& /* a */, Real& /* b */, Tol const& /* tol */){}
template <class Real>
void adjust_bounds(Real& /* a */, Real& b, tools::equal_floor const& /* tol */)
{
BOOST_MATH_STD_USING
b -= tools::epsilon<Real>() * b;
}
template <class Real>
void adjust_bounds(Real& a, Real& /* b */, tools::equal_ceil const& /* tol */)
{
BOOST_MATH_STD_USING
a += tools::epsilon<Real>() * a;
}
template <class Real>
void adjust_bounds(Real& a, Real& b, tools::equal_nearest_integer const& /* tol */)
{
BOOST_MATH_STD_USING
a += tools::epsilon<Real>() * a;
b -= tools::epsilon<Real>() * b;
}
//
// This is where all the work is done:
//
template <class Dist, class Tolerance>
typename Dist::value_type
do_inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& q,
typename Dist::value_type guess,
const typename Dist::value_type& multiplier,
typename Dist::value_type adder,
const Tolerance& tol,
boost::uintmax_t& max_iter)
{
typedef typename Dist::value_type value_type;
typedef typename Dist::policy_type policy_type;
static const char* function = "boost::math::do_inverse_discrete_quantile<%1%>";
BOOST_MATH_STD_USING
distribution_quantile_finder<Dist> f(dist, p, q);
//
// Max bounds of the distribution:
//
value_type min_bound, max_bound;
std::tr1::tie(min_bound, max_bound) = support(dist);
if(guess > max_bound)
guess = max_bound;
if(guess < min_bound)
guess = min_bound;
value_type fa = f(guess);
boost::uintmax_t count = max_iter - 1;
value_type fb(fa), a(guess), b =0; // Compiler warning C4701: potentially uninitialized local variable 'b' used
if(fa == 0)
return guess;
//
// For small expected results, just use a linear search:
//
if(guess < 10)
{
b = a;
while((a < 10) && (fa * fb >= 0))
{
if(fb <= 0)
{
a = b;
b = a + 1;
if(b > max_bound)
b = max_bound;
fb = f(b);
--count;
if(fb == 0)
return b;
}
else
{
b = a;
a = (std::max)(b - 1, value_type(0));
if(a < min_bound)
a = min_bound;
fa = f(a);
--count;
if(fa == 0)
return a;
}
}
}
//
// Try and bracket using a couple of additions first,
// we're assuming that "guess" is likely to be accurate
// to the nearest int or so:
//
else if(adder != 0)
{
//
// If we're looking for a large result, then bump "adder" up
// by a bit to increase our chances of bracketing the root:
//
//adder = (std::max)(adder, 0.001f * guess);
if(fa < 0)
{
b = a + adder;
if(b > max_bound)
b = max_bound;
}
else
{
b = (std::max)(a - adder, value_type(0));
if(b < min_bound)
b = min_bound;
}
fb = f(b);
--count;
if(fb == 0)
return b;
if(count && (fa * fb >= 0))
{
//
// We didn't bracket the root, try
// once more:
//
a = b;
fa = fb;
if(fa < 0)
{
b = a + adder;
if(b > max_bound)
b = max_bound;
}
else
{
b = (std::max)(a - adder, value_type(0));
if(b < min_bound)
b = min_bound;
}
fb = f(b);
--count;
}
if(a > b)
{
using std::swap;
swap(a, b);
swap(fa, fb);
}
}
//
// If the root hasn't been bracketed yet, try again
// using the multiplier this time:
//
if((boost::math::sign)(fb) == (boost::math::sign)(fa))
{
if(fa < 0)
{
//
// Zero is to the right of x2, so walk upwards
// until we find it:
//
while((boost::math::sign)(fb) == (boost::math::sign)(fa))
{
if(count == 0)
policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, policy_type());
a = b;
fa = fb;
b *= multiplier;
if(b > max_bound)
b = max_bound;
fb = f(b);
--count;
BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
}
}
else
{
//
// Zero is to the left of a, so walk downwards
// until we find it:
//
while((boost::math::sign)(fb) == (boost::math::sign)(fa))
{
if(fabs(a) < tools::min_value<value_type>())
{
// Escape route just in case the answer is zero!
max_iter -= count;
max_iter += 1;
return 0;
}
if(count == 0)
policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, policy_type());
b = a;
fb = fa;
a /= multiplier;
if(a < min_bound)
a = min_bound;
fa = f(a);
--count;
BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
}
}
}
max_iter -= count;
if(fa == 0)
return a;
if(fb == 0)
return b;
//
// Adjust bounds so that if we're looking for an integer
// result, then both ends round the same way:
//
adjust_bounds(a, b, tol);
//
// We don't want zero or denorm lower bounds:
//
if(a < tools::min_value<value_type>())
a = tools::min_value<value_type>();
//
// Go ahead and find the root:
//
std::pair<value_type, value_type> r = toms748_solve(f, a, b, fa, fb, tol, count, policy_type());
max_iter += count;
BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count);
return (r.first + r.second) / 2;
}
//
// Now finally are the public API functions.
// There is one overload for each policy,
// each one is responsible for selecting the correct
// termination condition, and rounding the result
// to an int where required.
//
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& q,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::real>&,
boost::uintmax_t& max_iter)
{
if(p <= pdf(dist, 0))
return 0;
return do_inverse_discrete_quantile(
dist,
p,
q,
guess,
multiplier,
adder,
tools::eps_tolerance<typename Dist::value_type>(policies::digits<typename Dist::value_type, typename Dist::policy_type>()),
max_iter);
}
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& q,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_outwards>&,
boost::uintmax_t& max_iter)
{
typedef typename Dist::value_type value_type;
BOOST_MATH_STD_USING
if(p <= pdf(dist, 0))
return 0;
//
// What happens next depends on whether we're looking for an
// upper or lower quantile:
//
if(p < 0.5f)
return floor(do_inverse_discrete_quantile(
dist,
p,
q,
(guess < 1 ? value_type(1) : floor(guess)),
multiplier,
adder,
tools::equal_floor(),
max_iter));
// else:
return ceil(do_inverse_discrete_quantile(
dist,
p,
q,
ceil(guess),
multiplier,
adder,
tools::equal_ceil(),
max_iter));
}
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& q,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_inwards>&,
boost::uintmax_t& max_iter)
{
typedef typename Dist::value_type value_type;
BOOST_MATH_STD_USING
if(p <= pdf(dist, 0))
return 0;
//
// What happens next depends on whether we're looking for an
// upper or lower quantile:
//
if(p < 0.5f)
return ceil(do_inverse_discrete_quantile(
dist,
p,
q,
ceil(guess),
multiplier,
adder,
tools::equal_ceil(),
max_iter));
// else:
return floor(do_inverse_discrete_quantile(
dist,
p,
q,
(guess < 1 ? value_type(1) : floor(guess)),
multiplier,
adder,
tools::equal_floor(),
max_iter));
}
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& q,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_down>&,
boost::uintmax_t& max_iter)
{
typedef typename Dist::value_type value_type;
BOOST_MATH_STD_USING
if(p <= pdf(dist, 0))
return 0;
return floor(do_inverse_discrete_quantile(
dist,
p,
q,
(guess < 1 ? value_type(1) : floor(guess)),
multiplier,
adder,
tools::equal_floor(),
max_iter));
}
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& q,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_up>&,
boost::uintmax_t& max_iter)
{
BOOST_MATH_STD_USING
if(p <= pdf(dist, 0))
return 0;
return ceil(do_inverse_discrete_quantile(
dist,
p,
q,
ceil(guess),
multiplier,
adder,
tools::equal_ceil(),
max_iter));
}
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& q,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_nearest>&,
boost::uintmax_t& max_iter)
{
typedef typename Dist::value_type value_type;
BOOST_MATH_STD_USING
if(p <= pdf(dist, 0))
return 0;
//
// Note that we adjust the guess to the nearest half-integer:
// this increase the chances that we will bracket the root
// with two results that both round to the same integer quickly.
//
return floor(do_inverse_discrete_quantile(
dist,
p,
q,
(guess < 0.5f ? value_type(1.5f) : floor(guess + 0.5f) + 0.5f),
multiplier,
adder,
tools::equal_nearest_integer(),
max_iter) + 0.5f);
}
}}} // namespaces
#endif // BOOST_MATH_DISTRIBUTIONS_DETAIL_INV_DISCRETE_QUANTILE

View File

@@ -0,0 +1,261 @@
// 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_STATS_EXPONENTIAL_HPP
#define BOOST_STATS_EXPONENTIAL_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4702) // unreachable code (return after domain_error throw).
#endif
#include <utility>
namespace boost{ namespace math{
namespace detail{
//
// Error check:
//
template <class RealType, class Policy>
inline bool verify_lambda(const char* function, RealType l, RealType* presult, const Policy& pol)
{
if(l <= 0)
{
*presult = policies::raise_domain_error<RealType>(
function,
"The scale parameter \"lambda\" must be > 0, but was: %1%.", l, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool verify_exp_x(const char* function, RealType x, RealType* presult, const Policy& pol)
{
if(x < 0)
{
*presult = policies::raise_domain_error<RealType>(
function,
"The random variable must be >= 0, but was: %1%.", x, pol);
return false;
}
return true;
}
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class exponential_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
exponential_distribution(RealType lambda = 1)
: m_lambda(lambda)
{
RealType err;
detail::verify_lambda("boost::math::exponential_distribution<%1%>::exponential_distribution", lambda, &err, Policy());
} // exponential_distribution
RealType lambda()const { return m_lambda; }
private:
RealType m_lambda;
};
typedef exponential_distribution<double> exponential;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const exponential_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(static_cast<RealType>(0), max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const exponential_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
using boost::math::tools::min_value;
return std::pair<RealType, RealType>(min_value<RealType>(), max_value<RealType>());
// min_value<RealType>() to avoid a discontinuity at x = 0.
}
template <class RealType, class Policy>
inline RealType pdf(const exponential_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::pdf(const exponential_distribution<%1%>&, %1%)";
RealType lambda = dist.lambda();
RealType result;
if(0 == detail::verify_lambda(function, lambda, &result, Policy()))
return result;
if(0 == detail::verify_exp_x(function, x, &result, Policy()))
return result;
result = lambda * exp(-lambda * x);
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const exponential_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(const exponential_distribution<%1%>&, %1%)";
RealType result;
RealType lambda = dist.lambda();
if(0 == detail::verify_lambda(function, lambda, &result, Policy()))
return result;
if(0 == detail::verify_exp_x(function, x, &result, Policy()))
return result;
result = -boost::math::expm1(-x * lambda, Policy());
return result;
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const exponential_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const exponential_distribution<%1%>&, %1%)";
RealType result;
RealType lambda = dist.lambda();
if(0 == detail::verify_lambda(function, lambda, &result, Policy()))
return result;
if(0 == detail::check_probability(function, p, &result, Policy()))
return result;
if(p == 0)
return 0;
if(p == 1)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
result = -boost::math::log1p(-p, Policy()) / lambda;
return result;
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<exponential_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(const exponential_distribution<%1%>&, %1%)";
RealType result;
RealType lambda = c.dist.lambda();
if(0 == detail::verify_lambda(function, lambda, &result, Policy()))
return result;
if(0 == detail::verify_exp_x(function, c.param, &result, Policy()))
return result;
result = exp(-c.param * lambda);
return result;
}
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<exponential_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const exponential_distribution<%1%>&, %1%)";
RealType result;
RealType lambda = c.dist.lambda();
if(0 == detail::verify_lambda(function, lambda, &result, Policy()))
return result;
RealType q = c.param;
if(0 == detail::check_probability(function, q, &result, Policy()))
return result;
if(q == 1)
return 0;
if(q == 0)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
result = -log(q) / lambda;
return result;
}
template <class RealType, class Policy>
inline RealType mean(const exponential_distribution<RealType, Policy>& dist)
{
RealType result;
RealType lambda = dist.lambda();
if(0 == detail::verify_lambda("boost::math::mean(const exponential_distribution<%1%>&)", lambda, &result, Policy()))
return result;
return 1 / lambda;
}
template <class RealType, class Policy>
inline RealType standard_deviation(const exponential_distribution<RealType, Policy>& dist)
{
RealType result;
RealType lambda = dist.lambda();
if(0 == detail::verify_lambda("boost::math::standard_deviation(const exponential_distribution<%1%>&)", lambda, &result, Policy()))
return result;
return 1 / lambda;
}
template <class RealType, class Policy>
inline RealType mode(const exponential_distribution<RealType, Policy>& /*dist*/)
{
return 0;
}
template <class RealType, class Policy>
inline RealType median(const exponential_distribution<RealType, Policy>& dist)
{
using boost::math::constants::ln_two;
return ln_two<RealType>() / dist.lambda(); // ln(2) / lambda
}
template <class RealType, class Policy>
inline RealType skewness(const exponential_distribution<RealType, Policy>& /*dist*/)
{
return 2;
}
template <class RealType, class Policy>
inline RealType kurtosis(const exponential_distribution<RealType, Policy>& /*dist*/)
{
return 9;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const exponential_distribution<RealType, Policy>& /*dist*/)
{
return 6;
}
} // namespace math
} // namespace boost
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_EXPONENTIAL_HPP

View File

@@ -0,0 +1,260 @@
// 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_STATS_EXTREME_VALUE_HPP
#define BOOST_STATS_EXTREME_VALUE_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/config/no_tr1/cmath.hpp>
//
// This is the maximum extreme value distribution, see
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366g.htm
// and http://mathworld.wolfram.com/ExtremeValueDistribution.html
// Also known as a Fisher-Tippett distribution, a log-Weibull
// distribution or a Gumbel distribution.
#include <utility>
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4702) // unreachable code (return after domain_error throw).
#endif
namespace boost{ namespace math{
namespace detail{
//
// Error check:
//
template <class RealType, class Policy>
inline bool verify_scale_b(const char* function, RealType b, RealType* presult, const Policy& pol)
{
if(b <= 0)
{
*presult = policies::raise_domain_error<RealType>(
function,
"The scale parameter \"b\" must be > 0, but was: %1%.", b, pol);
return false;
}
return true;
}
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class extreme_value_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
extreme_value_distribution(RealType a = 0, RealType b = 1)
: m_a(a), m_b(b)
{
RealType err;
detail::verify_scale_b("boost::math::extreme_value_distribution<%1%>::extreme_value_distribution", b, &err, Policy());
} // extreme_value_distribution
RealType location()const { return m_a; }
RealType scale()const { return m_b; }
private:
RealType m_a, m_b;
};
typedef extreme_value_distribution<double> extreme_value;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const extreme_value_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const extreme_value_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
}
template <class RealType, class Policy>
inline RealType pdf(const extreme_value_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType a = dist.location();
RealType b = dist.scale();
RealType result;
if(0 == detail::verify_scale_b("boost::math::pdf(const extreme_value_distribution<%1%>&, %1%)", b, &result, Policy()))
return result;
result = exp((a-x)/b) * exp(-exp((a-x)/b)) / b;
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const extreme_value_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType a = dist.location();
RealType b = dist.scale();
RealType result;
if(0 == detail::verify_scale_b("boost::math::cdf(const extreme_value_distribution<%1%>&, %1%)", b, &result, Policy()))
return result;
result = exp(-exp((a-x)/b));
return result;
} // cdf
template <class RealType, class Policy>
RealType quantile(const extreme_value_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const extreme_value_distribution<%1%>&, %1%)";
RealType a = dist.location();
RealType b = dist.scale();
RealType result;
if(0 == detail::verify_scale_b(function, b, &result, Policy()))
return result;
if(0 == detail::check_probability(function, p, &result, Policy()))
return result;
if(p == 0)
return -policies::raise_overflow_error<RealType>(function, 0, Policy());
if(p == 1)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
result = a - log(-log(p)) * b;
return result;
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<extreme_value_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType a = c.dist.location();
RealType b = c.dist.scale();
RealType result;
if(0 == detail::verify_scale_b("boost::math::cdf(const extreme_value_distribution<%1%>&, %1%)", b, &result, Policy()))
return result;
result = -boost::math::expm1(-exp((a-c.param)/b), Policy());
return result;
}
template <class RealType, class Policy>
RealType quantile(const complemented2_type<extreme_value_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const extreme_value_distribution<%1%>&, %1%)";
RealType a = c.dist.location();
RealType b = c.dist.scale();
RealType q = c.param;
RealType result;
if(0 == detail::verify_scale_b(function, b, &result, Policy()))
return result;
if(0 == detail::check_probability(function, q, &result, Policy()))
return result;
if(q == 0)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
if(q == 1)
return -policies::raise_overflow_error<RealType>(function, 0, Policy());
result = a - log(-boost::math::log1p(-q, Policy())) * b;
return result;
}
template <class RealType, class Policy>
inline RealType mean(const extreme_value_distribution<RealType, Policy>& dist)
{
RealType a = dist.location();
RealType b = dist.scale();
RealType result;
if(0 == detail::verify_scale_b("boost::math::mean(const extreme_value_distribution<%1%>&)", b, &result, Policy()))
return result;
return a + constants::euler<RealType>() * b;
}
template <class RealType, class Policy>
inline RealType standard_deviation(const extreme_value_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions.
RealType b = dist.scale();
RealType result;
if(0 == detail::verify_scale_b("boost::math::standard_deviation(const extreme_value_distribution<%1%>&)", b, &result, Policy()))
return result;
return constants::pi<RealType>() * b / sqrt(static_cast<RealType>(6));
}
template <class RealType, class Policy>
inline RealType mode(const extreme_value_distribution<RealType, Policy>& dist)
{
return dist.location();
}
template <class RealType, class Policy>
inline RealType median(const extreme_value_distribution<RealType, Policy>& dist)
{
using constants::ln_ln_two;
return dist.location() - dist.scale() * ln_ln_two<RealType>();
}
template <class RealType, class Policy>
inline RealType skewness(const extreme_value_distribution<RealType, Policy>& /*dist*/)
{
//
// This is 12 * sqrt(6) * zeta(3) / pi^3:
// See http://mathworld.wolfram.com/ExtremeValueDistribution.html
//
return static_cast<RealType>(1.1395470994046486574927930193898461120875997958366L);
}
template <class RealType, class Policy>
inline RealType kurtosis(const extreme_value_distribution<RealType, Policy>& /*dist*/)
{
// See http://mathworld.wolfram.com/ExtremeValueDistribution.html
return RealType(27) / 5;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const extreme_value_distribution<RealType, Policy>& /*dist*/)
{
// See http://mathworld.wolfram.com/ExtremeValueDistribution.html
return RealType(12) / 5;
}
} // namespace math
} // namespace boost
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_EXTREME_VALUE_HPP

View File

@@ -0,0 +1,146 @@
// 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_STATS_FIND_LOCATION_HPP
#define BOOST_STATS_FIND_LOCATION_HPP
#include <boost/math/distributions/fwd.hpp> // for all distribution signatures.
#include <boost/math/distributions/complement.hpp>
#include <boost/math/policies/policy.hpp>
#include <boost/math/tools/traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/policies/error_handling.hpp>
// using boost::math::policies::policy;
// using boost::math::complement; // will be needed by users who want complement,
// but NOT placed here to avoid putting it in global scope.
namespace boost
{
namespace math
{
// Function to find location of random variable z
// to give probability p (given scale)
// Applies to normal, lognormal, extreme value, Cauchy, (and symmetrical triangular),
// enforced by BOOST_STATIC_ASSERT below.
template <class Dist, class Policy>
inline
typename Dist::value_type find_location( // For example, normal mean.
typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p.
// For example, a nominal minimum acceptable z, so that p * 100 % are > z
typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z.
typename Dist::value_type scale, // scale parameter, for example, normal standard deviation.
const Policy& pol
)
{
#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
// Will fail to compile here if try to use with a distribution without scale & location,
// for example pareto, and many others. These tests are disabled by the pp-logic
// above if the compiler doesn't support the SFINAE tricks used in the traits class.
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<Dist>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<Dist>::value);
#endif
static const char* function = "boost::math::find_location<Dist, Policy>&, %1%)";
if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, pol);
}
if(!(boost::math::isfinite)(z))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "z parameter was %1%, but must be finite!", z, pol);
}
if(!(boost::math::isfinite)(scale))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "scale parameter was %1%, but must be finite!", scale, pol);
}
//cout << "z " << z << ", p " << p << ", quantile(Dist(), p) "
// << quantile(Dist(), p) << ", quan * scale " << quantile(Dist(), p) * scale << endl;
return z - (quantile(Dist(), p) * scale);
} // find_location
template <class Dist>
inline // with default policy.
typename Dist::value_type find_location( // For example, normal mean.
typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p.
// For example, a nominal minimum acceptable z, so that p * 100 % are > z
typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z.
typename Dist::value_type scale) // scale parameter, for example, normal standard deviation.
{ // Forward to find_location with default policy.
return (find_location<Dist>(z, p, scale, policies::policy<>()));
} // find_location
// So the user can start from the complement q = (1 - p) of the probability p,
// for example, l = find_location<normal>(complement(z, q, sd));
template <class Dist, class Real1, class Real2, class Real3>
inline typename Dist::value_type find_location( // Default policy.
complemented3_type<Real1, Real2, Real3> const& c)
{
static const char* function = "boost::math::find_location<Dist, Policy>&, %1%)";
typename Dist::value_type p = c.param1;
if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, policies::policy<>());
}
typename Dist::value_type z = c.dist;
if(!(boost::math::isfinite)(z))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "z parameter was %1%, but must be finite!", z, policies::policy<>());
}
typename Dist::value_type scale = c.param2;
if(!(boost::math::isfinite)(scale))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "scale parameter was %1%, but must be finite!", scale, policies::policy<>());
}
// cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl;
return z - quantile(Dist(), p) * scale;
} // find_location complement
template <class Dist, class Real1, class Real2, class Real3, class Real4>
inline typename Dist::value_type find_location( // Explicit policy.
complemented4_type<Real1, Real2, Real3, Real4> const& c)
{
static const char* function = "boost::math::find_location<Dist, Policy>&, %1%)";
typename Dist::value_type p = c.param1;
if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, c.param3);
}
typename Dist::value_type z = c.dist;
if(!(boost::math::isfinite)(z))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "z parameter was %1%, but must be finite!", z, c.param3);
}
typename Dist::value_type scale = c.param2;
if(!(boost::math::isfinite)(scale))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "scale parameter was %1%, but must be finite!", scale, c.param3);
}
// cout << "z " << c.dist << ", quantile (Dist(), " << c.param1 << ") * scale " << c.param2 << endl;
return z - quantile(Dist(), p) * scale;
} // find_location complement
} // namespace boost
} // namespace math
#endif // BOOST_STATS_FIND_LOCATION_HPP

View File

@@ -0,0 +1,211 @@
// 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_STATS_FIND_SCALE_HPP
#define BOOST_STATS_FIND_SCALE_HPP
#include <boost/math/distributions/fwd.hpp> // for all distribution signatures.
#include <boost/math/distributions/complement.hpp>
#include <boost/math/policies/policy.hpp>
// using boost::math::policies::policy;
#include <boost/math/tools/traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/policies/error_handling.hpp>
// using boost::math::complement; // will be needed by users who want complement,
// but NOT placed here to avoid putting it in global scope.
namespace boost
{
namespace math
{
// Function to find location of random variable z
// to give probability p (given scale)
// Applies to normal, lognormal, extreme value, Cauchy, (and symmetrical triangular),
// distributions that have scale.
// BOOST_STATIC_ASSERTs, see below, are used to enforce this.
template <class Dist, class Policy>
inline
typename Dist::value_type find_scale( // For example, normal mean.
typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p.
// For example, a nominal minimum acceptable weight z, so that p * 100 % are > z
typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z.
typename Dist::value_type location, // location parameter, for example, normal distribution mean.
const Policy& pol
)
{
#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<Dist>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<Dist>::value);
#endif
static const char* function = "boost::math::find_scale<Dist, Policy>(%1%, %1%, %1%, Policy)";
if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "Probability parameter was %1%, but must be >= 0 and <= 1!", p, pol);
}
if(!(boost::math::isfinite)(z))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "find_scale z parameter was %1%, but must be finite!", z, pol);
}
if(!(boost::math::isfinite)(location))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "find_scale location parameter was %1%, but must be finite!", location, pol);
}
//cout << "z " << z << ", p " << p << ", quantile(Dist(), p) "
//<< quantile(Dist(), p) << ", z - mean " << z - location
//<<", sd " << (z - location) / quantile(Dist(), p) << endl;
//quantile(N01, 0.001) -3.09023
//quantile(N01, 0.01) -2.32635
//quantile(N01, 0.05) -1.64485
//quantile(N01, 0.333333) -0.430728
//quantile(N01, 0.5) 0
//quantile(N01, 0.666667) 0.430728
//quantile(N01, 0.9) 1.28155
//quantile(N01, 0.95) 1.64485
//quantile(N01, 0.99) 2.32635
//quantile(N01, 0.999) 3.09023
typename Dist::value_type result =
(z - location) // difference between desired x and current location.
/ quantile(Dist(), p); // standard distribution.
if (result <= 0)
{ // If policy isn't to throw, return the scale <= 0.
policies::raise_evaluation_error<typename Dist::value_type>(function,
"Computed scale (%1%) is <= 0!" " Was the complement intended?",
result, Policy());
}
return result;
} // template <class Dist, class Policy> find_scale
template <class Dist>
inline // with default policy.
typename Dist::value_type find_scale( // For example, normal mean.
typename Dist::value_type z, // location of random variable z to give probability, P(X > z) == p.
// For example, a nominal minimum acceptable z, so that p * 100 % are > z
typename Dist::value_type p, // probability value desired at x, say 0.95 for 95% > z.
typename Dist::value_type location) // location parameter, for example, mean.
{ // Forward to find_scale using the default policy.
return (find_scale<Dist>(z, p, location, policies::policy<>()));
} // find_scale
template <class Dist, class Real1, class Real2, class Real3, class Policy>
inline typename Dist::value_type find_scale(
complemented4_type<Real1, Real2, Real3, Policy> const& c)
{
//cout << "cparam1 q " << c.param1 // q
// << ", c.dist z " << c.dist // z
// << ", c.param2 l " << c.param2 // l
// << ", quantile (Dist(), c.param1 = q) "
// << quantile(Dist(), c.param1) //q
// << endl;
#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<Dist>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<Dist>::value);
#endif
static const char* function = "boost::math::find_scale<Dist, Policy>(complement(%1%, %1%, %1%, Policy))";
// Checks on arguments, as not complemented version,
// Explicit policy.
typename Dist::value_type q = c.param1;
if(!(boost::math::isfinite)(q) || (q < 0) || (q > 1))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "Probability parameter was %1%, but must be >= 0 and <= 1!", q, c.param3);
}
typename Dist::value_type z = c.dist;
if(!(boost::math::isfinite)(z))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "find_scale z parameter was %1%, but must be finite!", z, c.param3);
}
typename Dist::value_type location = c.param2;
if(!(boost::math::isfinite)(location))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "find_scale location parameter was %1%, but must be finite!", location, c.param3);
}
typename Dist::value_type result =
(c.dist - c.param2) // difference between desired x and current location.
/ quantile(complement(Dist(), c.param1));
// ( z - location) / (quantile(complement(Dist(), q))
if (result <= 0)
{ // If policy isn't to throw, return the scale <= 0.
policies::raise_evaluation_error<typename Dist::value_type>(function,
"Computed scale (%1%) is <= 0!" " Was the complement intended?",
result, Policy());
}
return result;
} // template <class Dist, class Policy, class Real1, class Real2, class Real3> typename Dist::value_type find_scale
// So the user can start from the complement q = (1 - p) of the probability p,
// for example, s = find_scale<normal>(complement(z, q, l));
template <class Dist, class Real1, class Real2, class Real3>
inline typename Dist::value_type find_scale(
complemented3_type<Real1, Real2, Real3> const& c)
{
//cout << "cparam1 q " << c.param1 // q
// << ", c.dist z " << c.dist // z
// << ", c.param2 l " << c.param2 // l
// << ", quantile (Dist(), c.param1 = q) "
// << quantile(Dist(), c.param1) //q
// << endl;
#if !defined(BOOST_NO_SFINAE) && !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590))
BOOST_STATIC_ASSERT(::boost::math::tools::is_distribution<Dist>::value);
BOOST_STATIC_ASSERT(::boost::math::tools::is_scaled_distribution<Dist>::value);
#endif
static const char* function = "boost::math::find_scale<Dist, Policy>(complement(%1%, %1%, %1%, Policy))";
// Checks on arguments, as not complemented version,
// default policy policies::policy<>().
typename Dist::value_type q = c.param1;
if(!(boost::math::isfinite)(q) || (q < 0) || (q > 1))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "Probability parameter was %1%, but must be >= 0 and <= 1!", q, policies::policy<>());
}
typename Dist::value_type z = c.dist;
if(!(boost::math::isfinite)(z))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "find_scale z parameter was %1%, but must be finite!", z, policies::policy<>());
}
typename Dist::value_type location = c.param2;
if(!(boost::math::isfinite)(location))
{
return policies::raise_domain_error<typename Dist::value_type>(
function, "find_scale location parameter was %1%, but must be finite!", location, policies::policy<>());
}
typename Dist::value_type result =
(z - location) // difference between desired x and current location.
/ quantile(complement(Dist(), q));
// ( z - location) / (quantile(complement(Dist(), q))
if (result <= 0)
{ // If policy isn't to throw, return the scale <= 0.
policies::raise_evaluation_error<typename Dist::value_type>(function,
"Computed scale (%1%) is <= 0!" " Was the complement intended?",
result, policies::policy<>()); // This is only the default policy - also Want a version with Policy here.
}
return result;
} // template <class Dist, class Real1, class Real2, class Real3> typename Dist::value_type find_scale
} // namespace boost
} // namespace math
#endif // BOOST_STATS_FIND_SCALE_HPP

View File

@@ -0,0 +1,385 @@
// 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_DISTRIBUTIONS_FISHER_F_HPP
#define BOOST_MATH_DISTRIBUTIONS_FISHER_F_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/beta.hpp> // for incomplete beta.
#include <boost/math/distributions/complement.hpp> // complements
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp>
#include <utility>
namespace boost{ namespace math{
template <class RealType = double, class Policy = policies::policy<> >
class fisher_f_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
fisher_f_distribution(const RealType& i, const RealType& j) : m_df1(i), m_df2(j)
{
static const char* function = "fisher_f_distribution<%1%>::fisher_f_distribution";
RealType result;
detail::check_df(
function, m_df1, &result, Policy());
detail::check_df(
function, m_df2, &result, Policy());
} // fisher_f_distribution
RealType degrees_of_freedom1()const
{
return m_df1;
}
RealType degrees_of_freedom2()const
{
return m_df2;
}
private:
//
// Data members:
//
RealType m_df1; // degrees of freedom are a real number.
RealType m_df2; // degrees of freedom are a real number.
};
typedef fisher_f_distribution<double> fisher_f;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const fisher_f_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const fisher_f_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
RealType pdf(const fisher_f_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
static const char* function = "boost::math::pdf(fisher_f_distribution<%1%> const&, %1%)";
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if((x < 0) || !(boost::math::isfinite)(x))
{
return policies::raise_domain_error<RealType>(
function, "Random variable parameter was %1%, but must be > 0 !", x, Policy());
}
if(x == 0)
{
// special cases:
if(df1 < 2)
return policies::raise_overflow_error<RealType>(
function, 0, Policy());
else if(df1 == 2)
return 1;
else
return 0;
}
//
// You reach this formula by direct differentiation of the
// cdf expressed in terms of the incomplete beta.
//
// There are two versions so we don't pass a value of z
// that is very close to 1 to ibeta_derivative: for some values
// of df1 and df2, all the change takes place in this area.
//
RealType v1x = df1 * x;
RealType result;
if(v1x > df2)
{
result = (df2 * df1) / ((df2 + v1x) * (df2 + v1x));
result *= ibeta_derivative(df2 / 2, df1 / 2, df2 / (df2 + v1x), Policy());
}
else
{
result = df2 + df1 * x;
result = (result * df1 - x * df1 * df1) / (result * result);
result *= ibeta_derivative(df1 / 2, df2 / 2, v1x / (df2 + v1x), Policy());
}
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const fisher_f_distribution<RealType, Policy>& dist, const RealType& x)
{
static const char* function = "boost::math::cdf(fisher_f_distribution<%1%> const&, %1%)";
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if((x < 0) || !(boost::math::isfinite)(x))
{
return policies::raise_domain_error<RealType>(
function, "Random Variable parameter was %1%, but must be > 0 !", x, Policy());
}
RealType v1x = df1 * x;
//
// There are two equivalent formulas used here, the aim is
// to prevent the final argument to the incomplete beta
// from being too close to 1: for some values of df1 and df2
// the rate of change can be arbitrarily large in this area,
// whilst the value we're passing will have lost information
// content as a result of being 0.999999something. Better
// to switch things around so we're passing 1-z instead.
//
return v1x > df2
? boost::math::ibetac(df2 / 2, df1 / 2, df2 / (df2 + v1x), Policy())
: boost::math::ibeta(df1 / 2, df2 / 2, v1x / (df2 + v1x), Policy());
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const fisher_f_distribution<RealType, Policy>& dist, const RealType& p)
{
static const char* function = "boost::math::quantile(fisher_f_distribution<%1%> const&, %1%)";
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy())
&& detail::check_probability(
function, p, &error_result, Policy()))
return error_result;
RealType x, y;
x = boost::math::ibeta_inv(df1 / 2, df2 / 2, p, &y, Policy());
return df2 * x / (df1 * y);
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<fisher_f_distribution<RealType, Policy>, RealType>& c)
{
static const char* function = "boost::math::cdf(fisher_f_distribution<%1%> const&, %1%)";
RealType df1 = c.dist.degrees_of_freedom1();
RealType df2 = c.dist.degrees_of_freedom2();
RealType x = c.param;
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if((x < 0) || !(boost::math::isfinite)(x))
{
return policies::raise_domain_error<RealType>(
function, "Random Variable parameter was %1%, but must be > 0 !", x, Policy());
}
RealType v1x = df1 * x;
//
// There are two equivalent formulas used here, the aim is
// to prevent the final argument to the incomplete beta
// from being too close to 1: for some values of df1 and df2
// the rate of change can be arbitrarily large in this area,
// whilst the value we're passing will have lost information
// content as a result of being 0.999999something. Better
// to switch things around so we're passing 1-z instead.
//
return v1x > df2
? boost::math::ibeta(df2 / 2, df1 / 2, df2 / (df2 + v1x), Policy())
: boost::math::ibetac(df1 / 2, df2 / 2, v1x / (df2 + v1x), Policy());
}
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<fisher_f_distribution<RealType, Policy>, RealType>& c)
{
static const char* function = "boost::math::quantile(fisher_f_distribution<%1%> const&, %1%)";
RealType df1 = c.dist.degrees_of_freedom1();
RealType df2 = c.dist.degrees_of_freedom2();
RealType p = c.param;
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy())
&& detail::check_probability(
function, p, &error_result, Policy()))
return error_result;
RealType x, y;
x = boost::math::ibetac_inv(df1 / 2, df2 / 2, p, &y, Policy());
return df2 * x / (df1 * y);
}
template <class RealType, class Policy>
inline RealType mean(const fisher_f_distribution<RealType, Policy>& dist)
{ // Mean of F distribution = v.
static const char* function = "boost::math::mean(fisher_f_distribution<%1%> const&)";
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if(df2 <= 2)
{
return policies::raise_domain_error<RealType>(
function, "Second degree of freedom was %1% but must be > 2 in order for the distribution to have a mean.", df2, Policy());
}
return df2 / (df2 - 2);
} // mean
template <class RealType, class Policy>
inline RealType variance(const fisher_f_distribution<RealType, Policy>& dist)
{ // Variance of F distribution.
static const char* function = "boost::math::variance(fisher_f_distribution<%1%> const&)";
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if(df2 <= 4)
{
return policies::raise_domain_error<RealType>(
function, "Second degree of freedom was %1% but must be > 4 in order for the distribution to have a valid variance.", df2, Policy());
}
return 2 * df2 * df2 * (df1 + df2 - 2) / (df1 * (df2 - 2) * (df2 - 2) * (df2 - 4));
} // variance
template <class RealType, class Policy>
inline RealType mode(const fisher_f_distribution<RealType, Policy>& dist)
{
static const char* function = "boost::math::mode(fisher_f_distribution<%1%> const&)";
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if(df2 <= 2)
{
return policies::raise_domain_error<RealType>(
function, "Second degree of freedom was %1% but must be > 2 in order for the distribution to have a mode.", df2, Policy());
}
return df2 * (df1 - 2) / (df1 * (df2 + 2));
}
//template <class RealType, class Policy>
//inline RealType median(const fisher_f_distribution<RealType, Policy>& dist)
//{ // Median of Fisher F distribution is not defined.
// return tools::domain_error<RealType>(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
// } // median
// Now implemented via quantile(half) in derived accessors.
template <class RealType, class Policy>
inline RealType skewness(const fisher_f_distribution<RealType, Policy>& dist)
{
static const char* function = "boost::math::skewness(fisher_f_distribution<%1%> const&)";
BOOST_MATH_STD_USING // ADL of std names
// See http://mathworld.wolfram.com/F-Distribution.html
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if(df2 <= 6)
{
return policies::raise_domain_error<RealType>(
function, "Second degree of freedom was %1% but must be > 6 in order for the distribution to have a skewness.", df2, Policy());
}
return 2 * (df2 + 2 * df1 - 2) * sqrt((2 * df2 - 8) / (df1 * (df2 + df1 - 2))) / (df2 - 6);
}
template <class RealType, class Policy>
RealType kurtosis_excess(const fisher_f_distribution<RealType, Policy>& dist);
template <class RealType, class Policy>
inline RealType kurtosis(const fisher_f_distribution<RealType, Policy>& dist)
{
return 3 + kurtosis_excess(dist);
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const fisher_f_distribution<RealType, Policy>& dist)
{
static const char* function = "boost::math::kurtosis_excess(fisher_f_distribution<%1%> const&)";
// See http://mathworld.wolfram.com/F-Distribution.html
RealType df1 = dist.degrees_of_freedom1();
RealType df2 = dist.degrees_of_freedom2();
// Error check:
RealType error_result;
if(false == detail::check_df(
function, df1, &error_result, Policy())
&& detail::check_df(
function, df2, &error_result, Policy()))
return error_result;
if(df2 <= 8)
{
return policies::raise_domain_error<RealType>(
function, "Second degree of freedom was %1% but must be > 8 in order for the distribution to have a kutosis.", df2, Policy());
}
RealType df2_2 = df2 * df2;
RealType df1_2 = df1 * df1;
RealType n = -16 + 20 * df2 - 8 * df2_2 + df2_2 * df2 + 44 * df1 - 32 * df2 * df1 + 5 * df2_2 * df1 - 22 * df1_2 + 5 * df2 * df1_2;
n *= 12;
RealType d = df1 * (df2 - 6) * (df2 - 8) * (df1 + df2 - 2);
return n / d;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_MATH_DISTRIBUTIONS_FISHER_F_HPP

View File

@@ -0,0 +1,110 @@
// Copyright Paul A. Bristow 2007.
// Copyright John Maddock 2007.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_DISTRIBUTIONS_FWD_HPP
#define BOOST_MATH_DISTRIBUTIONS_FWD_HPP
namespace boost{ namespace math{
template <class RealType, class Policy>
class bernoulli_distribution;
template <class RealType, class Policy>
class beta_distribution;
template <class RealType, class Policy>
class binomial_distribution;
template <class RealType, class Policy>
class cauchy_distribution;
template <class RealType, class Policy>
class chi_squared_distribution;
template <class RealType, class Policy>
class exponential_distribution;
template <class RealType, class Policy>
class extreme_value_distribution;
template <class RealType, class Policy>
class fisher_f_distribution;
template <class RealType, class Policy>
class gamma_distribution;
template <class RealType, class Policy>
class lognormal_distribution;
template <class RealType, class Policy>
class negative_binomial_distribution;
template <class RealType, class Policy>
class non_central_chi_squared_distribution;
template <class RealType, class Policy>
class non_central_beta_distribution;
template <class RealType, class Policy>
class non_central_f_distribution;
template <class RealType, class Policy>
class non_central_t_distribution;
template <class RealType, class Policy>
class normal_distribution;
template <class RealType, class Policy>
class pareto_distribution;
template <class RealType, class Policy>
class poisson_distribution;
template <class RealType, class Policy>
class rayleigh_distribution;
template <class RealType, class Policy>
class students_t_distribution;
template <class RealType, class Policy>
class triangular_distribution;
template <class RealType, class Policy>
class uniform_distribution;
template <class RealType, class Policy>
class weibull_distribution;
}} // namespaces
#define BOOST_MATH_DECLARE_DISTRIBUTIONS(Type, Policy)\
typedef boost::math::bernoulli_distribution<Type, Policy> bernoulli;\
typedef boost::math::beta_distribution<Type, Policy> beta;\
typedef boost::math::binomial_distribution<Type, Policy> binomial;\
typedef boost::math::cauchy_distribution<Type, Policy> cauchy;\
typedef boost::math::chi_squared_distribution<Type, Policy> chi_squared;\
typedef boost::math::exponential_distribution<Type, Policy> exponential;\
typedef boost::math::extreme_value_distribution<Type, Policy> extreme_value;\
typedef boost::math::fisher_f_distribution<Type, Policy> fisher_f;\
typedef boost::math::gamma_distribution<Type, Policy> gamma;\
typedef boost::math::lognormal_distribution<Type, Policy> lognormal;\
typedef boost::math::negative_binomial_distribution<Type, Policy> negative_binomial;\
typedef boost::math::normal_distribution<Type, Policy> normal;\
typedef boost::math::pareto_distribution<Type, Policy> pareto;\
typedef boost::math::poisson_distribution<Type, Policy> poisson;\
typedef boost::math::rayleigh_distribution<Type, Policy> rayleigh;\
typedef boost::math::students_t_distribution<Type, Policy> students_t;\
typedef boost::math::triangular_distribution<Type, Policy> triangular;\
typedef boost::math::uniform_distribution<Type, Policy> uniform;\
typedef boost::math::weibull_distribution<Type, Policy> weibull;\
typedef boost::math::non_central_chi_squared_distribution<Type, Policy> non_central_chi_squared;\
typedef boost::math::non_central_beta_distribution<Type, Policy> non_central_beta;\
typedef boost::math::non_central_f_distribution<Type, Policy> non_central_f;\
typedef boost::math::non_central_t_distribution<Type, Policy> non_central_t;\
#endif // BOOST_MATH_DISTRIBUTIONS_FWD_HPP

View File

@@ -0,0 +1,349 @@
// 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_STATS_GAMMA_HPP
#define BOOST_STATS_GAMMA_HPP
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda366b.htm
// http://mathworld.wolfram.com/GammaDistribution.html
// http://en.wikipedia.org/wiki/Gamma_distribution
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/distributions/complement.hpp>
#include <utility>
namespace boost{ namespace math
{
namespace detail
{
template <class RealType, class Policy>
inline bool check_gamma_shape(
const char* function,
RealType shape,
RealType* result, const Policy& pol)
{
if((shape <= 0) || !(boost::math::isfinite)(shape))
{
*result = policies::raise_domain_error<RealType>(
function,
"Shape parameter is %1%, but must be > 0 !", shape, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_gamma_x(
const char* function,
RealType const& x,
RealType* result, const Policy& pol)
{
if((x < 0) || !(boost::math::isfinite)(x))
{
*result = policies::raise_domain_error<RealType>(
function,
"Random variate is %1% but must be >= 0 !", x, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_gamma(
const char* function,
RealType scale,
RealType shape,
RealType* result, const Policy& pol)
{
return check_scale(function, scale, result, pol) && check_gamma_shape(function, shape, result, pol);
}
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class gamma_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
gamma_distribution(RealType shape, RealType scale = 1)
: m_shape(shape), m_scale(scale)
{
RealType result;
detail::check_gamma("boost::math::gamma_distribution<%1%>::gamma_distribution", scale, shape, &result, Policy());
}
RealType shape()const
{
return m_shape;
}
RealType scale()const
{
return m_scale;
}
private:
//
// Data members:
//
RealType m_shape; // distribution shape
RealType m_scale; // distribution scale
};
// NO typedef because of clash with name of gamma function.
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const gamma_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const gamma_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
using boost::math::tools::min_value;
return std::pair<RealType, RealType>(min_value<RealType>(), max_value<RealType>());
}
template <class RealType, class Policy>
inline RealType pdf(const gamma_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::pdf(const gamma_distribution<%1%>&, %1%)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_gamma_x(function, x, &result, Policy()))
return result;
if(x == 0)
{
return 0;
}
result = gamma_p_derivative(shape, x / scale, Policy()) / scale;
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const gamma_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(const gamma_distribution<%1%>&, %1%)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_gamma_x(function, x, &result, Policy()))
return result;
result = boost::math::gamma_p(shape, x / scale, Policy());
return result;
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const gamma_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_probability(function, p, &result, Policy()))
return result;
if(p == 1)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
result = gamma_p_inv(shape, p, Policy()) * scale;
return result;
}
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<gamma_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)";
RealType shape = c.dist.shape();
RealType scale = c.dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_gamma_x(function, c.param, &result, Policy()))
return result;
result = gamma_q(shape, c.param / scale, Policy());
return result;
}
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<gamma_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const gamma_distribution<%1%>&, %1%)";
RealType shape = c.dist.shape();
RealType scale = c.dist.scale();
RealType q = c.param;
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_probability(function, q, &result, Policy()))
return result;
if(q == 0)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
result = gamma_q_inv(shape, q, Policy()) * scale;
return result;
}
template <class RealType, class Policy>
inline RealType mean(const gamma_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::mean(const gamma_distribution<%1%>&)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
result = shape * scale;
return result;
}
template <class RealType, class Policy>
inline RealType variance(const gamma_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::variance(const gamma_distribution<%1%>&)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
result = shape * scale * scale;
return result;
}
template <class RealType, class Policy>
inline RealType mode(const gamma_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::mode(const gamma_distribution<%1%>&)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
if(shape < 1)
return policies::raise_domain_error<RealType>(
function,
"The mode of the gamma distribution is only defined for values of the shape parameter >= 1, but got %1%.",
shape, Policy());
result = (shape - 1) * scale;
return result;
}
//template <class RealType, class Policy>
//inline RealType median(const gamma_distribution<RealType, Policy>& dist)
//{ // Rely on default definition in derived accessors.
//}
template <class RealType, class Policy>
inline RealType skewness(const gamma_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::skewness(const gamma_distribution<%1%>&)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
result = 2 / sqrt(shape);
return result;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const gamma_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::kurtosis_excess(const gamma_distribution<%1%>&)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_gamma(function, scale, shape, &result, Policy()))
return result;
result = 6 / shape;
return result;
}
template <class RealType, class Policy>
inline RealType kurtosis(const gamma_distribution<RealType, Policy>& dist)
{
return kurtosis_excess(dist) + 3;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_GAMMA_HPP

View File

@@ -0,0 +1,310 @@
// 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_STATS_LOGNORMAL_HPP
#define BOOST_STATS_LOGNORMAL_HPP
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3669.htm
// http://mathworld.wolfram.com/LogNormalDistribution.html
// http://en.wikipedia.org/wiki/Lognormal_distribution
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/distributions/normal.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <utility>
namespace boost{ namespace math
{
namespace detail
{
template <class RealType, class Policy>
inline bool check_lognormal_x(
const char* function,
RealType const& x,
RealType* result, const Policy& pol)
{
if((x < 0) || !(boost::math::isfinite)(x))
{
*result = policies::raise_domain_error<RealType>(
function,
"Random variate is %1% but must be >= 0 !", x, pol);
return false;
}
return true;
}
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class lognormal_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
lognormal_distribution(RealType location = 0, RealType scale = 1)
: m_location(location), m_scale(scale)
{
RealType result;
detail::check_scale("boost::math::lognormal_distribution<%1%>::lognormal_distribution", scale, &result, Policy());
}
RealType location()const
{
return m_location;
}
RealType scale()const
{
return m_scale;
}
private:
//
// Data members:
//
RealType m_location; // distribution location.
RealType m_scale; // distribution scale.
};
typedef lognormal_distribution<double> lognormal;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const lognormal_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x is >0 to +infinity.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const lognormal_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
RealType pdf(const lognormal_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType mu = dist.location();
RealType sigma = dist.scale();
static const char* function = "boost::math::pdf(const lognormal_distribution<%1%>&, %1%)";
RealType result;
if(0 == detail::check_scale(function, sigma, &result, Policy()))
return result;
if(0 == detail::check_lognormal_x(function, x, &result, Policy()))
return result;
if(x == 0)
return 0;
RealType exponent = log(x) - mu;
exponent *= -exponent;
exponent /= 2 * sigma * sigma;
result = exp(exponent);
result /= sigma * sqrt(2 * constants::pi<RealType>()) * x;
return result;
}
template <class RealType, class Policy>
inline RealType cdf(const lognormal_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(const lognormal_distribution<%1%>&, %1%)";
RealType result;
if(0 == detail::check_lognormal_x(function, x, &result, Policy()))
return result;
if(x == 0)
return 0;
normal_distribution<RealType, Policy> norm(dist.location(), dist.scale());
return cdf(norm, log(x));
}
template <class RealType, class Policy>
inline RealType quantile(const lognormal_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const lognormal_distribution<%1%>&, %1%)";
RealType result;
if(0 == detail::check_probability(function, p, &result, Policy()))
return result;
if(p == 0)
return 0;
if(p == 1)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
normal_distribution<RealType, Policy> norm(dist.location(), dist.scale());
return exp(quantile(norm, p));
}
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<lognormal_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(const lognormal_distribution<%1%>&, %1%)";
RealType result;
if(0 == detail::check_lognormal_x(function, c.param, &result, Policy()))
return result;
if(c.param == 0)
return 1;
normal_distribution<RealType, Policy> norm(c.dist.location(), c.dist.scale());
return cdf(complement(norm, log(c.param)));
}
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<lognormal_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const lognormal_distribution<%1%>&, %1%)";
RealType result;
if(0 == detail::check_probability(function, c.param, &result, Policy()))
return result;
if(c.param == 1)
return 0;
if(c.param == 0)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
normal_distribution<RealType, Policy> norm(c.dist.location(), c.dist.scale());
return exp(quantile(complement(norm, c.param)));
}
template <class RealType, class Policy>
inline RealType mean(const lognormal_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType mu = dist.location();
RealType sigma = dist.scale();
RealType result;
if(0 == detail::check_scale("boost::math::mean(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))
return result;
return exp(mu + sigma * sigma / 2);
}
template <class RealType, class Policy>
inline RealType variance(const lognormal_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType mu = dist.location();
RealType sigma = dist.scale();
RealType result;
if(0 == detail::check_scale("boost::math::variance(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))
return result;
return boost::math::expm1(sigma * sigma, Policy()) * exp(2 * mu + sigma * sigma);
}
template <class RealType, class Policy>
inline RealType mode(const lognormal_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType mu = dist.location();
RealType sigma = dist.scale();
RealType result;
if(0 == detail::check_scale("boost::math::mode(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))
return result;
return exp(mu - sigma * sigma);
}
template <class RealType, class Policy>
inline RealType median(const lognormal_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType mu = dist.location();
return exp(mu); // e^mu
}
template <class RealType, class Policy>
inline RealType skewness(const lognormal_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
//RealType mu = dist.location();
RealType sigma = dist.scale();
RealType ss = sigma * sigma;
RealType ess = exp(ss);
RealType result;
if(0 == detail::check_scale("boost::math::skewness(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))
return result;
return (ess + 2) * sqrt(boost::math::expm1(ss, Policy()));
}
template <class RealType, class Policy>
inline RealType kurtosis(const lognormal_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
//RealType mu = dist.location();
RealType sigma = dist.scale();
RealType ss = sigma * sigma;
RealType result;
if(0 == detail::check_scale("boost::math::kurtosis(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))
return result;
return exp(4 * ss) + 2 * exp(3 * ss) + 3 * exp(2 * ss) - 3;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const lognormal_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
// RealType mu = dist.location();
RealType sigma = dist.scale();
RealType ss = sigma * sigma;
RealType result;
if(0 == detail::check_scale("boost::math::kurtosis_excess(const lognormal_distribution<%1%>&)", sigma, &result, Policy()))
return result;
return exp(4 * ss) + 2 * exp(3 * ss) + 3 * exp(2 * ss) - 6;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_STUDENTS_T_HPP

View File

@@ -0,0 +1,588 @@
// boost\math\special_functions\negative_binomial.hpp
// Copyright Paul A. Bristow 2007.
// Copyright John Maddock 2007.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
// http://en.wikipedia.org/wiki/negative_binomial_distribution
// http://mathworld.wolfram.com/NegativeBinomialDistribution.html
// http://documents.wolfram.com/teachersedition/Teacher/Statistics/DiscreteDistributions.html
// The negative binomial distribution NegativeBinomialDistribution[n, p]
// is the distribution of the number (k) of failures that occur in a sequence of trials before
// r successes have occurred, where the probability of success in each trial is p.
// In a sequence of Bernoulli trials or events
// (independent, yes or no, succeed or fail) with success_fraction probability p,
// negative_binomial is the probability that k or fewer failures
// preceed the r th trial's success.
// random variable k is the number of failures (NOT the probability).
// Negative_binomial distribution is a discrete probability distribution.
// But note that the negative binomial distribution
// (like others including the binomial, Poisson & Bernoulli)
// is strictly defined as a discrete function: only integral values of k are envisaged.
// However because of the method of calculation using a continuous gamma function,
// it is convenient to treat it as if a continous function,
// and permit non-integral values of k.
// However, by default the policy is to use discrete_quantile_policy.
// To enforce the strict mathematical model, users should use conversion
// on k outside this function to ensure that k is integral.
// MATHCAD cumulative negative binomial pnbinom(k, n, p)
// Implementation note: much greater speed, and perhaps greater accuracy,
// might be achieved for extreme values by using a normal approximation.
// This is NOT been tested or implemented.
#ifndef BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
#define BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x) == Ix(a, b).
#include <boost/math/distributions/complement.hpp> // complement.
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks domain_error & logic_error.
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
#include <boost/math/tools/roots.hpp> // for root finding.
#include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/type_traits/is_integral.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/mpl/if.hpp>
#include <limits> // using std::numeric_limits;
#include <utility>
#if defined (BOOST_MSVC)
# pragma warning(push)
// This believed not now necessary, so commented out.
//# pragma warning(disable: 4702) // unreachable code.
// in domain_error_imp in error_handling.
#endif
namespace boost
{
namespace math
{
namespace negative_binomial_detail
{
// Common error checking routines for negative binomial distribution functions:
template <class RealType, class Policy>
inline bool check_successes(const char* function, const RealType& r, RealType* result, const Policy& pol)
{
if( !(boost::math::isfinite)(r) || (r <= 0) )
{
*result = policies::raise_domain_error<RealType>(
function,
"Number of successes argument is %1%, but must be > 0 !", r, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_success_fraction(const char* function, const RealType& p, RealType* result, const Policy& pol)
{
if( !(boost::math::isfinite)(p) || (p < 0) || (p > 1) )
{
*result = policies::raise_domain_error<RealType>(
function,
"Success fraction argument is %1%, but must be >= 0 and <= 1 !", p, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_dist(const char* function, const RealType& r, const RealType& p, RealType* result, const Policy& pol)
{
return check_success_fraction(function, p, result, pol)
&& check_successes(function, r, result, pol);
}
template <class RealType, class Policy>
inline bool check_dist_and_k(const char* function, const RealType& r, const RealType& p, RealType k, RealType* result, const Policy& pol)
{
if(check_dist(function, r, p, result, pol) == false)
{
return false;
}
if( !(boost::math::isfinite)(k) || (k < 0) )
{ // Check k failures.
*result = policies::raise_domain_error<RealType>(
function,
"Number of failures argument is %1%, but must be >= 0 !", k, pol);
return false;
}
return true;
} // Check_dist_and_k
template <class RealType, class Policy>
inline bool check_dist_and_prob(const char* function, const RealType& r, RealType p, RealType prob, RealType* result, const Policy& pol)
{
if(check_dist(function, r, p, result, pol) && detail::check_probability(function, prob, result, pol) == false)
{
return false;
}
return true;
} // check_dist_and_prob
} // namespace negative_binomial_detail
template <class RealType = double, class Policy = policies::policy<> >
class negative_binomial_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
negative_binomial_distribution(RealType r, RealType p) : m_r(r), m_p(p)
{ // Constructor.
RealType result;
negative_binomial_detail::check_dist(
"negative_binomial_distribution<%1%>::negative_binomial_distribution",
m_r, // Check successes r > 0.
m_p, // Check success_fraction 0 <= p <= 1.
&result, Policy());
} // negative_binomial_distribution constructor.
// Private data getter class member functions.
RealType success_fraction() const
{ // Probability of success as fraction in range 0 to 1.
return m_p;
}
RealType successes() const
{ // Total number of successes r.
return m_r;
}
static RealType find_lower_bound_on_p(
RealType trials,
RealType successes,
RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
{
static const char* function = "boost::math::negative_binomial<%1%>::find_lower_bound_on_p";
RealType result; // of error checks.
RealType failures = trials - successes;
if(false == detail::check_probability(function, alpha, &result, Policy())
&& negative_binomial_detail::check_dist_and_k(
function, successes, RealType(0), failures, &result, Policy()))
{
return result;
}
// Use complement ibeta_inv function for lower bound.
// This is adapted from the corresponding binomial formula
// here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
// This is a Clopper-Pearson interval, and may be overly conservative,
// see also "A Simple Improved Inferential Method for Some
// Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
// http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
//
return ibeta_inv(successes, failures + 1, alpha, static_cast<RealType*>(0), Policy());
} // find_lower_bound_on_p
static RealType find_upper_bound_on_p(
RealType trials,
RealType successes,
RealType alpha) // alpha 0.05 equivalent to 95% for one-sided test.
{
static const char* function = "boost::math::negative_binomial<%1%>::find_upper_bound_on_p";
RealType result; // of error checks.
RealType failures = trials - successes;
if(false == negative_binomial_detail::check_dist_and_k(
function, successes, RealType(0), failures, &result, Policy())
&& detail::check_probability(function, alpha, &result, Policy()))
{
return result;
}
if(failures == 0)
return 1;
// Use complement ibetac_inv function for upper bound.
// Note adjusted failures value: *not* failures+1 as usual.
// This is adapted from the corresponding binomial formula
// here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc241.htm
// This is a Clopper-Pearson interval, and may be overly conservative,
// see also "A Simple Improved Inferential Method for Some
// Discrete Distributions" Yong CAI and K. KRISHNAMOORTHY
// http://www.ucs.louisiana.edu/~kxk4695/Discrete_new.pdf
//
return ibetac_inv(successes, failures, alpha, static_cast<RealType*>(0), Policy());
} // find_upper_bound_on_p
// Estimate number of trials :
// "How many trials do I need to be P% sure of seeing k or fewer failures?"
static RealType find_minimum_number_of_trials(
RealType k, // number of failures (k >= 0).
RealType p, // success fraction 0 <= p <= 1.
RealType alpha) // risk level threshold 0 <= alpha <= 1.
{
static const char* function = "boost::math::negative_binomial<%1%>::find_minimum_number_of_trials";
// Error checks:
RealType result;
if(false == negative_binomial_detail::check_dist_and_k(
function, RealType(1), p, k, &result, Policy())
&& detail::check_probability(function, alpha, &result, Policy()))
{ return result; }
result = ibeta_inva(k + 1, p, alpha, Policy()); // returns n - k
return result + k;
} // RealType find_number_of_failures
static RealType find_maximum_number_of_trials(
RealType k, // number of failures (k >= 0).
RealType p, // success fraction 0 <= p <= 1.
RealType alpha) // risk level threshold 0 <= alpha <= 1.
{
static const char* function = "boost::math::negative_binomial<%1%>::find_maximum_number_of_trials";
// Error checks:
RealType result;
if(false == negative_binomial_detail::check_dist_and_k(
function, RealType(1), p, k, &result, Policy())
&& detail::check_probability(function, alpha, &result, Policy()))
{ return result; }
result = ibetac_inva(k + 1, p, alpha, Policy()); // returns n - k
return result + k;
} // RealType find_number_of_trials complemented
private:
RealType m_r; // successes.
RealType m_p; // success_fraction
}; // template <class RealType, class Policy> class negative_binomial_distribution
typedef negative_binomial_distribution<double> negative_binomial; // Reserved name of type double.
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const negative_binomial_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable k.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>()); // max_integer?
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const negative_binomial_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable k.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>()); // max_integer?
}
template <class RealType, class Policy>
inline RealType mean(const negative_binomial_distribution<RealType, Policy>& dist)
{ // Mean of Negative Binomial distribution = r(1-p)/p.
return dist.successes() * (1 - dist.success_fraction() ) / dist.success_fraction();
} // mean
//template <class RealType, class Policy>
//inline RealType median(const negative_binomial_distribution<RealType, Policy>& dist)
//{ // Median of negative_binomial_distribution is not defined.
// return policies::raise_domain_error<RealType>(BOOST_CURRENT_FUNCTION, "Median is not implemented, result is %1%!", std::numeric_limits<RealType>::quiet_NaN());
//} // median
// Now implemented via quantile(half) in derived accessors.
template <class RealType, class Policy>
inline RealType mode(const negative_binomial_distribution<RealType, Policy>& dist)
{ // Mode of Negative Binomial distribution = floor[(r-1) * (1 - p)/p]
BOOST_MATH_STD_USING // ADL of std functions.
return floor((dist.successes() -1) * (1 - dist.success_fraction()) / dist.success_fraction());
} // mode
template <class RealType, class Policy>
inline RealType skewness(const negative_binomial_distribution<RealType, Policy>& dist)
{ // skewness of Negative Binomial distribution = 2-p / (sqrt(r(1-p))
BOOST_MATH_STD_USING // ADL of std functions.
RealType p = dist.success_fraction();
RealType r = dist.successes();
return (2 - p) /
sqrt(r * (1 - p));
} // skewness
template <class RealType, class Policy>
inline RealType kurtosis(const negative_binomial_distribution<RealType, Policy>& dist)
{ // kurtosis of Negative Binomial distribution
// http://en.wikipedia.org/wiki/Negative_binomial is kurtosis_excess so add 3
RealType p = dist.success_fraction();
RealType r = dist.successes();
return 3 + (6 / r) + ((p * p) / (r * (1 - p)));
} // kurtosis
template <class RealType, class Policy>
inline RealType kurtosis_excess(const negative_binomial_distribution<RealType, Policy>& dist)
{ // kurtosis excess of Negative Binomial distribution
// http://mathworld.wolfram.com/Kurtosis.html table of kurtosis_excess
RealType p = dist.success_fraction();
RealType r = dist.successes();
return (6 - p * (6-p)) / (r * (1-p));
} // kurtosis_excess
template <class RealType, class Policy>
inline RealType variance(const negative_binomial_distribution<RealType, Policy>& dist)
{ // Variance of Binomial distribution = r (1-p) / p^2.
return dist.successes() * (1 - dist.success_fraction())
/ (dist.success_fraction() * dist.success_fraction());
} // variance
// RealType standard_deviation(const negative_binomial_distribution<RealType, Policy>& dist)
// standard_deviation provided by derived accessors.
// RealType hazard(const negative_binomial_distribution<RealType, Policy>& dist)
// hazard of Negative Binomial distribution provided by derived accessors.
// RealType chf(const negative_binomial_distribution<RealType, Policy>& dist)
// 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)
{ // Probability Density/Mass Function.
BOOST_FPU_EXCEPTION_GUARD
static const char* function = "boost::math::pdf(const negative_binomial_distribution<%1%>&, %1%)";
RealType r = dist.successes();
RealType p = dist.success_fraction();
RealType result;
if(false == negative_binomial_detail::check_dist_and_k(
function,
r,
dist.success_fraction(),
k,
&result, Policy()))
{
return result;
}
result = (p/(r + k)) * ibeta_derivative(r, static_cast<RealType>(k+1), p, Policy());
// Equivalent to:
// return exp(lgamma(r + k) - lgamma(r) - lgamma(k+1)) * pow(p, r) * pow((1-p), k);
return result;
} // negative_binomial_pdf
template <class RealType, class Policy>
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.
// k argument may be integral, signed, or unsigned, or floating point.
// If necessary, it has already been promoted from an integral type.
RealType p = dist.success_fraction();
RealType r = dist.successes();
// Error check:
RealType result;
if(false == negative_binomial_detail::check_dist_and_k(
function,
r,
dist.success_fraction(),
k,
&result, Policy()))
{
return result;
}
RealType probability = ibeta(r, static_cast<RealType>(k+1), p, Policy());
// Ip(r, k+1) = ibeta(r, k+1, p)
return probability;
} // cdf Cumulative Distribution Function Negative Binomial.
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function Negative Binomial.
static const char* function = "boost::math::cdf(const negative_binomial_distribution<%1%>&, %1%)";
using boost::math::ibetac; // Regularized incomplete beta function complement.
// k argument may be integral, signed, or unsigned, or floating point.
// If necessary, it has already been promoted from an integral type.
RealType const& k = c.param;
negative_binomial_distribution<RealType, Policy> const& dist = c.dist;
RealType p = dist.success_fraction();
RealType r = dist.successes();
// Error check:
RealType result;
if(false == negative_binomial_detail::check_dist_and_k(
function,
r,
p,
k,
&result, Policy()))
{
return result;
}
// Calculate cdf negative binomial using the incomplete beta function.
// Use of ibeta here prevents cancellation errors in calculating
// 1-p if p is very small, perhaps smaller than machine epsilon.
// Ip(k+1, r) = ibetac(r, k+1, p)
// constrain_probability here?
RealType probability = ibetac(r, static_cast<RealType>(k+1), p, Policy());
// Numerical errors might cause probability to be slightly outside the range < 0 or > 1.
// This might cause trouble downstream, so warn, possibly throw exception, but constrain to the limits.
return probability;
} // cdf Cumulative Distribution Function Negative Binomial.
template <class RealType, class Policy>
inline RealType quantile(const negative_binomial_distribution<RealType, Policy>& dist, const RealType& P)
{ // Quantile, percentile/100 or Percent Point Negative Binomial function.
// Return the number of expected failures k for a given probability p.
// Inverse cumulative Distribution Function or Quantile (percentile / 100) of negative_binomial Probability.
// MAthCAD pnbinom return smallest k such that negative_binomial(k, n, p) >= probability.
// k argument may be integral, signed, or unsigned, or floating point.
// BUT Cephes/CodeCogs says: finds argument p (0 to 1) such that cdf(k, n, p) = y
static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
BOOST_MATH_STD_USING // ADL of std functions.
RealType p = dist.success_fraction();
RealType r = dist.successes();
// Check dist and P.
RealType result;
if(false == negative_binomial_detail::check_dist_and_prob
(function, r, p, P, &result, Policy()))
{
return result;
}
// Special cases.
if (P == 1)
{ // Would need +infinity failures for total confidence.
result = policies::raise_overflow_error<RealType>(
function,
"Probability argument is 1, which implies infinite failures !", Policy());
return result;
// usually means return +std::numeric_limits<RealType>::infinity();
// unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
}
if (P == 0)
{ // No failures are expected if P = 0.
return 0; // Total trials will be just dist.successes.
}
if (P <= pow(dist.success_fraction(), dist.successes()))
{ // p <= pdf(dist, 0) == cdf(dist, 0)
return 0;
}
/*
// Calculate quantile of negative_binomial using the inverse incomplete beta function.
using boost::math::ibeta_invb;
return ibeta_invb(r, p, P, Policy()) - 1; //
*/
RealType guess = 0;
RealType factor = 5;
if(r * r * r * P * p > 0.005)
guess = detail::inverse_negative_binomial_cornish_fisher(r, p, 1-p, P, 1-P, Policy());
if(guess < 10)
{
//
// Cornish-Fisher Negative binomial approximation not accurate in this area:
//
guess = (std::min)(r * 2, RealType(10));
}
else
factor = (1-P < sqrt(tools::epsilon<RealType>())) ? 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>();
typedef typename Policy::discrete_quantile_type discrete_type;
return detail::inverse_discrete_quantile(
dist,
P,
1-P,
guess,
factor,
RealType(1),
discrete_type(),
max_iter);
} // RealType quantile(const negative_binomial_distribution dist, p)
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<negative_binomial_distribution<RealType, Policy>, RealType>& c)
{ // Quantile or Percent Point Binomial function.
// Return the number of expected failures k for a given
// complement of the probability Q = 1 - P.
static const char* function = "boost::math::quantile(const negative_binomial_distribution<%1%>&, %1%)";
BOOST_MATH_STD_USING
// Error checks:
RealType Q = c.param;
const negative_binomial_distribution<RealType, Policy>& dist = c.dist;
RealType p = dist.success_fraction();
RealType r = dist.successes();
RealType result;
if(false == negative_binomial_detail::check_dist_and_prob(
function,
r,
p,
Q,
&result, Policy()))
{
return result;
}
// Special cases:
//
if(Q == 1)
{ // There may actually be no answer to this question,
// 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()))
{ // q <= cdf(complement(dist, 0)) == pdf(dist, 0)
return 0; //
}
if(Q == 0)
{ // Probability 1 - Q == 1 so infinite failures to achieve certainty.
// Would need +infinity failures for total confidence.
result = policies::raise_overflow_error<RealType>(
function,
"Probability argument complement is 0, which implies infinite failures !", Policy());
return result;
// usually means return +std::numeric_limits<RealType>::infinity();
// unless #define BOOST_MATH_THROW_ON_OVERFLOW_ERROR
}
//return ibetac_invb(r, p, Q, Policy()) -1;
RealType guess = 0;
RealType factor = 5;
if(r * r * r * (1-Q) * p > 0.005)
guess = detail::inverse_negative_binomial_cornish_fisher(r, p, 1-p, 1-Q, Q, Policy());
if(guess < 10)
{
//
// Cornish-Fisher Negative binomial approximation not accurate in this area:
//
guess = (std::min)(r * 2, RealType(10));
}
else
factor = (Q < sqrt(tools::epsilon<RealType>())) ? 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>();
typedef typename Policy::discrete_quantile_type discrete_type;
return detail::inverse_discrete_quantile(
dist,
1-Q,
Q,
guess,
factor,
RealType(1),
discrete_type(),
max_iter);
} // quantile complement
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#if defined (BOOST_MSVC)
# pragma warning(pop)
#endif
#endif // BOOST_MATH_SPECIAL_NEGATIVE_BINOMIAL_HPP

View File

@@ -0,0 +1,845 @@
// boost\math\distributions\non_central_beta.hpp
// Copyright John Maddock 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_BETA_HPP
#define BOOST_MATH_SPECIAL_NON_CENTRAL_BETA_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/beta.hpp> // for incomplete gamma. gamma_q
#include <boost/math/distributions/complement.hpp> // complements
#include <boost/math/distributions/beta.hpp> // central distribution
#include <boost/math/distributions/detail/generic_mode.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
#include <boost/math/tools/roots.hpp> // for root finding.
namespace boost
{
namespace math
{
template <class RealType, class Policy>
class non_central_beta_distribution;
namespace detail{
template <class T, class Policy>
T non_central_beta_p(T a, T b, T lam, T x, T y, const Policy& pol, T init_val = 0)
{
BOOST_MATH_STD_USING
using namespace boost::math;
//
// Variables come first:
//
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T errtol = ldexp(1.0f, -boost::math::policies::digits<T, Policy>());
T l2 = lam / 2;
//
// k is the starting point for iteration, and is the
// maximum of the poisson weighting term:
//
int k = itrunc(l2);
if(k == 0)
k = 1;
// Starting Poisson weight:
T pois = gamma_p_derivative(T(k+1), l2, pol);
if(pois == 0)
return init_val;
// Starting beta term:
T beta = x < y
? ibeta(a + k, b, x, pol)
: ibetac(b, a + k, y, pol);
// recurance term:
T xterm = x < y
? ibeta_derivative(a + k, b, x, pol)
: ibeta_derivative(b, a + k, y, pol);
xterm *= y / (a + b + k - 1);
T poisf(pois), betaf(beta), xtermf(xterm);
T sum = init_val;
if((beta == 0) && (xterm == 0))
return init_val;
//
// Backwards recursion first, this is the stable
// direction for recursion:
//
T last_term = 0;
boost::uintmax_t count = k;
for(int i = k; i >= 0; --i)
{
T term = beta * pois;
sum += term;
if(((fabs(term/sum) < errtol) && (last_term >= term)) || (term == 0))
{
count = k - i;
break;
}
pois *= i / l2;
beta += xterm;
xterm *= (a + i - 1) / (x * (a + b + i - 2));
last_term = term;
}
for(int i = k + 1; ; ++i)
{
poisf *= l2 / i;
xtermf *= (x * (a + b + i - 2)) / (a + i - 1);
betaf -= xtermf;
T term = poisf * betaf;
sum += term;
if((fabs(term/sum) < errtol) || (term == 0))
{
break;
}
if(static_cast<boost::uintmax_t>(count + i - k) > max_iter)
{
return policies::raise_evaluation_error(
"cdf(non_central_beta_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
}
}
return sum;
}
template <class T, class Policy>
T non_central_beta_q(T a, T b, T lam, T x, T y, const Policy& pol, T init_val = 0)
{
BOOST_MATH_STD_USING
using namespace boost::math;
//
// Variables come first:
//
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T errtol = ldexp(1.0f, -boost::math::policies::digits<T, Policy>());
T l2 = lam / 2;
//
// k is the starting point for iteration, and is the
// maximum of the poisson weighting term:
//
int k = itrunc(l2);
if(k == 0)
k = 1;
// Starting Poisson weight:
T pois = gamma_p_derivative(T(k+1), l2, pol);
if(pois == 0)
return init_val;
// Starting beta term:
T beta = x < y
? ibetac(a + k, b, x, pol)
: ibeta(b, a + k, y, pol);
// recurance term:
T xterm = x < y
? ibeta_derivative(a + k, b, x, pol)
: ibeta_derivative(b, a + k, y, pol);
xterm *= y / (a + b + k - 1);
T poisf(pois), betaf(beta), xtermf(xterm);
T sum = init_val;
if((beta == 0) && (xterm == 0))
return init_val;
//
// Forwards recursion first, this is the stable
// direction for recursion, and the location
// of the bulk of the sum:
//
T last_term = 0;
boost::uintmax_t count = 0;
for(int i = k + 1; ; ++i)
{
poisf *= l2 / i;
xtermf *= (x * (a + b + i - 2)) / (a + i - 1);
betaf += xtermf;
T term = poisf * betaf;
sum += term;
if((fabs(term/sum) < errtol) && (last_term >= term))
{
count = i - k;
break;
}
if(static_cast<boost::uintmax_t>(i - k) > max_iter)
{
return policies::raise_evaluation_error(
"cdf(non_central_beta_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
}
last_term = term;
}
for(int i = k; i >= 0; --i)
{
T term = beta * pois;
sum += term;
if(fabs(term/sum) < errtol)
{
break;
}
if(static_cast<boost::uintmax_t>(count + k - i) > max_iter)
{
return policies::raise_evaluation_error(
"cdf(non_central_beta_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
}
pois *= i / l2;
beta -= xterm;
xterm *= (a + i - 1) / (x * (a + b + i - 2));
}
return sum;
}
template <class RealType, class Policy>
inline RealType non_central_beta_cdf(RealType x, RealType y, RealType a, RealType b, RealType l, bool invert, const Policy&)
{
typedef typename policies::evaluation<RealType, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
BOOST_MATH_STD_USING
if(x == 0)
return invert ? 1.0f : 0.0f;
if(y == 0)
return invert ? 0.0f : 1.0f;
value_type result;
value_type c = a + b + l / 2;
value_type cross = 1 - (b / c) * (1 + l / (2 * c * c));
if(l == 0)
result = cdf(boost::math::beta_distribution<RealType, Policy>(a, b), x);
else if(x > cross)
{
// Complement is the smaller of the two:
result = detail::non_central_beta_q(
static_cast<value_type>(a),
static_cast<value_type>(b),
static_cast<value_type>(l),
static_cast<value_type>(x),
static_cast<value_type>(y),
forwarding_policy(),
static_cast<value_type>(invert ? 0 : -1));
invert = !invert;
}
else
{
result = detail::non_central_beta_p(
static_cast<value_type>(a),
static_cast<value_type>(b),
static_cast<value_type>(l),
static_cast<value_type>(x),
static_cast<value_type>(y),
forwarding_policy(),
static_cast<value_type>(invert ? -1 : 0));
}
if(invert)
result = -result;
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
"boost::math::non_central_beta_cdf<%1%>(%1%, %1%, %1%)");
}
template <class T, class Policy>
struct nc_beta_quantile_functor
{
nc_beta_quantile_functor(const non_central_beta_distribution<T,Policy>& d, T t, bool c)
: dist(d), target(t), comp(c) {}
T operator()(const T& x)
{
return comp ?
target - cdf(complement(dist, x))
: cdf(dist, x) - target;
}
private:
non_central_beta_distribution<T,Policy> dist;
T target;
bool comp;
};
//
// This is more or less a copy of bracket_and_solve_root, but
// modified to search only the interval [0,1] using similar
// heuristics.
//
template <class F, class T, class Tol, class Policy>
std::pair<T, T> bracket_and_solve_root_01(F f, const T& guess, T factor, bool rising, Tol tol, boost::uintmax_t& max_iter, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* function = "boost::math::tools::bracket_and_solve_root_01<%1%>";
//
// Set up inital brackets:
//
T a = guess;
T b = a;
T fa = f(a);
T fb = fa;
//
// Set up invocation count:
//
boost::uintmax_t count = max_iter - 1;
if((fa < 0) == (guess < 0 ? !rising : rising))
{
//
// Zero is to the right of b, so walk upwards
// until we find it:
//
while((boost::math::sign)(fb) == (boost::math::sign)(fa))
{
if(count == 0)
{
b = policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", b, pol);
return std::make_pair(a, b);
}
//
// Heuristic: every 20 iterations we double the growth factor in case the
// initial guess was *really* bad !
//
if((max_iter - count) % 20 == 0)
factor *= 2;
//
// Now go ahead and move are guess by "factor",
// we do this by reducing 1-guess by factor:
//
a = b;
fa = fb;
b = 1 - ((1 - b) / factor);
fb = f(b);
--count;
BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
}
}
else
{
//
// Zero is to the left of a, so walk downwards
// until we find it:
//
while((boost::math::sign)(fb) == (boost::math::sign)(fa))
{
if(fabs(a) < tools::min_value<T>())
{
// Escape route just in case the answer is zero!
max_iter -= count;
max_iter += 1;
return a > 0 ? std::make_pair(T(0), T(a)) : std::make_pair(T(a), T(0));
}
if(count == 0)
{
a = policies::raise_evaluation_error(function, "Unable to bracket root, last nearest value was %1%", a, pol);
return std::make_pair(a, b);
}
//
// Heuristic: every 20 iterations we double the growth factor in case the
// initial guess was *really* bad !
//
if((max_iter - count) % 20 == 0)
factor *= 2;
//
// Now go ahead and move are guess by "factor":
//
b = a;
fb = fa;
a /= factor;
fa = f(a);
--count;
BOOST_MATH_INSTRUMENT_CODE("a = " << a << " b = " << b << " fa = " << fa << " fb = " << fb << " count = " << count);
}
}
max_iter -= count;
max_iter += 1;
std::pair<T, T> r = toms748_solve(
f,
(a < 0 ? b : a),
(a < 0 ? a : b),
(a < 0 ? fb : fa),
(a < 0 ? fa : fb),
tol,
count,
pol);
max_iter += count;
BOOST_MATH_INSTRUMENT_CODE("max_iter = " << max_iter << " count = " << count);
return r;
}
template <class RealType, class Policy>
RealType nc_beta_quantile(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& p, bool comp)
{
static const char* function = "quantile(non_central_beta_distribution<%1%>, %1%)";
typedef typename policies::evaluation<RealType, 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;
value_type a = dist.alpha();
value_type b = dist.beta();
value_type l = dist.non_centrality();
value_type r;
if(!beta_detail::check_alpha(
function,
a, &r, Policy())
||
!beta_detail::check_beta(
function,
b, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!detail::check_probability(
function,
static_cast<value_type>(p),
&r,
Policy()))
return (RealType)r;
//
// Special cases first:
//
if(p == 0)
return comp
? 1.0f
: 0.0f;
if(p == 1)
return !comp
? 1.0f
: 0.0f;
value_type c = a + b + l / 2;
value_type mean = 1 - (b / c) * (1 + l / (2 * c * c));
/*
//
// Calculate a normal approximation to the quantile,
// uses mean and variance approximations from:
// Algorithm AS 310:
// Computing the Non-Central Beta Distribution Function
// R. Chattamvelli; R. Shanmugam
// Applied Statistics, Vol. 46, No. 1. (1997), pp. 146-156.
//
// Unfortunately, when this is wrong it tends to be *very*
// wrong, so it's disabled for now, even though it often
// gets the initial guess quite close. Probably we could
// do much better by factoring in the skewness if only
// we could calculate it....
//
value_type delta = l / 2;
value_type delta2 = delta * delta;
value_type delta3 = delta * delta2;
value_type delta4 = delta2 * delta2;
value_type G = c * (c + 1) + delta;
value_type alpha = a + b;
value_type alpha2 = alpha * alpha;
value_type eta = (2 * alpha + 1) * (2 * alpha + 1) + 1;
value_type H = 3 * alpha2 + 5 * alpha + 2;
value_type F = alpha2 * (alpha + 1) + H * delta
+ (2 * alpha + 4) * delta2 + delta3;
value_type P = (3 * alpha + 1) * (9 * alpha + 17)
+ 2 * alpha * (3 * alpha + 2) * (3 * alpha + 4) + 15;
value_type Q = 54 * alpha2 + 162 * alpha + 130;
value_type R = 6 * (6 * alpha + 11);
value_type D = delta
* (H * H + 2 * P * delta + Q * delta2 + R * delta3 + 9 * delta4);
value_type variance = (b / G)
* (1 + delta * (l * l + 3 * l + eta) / (G * G))
- (b * b / F) * (1 + D / (F * F));
value_type sd = sqrt(variance);
value_type guess = comp
? quantile(complement(normal_distribution<RealType, Policy>(static_cast<RealType>(mean), static_cast<RealType>(sd)), p))
: quantile(normal_distribution<RealType, Policy>(static_cast<RealType>(mean), static_cast<RealType>(sd)), p);
if(guess >= 1)
guess = mean;
if(guess <= tools::min_value<value_type>())
guess = mean;
*/
value_type guess = mean;
detail::nc_beta_quantile_functor<value_type, Policy>
f(non_central_beta_distribution<value_type, Policy>(a, b, l), p, comp);
tools::eps_tolerance<value_type> tol(policies::digits<RealType, Policy>());
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
std::pair<value_type, value_type> ir
= bracket_and_solve_root_01(
f, guess, value_type(2.5), true, tol,
max_iter, Policy());
value_type result = ir.first + (ir.second - ir.first) / 2;
if(max_iter >= policies::get_max_root_iterations<Policy>())
{
return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
" either there is no answer to quantile of the non central beta distribution"
" or the answer is infinite. Current best guess is %1%",
policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function), Policy());
}
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function);
}
template <class T, class Policy>
T non_central_beta_pdf(T a, T b, T lam, T x, T y, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math;
//
// Variables come first:
//
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T errtol = ldexp(1.0f, -boost::math::policies::digits<T, Policy>());
T l2 = lam / 2;
//
// k is the starting point for iteration, and is the
// maximum of the poisson weighting term:
//
int k = itrunc(l2);
// Starting Poisson weight:
T pois = gamma_p_derivative(T(k+1), l2, pol);
// Starting beta term:
T beta = x < y ?
ibeta_derivative(a + k, b, x, pol)
: ibeta_derivative(b, a + k, y, pol);
T sum = 0;
T poisf(pois);
T betaf(beta);
//
// Stable backwards recursion first:
//
boost::uintmax_t count = k;
for(int i = k; i >= 0; --i)
{
T term = beta * pois;
sum += term;
if((fabs(term/sum) < errtol) || (term == 0))
{
count = k - i;
break;
}
pois *= i / l2;
beta *= (a + i - 1) / (x * (a + i + b - 1));
}
for(int i = k + 1; ; ++i)
{
poisf *= l2 / i;
betaf *= x * (a + b + i - 1) / (a + i - 1);
T term = poisf * betaf;
sum += term;
if((fabs(term/sum) < errtol) || (term == 0))
{
break;
}
if(static_cast<boost::uintmax_t>(count + i - k) > max_iter)
{
return policies::raise_evaluation_error(
"pdf(non_central_beta_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
}
}
return sum;
}
template <class RealType, class Policy>
RealType nc_beta_pdf(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING
static const char* function = "pdf(non_central_beta_distribution<%1%>, %1%)";
typedef typename policies::evaluation<RealType, 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;
value_type a = dist.alpha();
value_type b = dist.beta();
value_type l = dist.non_centrality();
value_type r;
if(!beta_detail::check_alpha(
function,
a, &r, Policy())
||
!beta_detail::check_beta(
function,
b, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!beta_detail::check_x(
function,
static_cast<value_type>(x),
&r,
Policy()))
return (RealType)r;
BOOST_MATH_STD_USING
if(l == 0)
return pdf(boost::math::beta_distribution<RealType, Policy>(dist.alpha(), dist.beta()), x);
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
non_central_beta_pdf(a, b, l, static_cast<value_type>(x), 1 - static_cast<value_type>(x), forwarding_policy()),
"function");
}
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class non_central_beta_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
non_central_beta_distribution(RealType a_, RealType b_, RealType lambda) : a(a_), b(b_), ncp(lambda)
{
const char* function = "boost::math::non_central_beta_distribution<%1%>::non_central_beta_distribution(%1%,%1%)";
RealType r;
beta_detail::check_alpha(
function,
a, &r, Policy());
beta_detail::check_beta(
function,
b, &r, Policy());
detail::check_non_centrality(
function,
lambda,
&r,
Policy());
} // non_central_beta_distribution constructor.
RealType alpha() const
{ // Private data getter function.
return a;
}
RealType beta() const
{ // Private data getter function.
return b;
}
RealType non_centrality() const
{ // Private data getter function.
return ncp;
}
private:
// Data member, initialized by constructor.
RealType a; // alpha.
RealType b; // beta.
RealType ncp; // non-centrality parameter
}; // template <class RealType, class Policy> class non_central_beta_distribution
typedef non_central_beta_distribution<double> non_central_beta; // Reserved name of type double.
// Non-member functions to give properties of the distribution.
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const non_central_beta_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable k.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, 1);
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const non_central_beta_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable k.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, 1);
}
template <class RealType, class Policy>
inline RealType mode(const non_central_beta_distribution<RealType, Policy>& dist)
{ // mode.
static const char* function = "mode(non_central_beta_distribution<%1%> const&)";
RealType a = dist.alpha();
RealType b = dist.beta();
RealType l = dist.non_centrality();
RealType r;
if(!beta_detail::check_alpha(
function,
a, &r, Policy())
||
!beta_detail::check_beta(
function,
b, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return (RealType)r;
RealType c = a + b + l / 2;
RealType mean = 1 - (b / c) * (1 + l / (2 * c * c));
return detail::generic_find_mode_01(
dist,
mean,
function);
}
#if 0
//
// We don't have the necessary information to implement
// these at present. These are just disabled for now,
// prototypes retained so we can fill in the blanks
// later:
//
template <class RealType, class Policy>
inline RealType mean(const non_central_beta_distribution<RealType, Policy>& dist)
{
// TODO
return 0;
} // mean
template <class RealType, class Policy>
inline RealType variance(const non_central_beta_distribution<RealType, Policy>& dist)
{ // variance.
const char* function = "boost::math::non_central_beta_distribution<%1%>::variance()";
// TODO
return 0;
}
// RealType standard_deviation(const non_central_beta_distribution<RealType, Policy>& dist)
// standard_deviation provided by derived accessors.
template <class RealType, class Policy>
inline RealType skewness(const non_central_beta_distribution<RealType, Policy>& dist)
{ // skewness = sqrt(l).
const char* function = "boost::math::non_central_beta_distribution<%1%>::skewness()";
// TODO
return 0;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const non_central_beta_distribution<RealType, Policy>& dist)
{
const char* function = "boost::math::non_central_beta_distribution<%1%>::kurtosis_excess()";
// TODO
return 0;
} // kurtosis_excess
template <class RealType, class Policy>
inline RealType kurtosis(const non_central_beta_distribution<RealType, Policy>& dist)
{
return kurtosis_excess(dist) + 3;
}
#endif
template <class RealType, class Policy>
inline RealType pdf(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& x)
{ // Probability Density/Mass Function.
return detail::nc_beta_pdf(dist, x);
} // pdf
template <class RealType, class Policy>
RealType cdf(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& x)
{
const char* function = "boost::math::non_central_beta_distribution<%1%>::cdf(%1%)";
RealType a = dist.alpha();
RealType b = dist.beta();
RealType l = dist.non_centrality();
RealType r;
if(!beta_detail::check_alpha(
function,
a, &r, Policy())
||
!beta_detail::check_beta(
function,
b, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!beta_detail::check_x(
function,
x,
&r,
Policy()))
return (RealType)r;
if(l == 0)
return cdf(beta_distribution<RealType, Policy>(a, b), x);
return detail::non_central_beta_cdf(x, 1 - x, a, b, l, false, Policy());
} // cdf
template <class RealType, class Policy>
RealType cdf(const complemented2_type<non_central_beta_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function
const char* function = "boost::math::non_central_beta_distribution<%1%>::cdf(%1%)";
non_central_beta_distribution<RealType, Policy> const& dist = c.dist;
RealType a = dist.alpha();
RealType b = dist.beta();
RealType l = dist.non_centrality();
RealType x = c.param;
RealType r;
if(!beta_detail::check_alpha(
function,
a, &r, Policy())
||
!beta_detail::check_beta(
function,
b, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!beta_detail::check_x(
function,
x,
&r,
Policy()))
return (RealType)r;
if(l == 0)
return cdf(complement(beta_distribution<RealType, Policy>(a, b), x));
return detail::non_central_beta_cdf(x, 1 - x, a, b, l, true, Policy());
} // ccdf
template <class RealType, class Policy>
inline RealType quantile(const non_central_beta_distribution<RealType, Policy>& dist, const RealType& p)
{ // Quantile (or Percent Point) function.
return detail::nc_beta_quantile(dist, p, false);
} // quantile
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<non_central_beta_distribution<RealType, Policy>, RealType>& c)
{ // Quantile (or Percent Point) function.
return detail::nc_beta_quantile(c.dist, c.param, true);
} // quantile complement.
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_MATH_SPECIAL_NON_CENTRAL_BETA_HPP

View File

@@ -0,0 +1,964 @@
// boost\math\distributions\non_central_chi_squared.hpp
// Copyright John Maddock 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP
#define BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q
#include <boost/math/special_functions/bessel.hpp> // for cyl_bessel_i
#include <boost/math/special_functions/round.hpp> // for iround
#include <boost/math/distributions/complement.hpp> // complements
#include <boost/math/distributions/chi_squared.hpp> // central distribution
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
#include <boost/math/tools/roots.hpp> // for root finding.
#include <boost/math/distributions/detail/generic_mode.hpp>
#include <boost/math/distributions/detail/generic_quantile.hpp>
namespace boost
{
namespace math
{
template <class RealType, class Policy>
class non_central_chi_squared_distribution;
namespace detail{
template <class T, class Policy>
T non_central_chi_square_q(T x, T f, T theta, const Policy& pol, T init_sum = 0)
{
//
// Computes the complement of the Non-Central Chi-Square
// Distribution CDF by summing a weighted sum of complements
// of the central-distributions. The weighting factor is
// a Poisson Distribution.
//
// This is an application of the technique described in:
//
// Computing discrete mixtures of continuous
// distributions: noncentral chisquare, noncentral t
// and the distribution of the square of the sample
// multiple correlation coeficient.
// D. Benton, K. Krishnamoorthy.
// Computational Statistics & Data Analysis 43 (2003) 249 - 267
//
BOOST_MATH_STD_USING
// Special case:
if(x == 0)
return 1;
//
// Initialize the variables we'll be using:
//
T lambda = theta / 2;
T del = f / 2;
T y = x / 2;
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T errtol = ldexp(1.0, -boost::math::policies::digits<T, Policy>());
T sum = init_sum;
//
// k is the starting location for iteration, we'll
// move both forwards and backwards from this point.
// k is chosen as the peek of the Poisson weights, which
// will occur *before* the largest term.
//
int k = iround(lambda, pol);
// Forwards and backwards Poisson weights:
T poisf = boost::math::gamma_p_derivative(1 + k, lambda, pol);
T poisb = poisf * k / lambda;
// Initial forwards central chi squared term:
T gamf = boost::math::gamma_q(del + k, y, pol);
// Forwards and backwards recursion terms on the central chi squared:
T xtermf = boost::math::gamma_p_derivative(del + 1 + k, y, pol);
T xtermb = xtermf * (del + k) / y;
// Initial backwards central chi squared term:
T gamb = gamf - xtermb;
//
// Forwards iteration first, this is the
// stable direction for the gamma function
// recurrences:
//
int i;
for(i = k; static_cast<boost::uintmax_t>(i-k) < max_iter; ++i)
{
T term = poisf * gamf;
sum += term;
poisf *= lambda / (i + 1);
gamf += xtermf;
xtermf *= y / (del + i + 1);
if(((sum == 0) || (fabs(term / sum) < errtol)) && (term >= poisf * gamf))
break;
}
//Error check:
if(static_cast<boost::uintmax_t>(i-k) >= max_iter)
policies::raise_evaluation_error(
"cdf(non_central_chi_squared_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
//
// Now backwards iteration: the gamma
// function recurrences are unstable in this
// direction, we rely on the terms deminishing in size
// faster than we introduce cancellation errors.
// For this reason it's very important that we start
// *before* the largest term so that backwards iteration
// is strictly converging.
//
for(i = k - 1; i >= 0; --i)
{
T term = poisb * gamb;
sum += term;
poisb *= i / lambda;
xtermb *= (del + i) / y;
gamb -= xtermb;
if((sum == 0) || (fabs(term / sum) < errtol))
break;
}
return sum;
}
template <class T, class Policy>
T non_central_chi_square_p_ding(T x, T f, T theta, const Policy& pol, T init_sum = 0)
{
//
// This is an implementation of:
//
// Algorithm AS 275:
// Computing the Non-Central #2 Distribution Function
// Cherng G. Ding
// Applied Statistics, Vol. 41, No. 2. (1992), pp. 478-482.
//
// This uses a stable forward iteration to sum the
// CDF, unfortunately this can not be used for large
// values of the non-centrality parameter because:
// * The first term may underfow to zero.
// * We may need an extra-ordinary number of terms
// before we reach the first *significant* term.
//
BOOST_MATH_STD_USING
// Special case:
if(x == 0)
return 0;
T tk = boost::math::gamma_p_derivative(f/2 + 1, x/2, pol);
T lambda = theta / 2;
T vk = exp(-lambda);
T uk = vk;
T sum = init_sum + tk * vk;
if(sum == 0)
return sum;
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T errtol = ldexp(1.0, -boost::math::policies::digits<T, Policy>());
int i;
T lterm(0), term(0);
for(i = 1; static_cast<boost::uintmax_t>(i) < max_iter; ++i)
{
tk = tk * x / (f + 2 * i);
uk = uk * lambda / i;
vk = vk + uk;
lterm = term;
term = vk * tk;
sum += term;
if((fabs(term / sum) < errtol) && (term <= lterm))
break;
}
//Error check:
if(static_cast<boost::uintmax_t>(i) >= max_iter)
policies::raise_evaluation_error(
"cdf(non_central_chi_squared_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
return sum;
}
template <class T, class Policy>
T non_central_chi_square_p(T y, T n, T lambda, const Policy& pol, T init_sum)
{
//
// This is taken more or less directly from:
//
// Computing discrete mixtures of continuous
// distributions: noncentral chisquare, noncentral t
// and the distribution of the square of the sample
// multiple correlation coeficient.
// D. Benton, K. Krishnamoorthy.
// Computational Statistics & Data Analysis 43 (2003) 249 - 267
//
// We're summing a Poisson weighting term multiplied by
// a central chi squared distribution.
//
BOOST_MATH_STD_USING
// Special case:
if(y == 0)
return 0;
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T errtol = ldexp(1.0, -boost::math::policies::digits<T, Policy>());
T errorf(0), errorb(0);
T x = y / 2;
T del = lambda / 2;
//
// Starting location for the iteration, we'll iterate
// both forwards and backwards from this point. The
// location chosen is the maximum of the Poisson weight
// function, which ocurrs *after* the largest term in the
// sum.
//
int k = iround(del, pol);
T a = n / 2 + k;
// Central chi squared term for forward iteration:
T gamkf = boost::math::gamma_p(a, x, pol);
if(lambda == 0)
return gamkf;
// Central chi squared term for backward iteration:
T gamkb = gamkf;
// Forwards Poisson weight:
T poiskf = gamma_p_derivative(k+1, del, pol);
// Backwards Poisson weight:
T poiskb = poiskf;
// Forwards gamma function recursion term:
T xtermf = boost::math::gamma_p_derivative(a, x, pol);
// Backwards gamma function recursion term:
T xtermb = xtermf * x / a;
T sum = init_sum + poiskf * gamkf;
if(sum == 0)
return sum;
int i = 1;
//
// Backwards recursion first, this is the stable
// direction for gamma function recurrences:
//
while(i <= k)
{
xtermb *= (a - i + 1) / x;
gamkb += xtermb;
poiskb = poiskb * (k - i + 1) / del;
errorf = errorb;
errorb = gamkb * poiskb;
sum += errorb;
if((fabs(errorb / sum) < errtol) && (errorb <= errorf))
break;
++i;
}
i = 1;
//
// Now forwards recursion, the gamma function
// recurrence relation is unstable in this direction,
// so we rely on the magnitude of successive terms
// decreasing faster than we introduce cancellation error.
// For this reason it's vital that k is chosen to be *after*
// the largest term, so that successive forward iterations
// are strictly (and rapidly) converging.
//
do
{
xtermf = xtermf * x / (a + i - 1);
gamkf = gamkf - xtermf;
poiskf = poiskf * del / (k + i);
errorf = poiskf * gamkf;
sum += errorf;
++i;
}while((fabs(errorf / sum) > errtol) && (static_cast<boost::uintmax_t>(i) < max_iter));
//Error check:
if(static_cast<boost::uintmax_t>(i) >= max_iter)
policies::raise_evaluation_error(
"cdf(non_central_chi_squared_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
return sum;
}
template <class T, class Policy>
T non_central_chi_square_pdf(T x, T n, T lambda, const Policy& pol)
{
//
// As above but for the PDF:
//
BOOST_MATH_STD_USING
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
T errtol = ldexp(1.0, -boost::math::policies::digits<T, Policy>());
T x2 = x / 2;
T n2 = n / 2;
T l2 = lambda / 2;
T sum = 0;
int k = itrunc(l2);
T pois = gamma_p_derivative(k + 1, l2, pol) * gamma_p_derivative(n2 + k, x2);
if(pois == 0)
return 0;
T poisb = pois;
for(int i = k; ; ++i)
{
sum += pois;
if(pois / sum < errtol)
break;
if(static_cast<boost::uintmax_t>(i - k) >= max_iter)
return policies::raise_evaluation_error(
"pdf(non_central_chi_squared_distribution<%1%>, %1%)",
"Series did not converge, closest value was %1%", sum, pol);
pois *= l2 * x2 / ((i + 1) * (n2 + i));
}
for(int i = k - 1; i >= 0; --i)
{
poisb *= (i + 1) * (n2 + i) / (l2 * x2);
sum += poisb;
if(poisb / sum < errtol)
break;
}
return sum / 2;
}
template <class RealType, class Policy>
inline RealType non_central_chi_squared_cdf(RealType x, RealType k, RealType l, bool invert, const Policy&)
{
typedef typename policies::evaluation<RealType, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
BOOST_MATH_STD_USING
value_type result;
if(l == 0)
result = cdf(boost::math::chi_squared_distribution<RealType, Policy>(k), x);
else if(x > k + l)
{
// Complement is the smaller of the two:
result = detail::non_central_chi_square_q(
static_cast<value_type>(x),
static_cast<value_type>(k),
static_cast<value_type>(l),
forwarding_policy(),
static_cast<value_type>(invert ? 0 : -1));
invert = !invert;
}
else if(l < 200)
{
// For small values of the non-centrality parameter
// we can use Ding's method:
result = detail::non_central_chi_square_p_ding(
static_cast<value_type>(x),
static_cast<value_type>(k),
static_cast<value_type>(l),
forwarding_policy(),
static_cast<value_type>(invert ? -1 : 0));
}
else
{
// For largers values of the non-centrality
// parameter Ding's method will consume an
// extra-ordinary number of terms, and worse
// may return zero when the result is in fact
// finite, use Krishnamoorthy's method instead:
result = detail::non_central_chi_square_p(
static_cast<value_type>(x),
static_cast<value_type>(k),
static_cast<value_type>(l),
forwarding_policy(),
static_cast<value_type>(invert ? -1 : 0));
}
if(invert)
result = -result;
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
"boost::math::non_central_chi_squared_cdf<%1%>(%1%, %1%, %1%)");
}
template <class T, class Policy>
struct nccs_quantile_functor
{
nccs_quantile_functor(const non_central_chi_squared_distribution<T,Policy>& d, T t, bool c)
: dist(d), target(t), comp(c) {}
T operator()(const T& x)
{
return comp ?
target - cdf(complement(dist, x))
: cdf(dist, x) - target;
}
private:
non_central_chi_squared_distribution<T,Policy> dist;
T target;
bool comp;
};
template <class RealType, class Policy>
RealType nccs_quantile(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& p, bool comp)
{
static const char* function = "quantile(non_central_chi_squared_distribution<%1%>, %1%)";
typedef typename policies::evaluation<RealType, 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;
value_type k = dist.degrees_of_freedom();
value_type l = dist.non_centrality();
value_type r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!detail::check_probability(
function,
static_cast<value_type>(p),
&r,
Policy()))
return (RealType)r;
value_type b = (l * l) / (k + 3 * l);
value_type c = (k + 3 * l) / (k + 2 * l);
value_type ff = (k + 2 * l) / (c * c);
value_type guess;
if(comp)
guess = b + c * quantile(complement(chi_squared_distribution<value_type, forwarding_policy>(ff), p));
else
guess = b + c * quantile(chi_squared_distribution<value_type, forwarding_policy>(ff), p);
if(guess < 0)
guess = tools::min_value<value_type>();
value_type result = detail::generic_quantile(
non_central_chi_squared_distribution<value_type, forwarding_policy>(k, l),
p,
guess,
comp,
function);
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function);
}
template <class RealType, class Policy>
RealType nccs_pdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING
static const char* function = "pdf(non_central_chi_squared_distribution<%1%>, %1%)";
typedef typename policies::evaluation<RealType, 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;
value_type k = dist.degrees_of_freedom();
value_type l = dist.non_centrality();
value_type r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!detail::check_positive_x(
function,
(value_type)x,
&r,
Policy()))
return (RealType)r;
BOOST_MATH_STD_USING
if(l == 0)
return pdf(boost::math::chi_squared_distribution<RealType, forwarding_policy>(dist.degrees_of_freedom()), x);
// Special case:
if(x == 0)
return 0;
if(l > 50)
{
r = non_central_chi_square_pdf(static_cast<value_type>(x), k, l, forwarding_policy());
}
else
{
r = log(x / l) * (k / 4 - 0.5f) - (x + l) / 2;
if(fabs(r) >= tools::log_max_value<RealType>() / 4)
{
r = non_central_chi_square_pdf(static_cast<value_type>(x), k, l, forwarding_policy());
}
else
{
r = exp(r);
r = 0.5f * r
* boost::math::cyl_bessel_i(k/2 - 1, sqrt(l * x), forwarding_policy());
}
}
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
r,
function);
}
template <class RealType, class Policy>
struct degrees_of_freedom_finder
{
degrees_of_freedom_finder(
RealType lam_, RealType x_, RealType p_, bool c)
: lam(lam_), x(x_), p(p_), comp(c) {}
RealType operator()(const RealType& v)
{
non_central_chi_squared_distribution<RealType, Policy> d(v, lam);
return comp ?
p - cdf(complement(d, x))
: cdf(d, x) - p;
}
private:
RealType lam;
RealType x;
RealType p;
bool comp;
};
template <class RealType, class Policy>
inline RealType find_degrees_of_freedom(
RealType lam, RealType x, RealType p, RealType q, const Policy& pol)
{
const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
if((p == 0) || (q == 0))
{
//
// Can't a thing if one of p and q is zero:
//
return policies::raise_evaluation_error<RealType>(function,
"Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%",
RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy());
}
degrees_of_freedom_finder<RealType, Policy> f(lam, x, p < q ? p : q, p < q ? false : true);
tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
//
// Pick an initial guess that we know will give us a probability
// right around 0.5.
//
RealType guess = x - lam;
if(guess < 1)
guess = 1;
std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
f, guess, RealType(2), false, tol, max_iter, pol);
RealType result = ir.first + (ir.second - ir.first) / 2;
if(max_iter >= policies::get_max_root_iterations<Policy>())
{
policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
" or there is no answer to problem. Current best guess is %1%", result, Policy());
}
return result;
}
template <class RealType, class Policy>
struct non_centrality_finder
{
non_centrality_finder(
RealType v_, RealType x_, RealType p_, bool c)
: v(v_), x(x_), p(p_), comp(c) {}
RealType operator()(const RealType& lam)
{
non_central_chi_squared_distribution<RealType, Policy> d(v, lam);
return comp ?
p - cdf(complement(d, x))
: cdf(d, x) - p;
}
private:
RealType v;
RealType x;
RealType p;
bool comp;
};
template <class RealType, class Policy>
inline RealType find_non_centrality(
RealType v, RealType x, RealType p, RealType q, const Policy& pol)
{
const char* function = "non_central_chi_squared<%1%>::find_non_centrality";
if((p == 0) || (q == 0))
{
//
// Can't do a thing if one of p and q is zero:
//
return policies::raise_evaluation_error<RealType>(function,
"Can't find non centrality parameter when the probability is 0 or 1, only possible answer is %1%",
RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy());
}
non_centrality_finder<RealType, Policy> f(v, x, p < q ? p : q, p < q ? false : true);
tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
//
// Pick an initial guess that we know will give us a probability
// right around 0.5.
//
RealType guess = x - v;
if(guess < 1)
guess = 1;
std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
f, guess, RealType(2), false, tol, max_iter, pol);
RealType result = ir.first + (ir.second - ir.first) / 2;
if(max_iter >= policies::get_max_root_iterations<Policy>())
{
policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
" or there is no answer to problem. Current best guess is %1%", result, Policy());
}
return result;
}
}
template <class RealType = double, class Policy = policies::policy<> >
class non_central_chi_squared_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
non_central_chi_squared_distribution(RealType df_, RealType lambda) : df(df_), ncp(lambda)
{
const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::non_central_chi_squared_distribution(%1%,%1%)";
RealType r;
detail::check_df(
function,
df, &r, Policy());
detail::check_non_centrality(
function,
ncp,
&r,
Policy());
} // non_central_chi_squared_distribution constructor.
RealType degrees_of_freedom() const
{ // Private data getter function.
return df;
}
RealType non_centrality() const
{ // Private data getter function.
return ncp;
}
static RealType find_degrees_of_freedom(RealType lam, RealType x, RealType p)
{
const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
typedef typename policies::evaluation<RealType, 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;
value_type result = detail::find_degrees_of_freedom(
static_cast<value_type>(lam),
static_cast<value_type>(x),
static_cast<value_type>(p),
static_cast<value_type>(1-p),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function);
}
template <class A, class B, class C>
static RealType find_degrees_of_freedom(const complemented3_type<A,B,C>& c)
{
const char* function = "non_central_chi_squared<%1%>::find_degrees_of_freedom";
typedef typename policies::evaluation<RealType, 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;
value_type result = detail::find_degrees_of_freedom(
static_cast<value_type>(c.dist),
static_cast<value_type>(c.param1),
static_cast<value_type>(1-c.param2),
static_cast<value_type>(c.param2),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function);
}
static RealType find_non_centrality(RealType v, RealType x, RealType p)
{
const char* function = "non_central_chi_squared<%1%>::find_non_centrality";
typedef typename policies::evaluation<RealType, 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;
value_type result = detail::find_non_centrality(
static_cast<value_type>(v),
static_cast<value_type>(x),
static_cast<value_type>(p),
static_cast<value_type>(1-p),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function);
}
template <class A, class B, class C>
static RealType find_non_centrality(const complemented3_type<A,B,C>& c)
{
const char* function = "non_central_chi_squared<%1%>::find_non_centrality";
typedef typename policies::evaluation<RealType, 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;
value_type result = detail::find_non_centrality(
static_cast<value_type>(c.dist),
static_cast<value_type>(c.param1),
static_cast<value_type>(1-c.param2),
static_cast<value_type>(c.param2),
forwarding_policy());
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
result,
function);
}
private:
// Data member, initialized by constructor.
RealType df; // degrees of freedom.
RealType ncp; // non-centrality parameter
}; // template <class RealType, class Policy> class non_central_chi_squared_distribution
typedef non_central_chi_squared_distribution<double> non_central_chi_squared; // Reserved name of type double.
// Non-member functions to give properties of the distribution.
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const non_central_chi_squared_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable k.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>()); // Max integer?
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const non_central_chi_squared_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable k.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline RealType mean(const non_central_chi_squared_distribution<RealType, Policy>& dist)
{ // Mean of poisson distribution = lambda.
const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::mean()";
RealType k = dist.degrees_of_freedom();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
return k + l;
} // mean
template <class RealType, class Policy>
inline RealType mode(const non_central_chi_squared_distribution<RealType, Policy>& dist)
{ // mode.
static const char* function = "mode(non_central_chi_squared_distribution<%1%> const&)";
RealType k = dist.degrees_of_freedom();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return (RealType)r;
return detail::generic_find_mode(dist, 1 + k, function);
}
template <class RealType, class Policy>
inline RealType variance(const non_central_chi_squared_distribution<RealType, Policy>& dist)
{ // variance.
const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::variance()";
RealType k = dist.degrees_of_freedom();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
return 2 * (2 * l + k);
}
// RealType standard_deviation(const non_central_chi_squared_distribution<RealType, Policy>& dist)
// standard_deviation provided by derived accessors.
template <class RealType, class Policy>
inline RealType skewness(const non_central_chi_squared_distribution<RealType, Policy>& dist)
{ // skewness = sqrt(l).
const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::skewness()";
RealType k = dist.degrees_of_freedom();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
BOOST_MATH_STD_USING
return pow(2 / (k + 2 * l), RealType(3)/2) * (k + 3 * l);
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const non_central_chi_squared_distribution<RealType, Policy>& dist)
{
const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::kurtosis_excess()";
RealType k = dist.degrees_of_freedom();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
return 12 * (k + 4 * l) / ((k + 2 * l) * (k + 2 * l));
} // kurtosis_excess
template <class RealType, class Policy>
inline RealType kurtosis(const non_central_chi_squared_distribution<RealType, Policy>& dist)
{
return kurtosis_excess(dist) + 3;
}
template <class RealType, class Policy>
inline RealType pdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
{ // Probability Density/Mass Function.
return detail::nccs_pdf(dist, x);
} // pdf
template <class RealType, class Policy>
RealType cdf(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& x)
{
const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)";
RealType k = dist.degrees_of_freedom();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!detail::check_positive_x(
function,
x,
&r,
Policy()))
return r;
return detail::non_central_chi_squared_cdf(x, k, l, false, Policy());
} // cdf
template <class RealType, class Policy>
RealType cdf(const complemented2_type<non_central_chi_squared_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function
const char* function = "boost::math::non_central_chi_squared_distribution<%1%>::cdf(%1%)";
non_central_chi_squared_distribution<RealType, Policy> const& dist = c.dist;
RealType x = c.param;
RealType k = dist.degrees_of_freedom();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
k, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy())
||
!detail::check_positive_x(
function,
x,
&r,
Policy()))
return r;
return detail::non_central_chi_squared_cdf(x, k, l, true, Policy());
} // ccdf
template <class RealType, class Policy>
inline RealType quantile(const non_central_chi_squared_distribution<RealType, Policy>& dist, const RealType& p)
{ // Quantile (or Percent Point) function.
return detail::nccs_quantile(dist, p, false);
} // quantile
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<non_central_chi_squared_distribution<RealType, Policy>, RealType>& c)
{ // Quantile (or Percent Point) function.
return detail::nccs_quantile(c.dist, c.param, true);
} // quantile complement.
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_MATH_SPECIAL_NON_CENTRAL_CHI_SQUARE_HPP

View File

@@ -0,0 +1,409 @@
// boost\math\distributions\non_central_f.hpp
// Copyright John Maddock 2008.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_F_HPP
#define BOOST_MATH_SPECIAL_NON_CENTRAL_F_HPP
#include <boost/math/distributions/non_central_beta.hpp>
#include <boost/math/distributions/detail/generic_mode.hpp>
#include <boost/math/special_functions/pow.hpp>
namespace boost
{
namespace math
{
template <class RealType = double, class Policy = policies::policy<> >
class non_central_f_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
non_central_f_distribution(RealType v1_, RealType v2_, RealType lambda) : v1(v1_), v2(v2_), ncp(lambda)
{
const char* function = "boost::math::non_central_f_distribution<%1%>::non_central_f_distribution(%1%,%1%)";
RealType r;
detail::check_df(
function,
v1, &r, Policy());
detail::check_df(
function,
v2, &r, Policy());
detail::check_non_centrality(
function,
lambda,
&r,
Policy());
} // non_central_f_distribution constructor.
RealType degrees_of_freedom1()const
{
return v1;
}
RealType degrees_of_freedom2()const
{
return v2;
}
RealType non_centrality() const
{ // Private data getter function.
return ncp;
}
private:
// Data member, initialized by constructor.
RealType v1; // alpha.
RealType v2; // beta.
RealType ncp; // non-centrality parameter
}; // template <class RealType, class Policy> class non_central_f_distribution
typedef non_central_f_distribution<double> non_central_f; // Reserved name of type double.
// Non-member functions to give properties of the distribution.
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const non_central_f_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable k.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const non_central_f_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable k.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline RealType mean(const non_central_f_distribution<RealType, Policy>& dist)
{
const char* function = "mean(non_central_f_distribution<%1%> const&)";
RealType v1 = dist.degrees_of_freedom1();
RealType v2 = dist.degrees_of_freedom2();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
v1, &r, Policy())
||
!detail::check_df(
function,
v2, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
if(v2 <= 2)
return policies::raise_domain_error(
function,
"Second degrees of freedom parameter was %1%, but must be > 2 !",
v2, Policy());
return v2 * (v1 + l) / (v1 * (v2 - 2));
} // mean
template <class RealType, class Policy>
inline RealType mode(const non_central_f_distribution<RealType, Policy>& dist)
{ // mode.
static const char* function = "mode(non_central_chi_squared_distribution<%1%> const&)";
RealType n = dist.degrees_of_freedom1();
RealType m = dist.degrees_of_freedom2();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
n, &r, Policy())
||
!detail::check_df(
function,
m, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
return detail::generic_find_mode(
dist,
m * (n + l) / (n * (m - 2)),
function);
}
template <class RealType, class Policy>
inline RealType variance(const non_central_f_distribution<RealType, Policy>& dist)
{ // variance.
const char* function = "variance(non_central_f_distribution<%1%> const&)";
RealType n = dist.degrees_of_freedom1();
RealType m = dist.degrees_of_freedom2();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
n, &r, Policy())
||
!detail::check_df(
function,
m, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
if(m <= 4)
return policies::raise_domain_error(
function,
"Second degrees of freedom parameter was %1%, but must be > 4 !",
m, Policy());
RealType result = 2 * m * m * ((n + l) * (n + l)
+ (m - 2) * (n + 2 * l));
result /= (m - 4) * (m - 2) * (m - 2) * n * n;
return result;
}
// RealType standard_deviation(const non_central_f_distribution<RealType, Policy>& dist)
// standard_deviation provided by derived accessors.
template <class RealType, class Policy>
inline RealType skewness(const non_central_f_distribution<RealType, Policy>& dist)
{ // skewness = sqrt(l).
const char* function = "skewness(non_central_f_distribution<%1%> const&)";
BOOST_MATH_STD_USING
RealType n = dist.degrees_of_freedom1();
RealType m = dist.degrees_of_freedom2();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
n, &r, Policy())
||
!detail::check_df(
function,
m, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
if(m <= 6)
return policies::raise_domain_error(
function,
"Second degrees of freedom parameter was %1%, but must be > 6 !",
m, Policy());
RealType result = 2 * constants::root_two<RealType>();
result *= sqrt(m - 4);
result *= (n * (m + n - 2) *(m + 2 * n - 2)
+ 3 * (m + n - 2) * (m + 2 * n - 2) * l
+ 6 * (m + n - 2) * l * l + 2 * l * l * l);
result /= (m - 6) * pow(n * (m + n - 2) + 2 * (m + n - 2) * l + l * l, RealType(1.5f));
return result;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const non_central_f_distribution<RealType, Policy>& dist)
{
const char* function = "kurtosis_excess(non_central_f_distribution<%1%> const&)";
BOOST_MATH_STD_USING
RealType n = dist.degrees_of_freedom1();
RealType m = dist.degrees_of_freedom2();
RealType l = dist.non_centrality();
RealType r;
if(!detail::check_df(
function,
n, &r, Policy())
||
!detail::check_df(
function,
m, &r, Policy())
||
!detail::check_non_centrality(
function,
l,
&r,
Policy()))
return r;
if(m <= 8)
return policies::raise_domain_error(
function,
"Second degrees of freedom parameter was %1%, but must be > 8 !",
m, Policy());
RealType l2 = l * l;
RealType l3 = l2 * l;
RealType l4 = l2 * l2;
RealType result = (3 * (m - 4) * (n * (m + n - 2)
* (4 * (m - 2) * (m - 2)
+ (m - 2) * (m + 10) * n
+ (10 + m) * n * n)
+ 4 * (m + n - 2) * (4 * (m - 2) * (m - 2)
+ (m - 2) * (10 + m) * n
+ (10 + m) * n * n) * l + 2 * (10 + m)
* (m + n - 2) * (2 * m + 3 * n - 4) * l2
+ 4 * (10 + m) * (-2 + m + n) * l3
+ (10 + m) * l4))
/
((-8 + m) * (-6 + m) * boost::math::pow<2>(n * (-2 + m + n)
+ 2 * (-2 + m + n) * l + l2));
return result;
} // kurtosis_excess
template <class RealType, class Policy>
inline RealType kurtosis(const non_central_f_distribution<RealType, Policy>& dist)
{
return kurtosis_excess(dist) + 3;
}
template <class RealType, class Policy>
inline RealType pdf(const non_central_f_distribution<RealType, Policy>& dist, const RealType& x)
{ // Probability Density/Mass Function.
typedef typename policies::evaluation<RealType, 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;
value_type alpha = dist.degrees_of_freedom1() / 2;
value_type beta = dist.degrees_of_freedom2() / 2;
value_type y = x * alpha / beta;
value_type r = pdf(boost::math::non_central_beta_distribution<value_type, forwarding_policy>(alpha, beta, dist.non_centrality()), y / (1 + y));
return policies::checked_narrowing_cast<RealType, forwarding_policy>(
r * (dist.degrees_of_freedom1() / dist.degrees_of_freedom2()) / ((1 + y) * (1 + y)),
"pdf(non_central_f_distribution<%1%>, %1%)");
} // pdf
template <class RealType, class Policy>
RealType cdf(const non_central_f_distribution<RealType, Policy>& dist, const RealType& x)
{
const char* function = "cdf(const non_central_f_distribution<%1%>&, %1%)";
RealType r;
if(!detail::check_df(
function,
dist.degrees_of_freedom1(), &r, Policy())
||
!detail::check_df(
function,
dist.degrees_of_freedom2(), &r, Policy())
||
!detail::check_non_centrality(
function,
dist.non_centrality(),
&r,
Policy()))
return r;
if((x < 0) || !(boost::math::isfinite)(x))
{
return policies::raise_domain_error<RealType>(
function, "Random Variable parameter was %1%, but must be > 0 !", x, Policy());
}
RealType alpha = dist.degrees_of_freedom1() / 2;
RealType beta = dist.degrees_of_freedom2() / 2;
RealType y = x * alpha / beta;
RealType c = y / (1 + y);
RealType cp = 1 / (1 + y);
//
// To ensure accuracy, we pass both x and 1-x to the
// non-central beta cdf routine, this ensures accuracy
// even when we compute x to be ~ 1:
//
r = detail::non_central_beta_cdf(c, cp, alpha, beta,
dist.non_centrality(), false, Policy());
return r;
} // cdf
template <class RealType, class Policy>
RealType cdf(const complemented2_type<non_central_f_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function
const char* function = "cdf(complement(const non_central_f_distribution<%1%>&, %1%))";
RealType r;
if(!detail::check_df(
function,
c.dist.degrees_of_freedom1(), &r, Policy())
||
!detail::check_df(
function,
c.dist.degrees_of_freedom2(), &r, Policy())
||
!detail::check_non_centrality(
function,
c.dist.non_centrality(),
&r,
Policy()))
return r;
if((c.param < 0) || !(boost::math::isfinite)(c.param))
{
return policies::raise_domain_error<RealType>(
function, "Random Variable parameter was %1%, but must be > 0 !", c.param, Policy());
}
RealType alpha = c.dist.degrees_of_freedom1() / 2;
RealType beta = c.dist.degrees_of_freedom2() / 2;
RealType y = c.param * alpha / beta;
RealType x = y / (1 + y);
RealType cx = 1 / (1 + y);
//
// To ensure accuracy, we pass both x and 1-x to the
// non-central beta cdf routine, this ensures accuracy
// even when we compute x to be ~ 1:
//
r = detail::non_central_beta_cdf(x, cx, alpha, beta,
c.dist.non_centrality(), true, Policy());
return r;
} // ccdf
template <class RealType, class Policy>
inline RealType quantile(const non_central_f_distribution<RealType, Policy>& dist, const RealType& p)
{ // Quantile (or Percent Point) function.
RealType alpha = dist.degrees_of_freedom1() / 2;
RealType beta = dist.degrees_of_freedom2() / 2;
RealType x = quantile(boost::math::non_central_beta_distribution<RealType, Policy>(alpha, beta, dist.non_centrality()), p);
if(x == 1)
return policies::raise_overflow_error<RealType>(
"quantile(const non_central_f_distribution<%1%>&, %1%)",
"Result of non central F quantile is too large to represent.",
Policy());
return (x / (1 - x)) * (dist.degrees_of_freedom2() / dist.degrees_of_freedom1());
} // quantile
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<non_central_f_distribution<RealType, Policy>, RealType>& c)
{ // Quantile (or Percent Point) function.
RealType alpha = c.dist.degrees_of_freedom1() / 2;
RealType beta = c.dist.degrees_of_freedom2() / 2;
RealType x = quantile(complement(boost::math::non_central_beta_distribution<RealType, Policy>(alpha, beta, c.dist.non_centrality()), c.param));
if(x == 1)
return policies::raise_overflow_error<RealType>(
"quantile(complement(const non_central_f_distribution<%1%>&, %1%))",
"Result of non central F quantile is too large to represent.",
Policy());
return (x / (1 - x)) * (c.dist.degrees_of_freedom2() / c.dist.degrees_of_freedom1());
} // quantile complement.
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_MATH_SPECIAL_NON_CENTRAL_F_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,308 @@
// 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)
#ifndef BOOST_STATS_NORMAL_HPP
#define BOOST_STATS_NORMAL_HPP
// http://en.wikipedia.org/wiki/Normal_distribution
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm
// Also:
// Weisstein, Eric W. "Normal Distribution."
// From MathWorld--A Wolfram Web Resource.
// http://mathworld.wolfram.com/NormalDistribution.html
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/erf.hpp> // for erf/erfc.
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <utility>
namespace boost{ namespace math{
template <class RealType = double, class Policy = policies::policy<> >
class normal_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
normal_distribution(RealType mean = 0, RealType sd = 1)
: m_mean(mean), m_sd(sd)
{ // Default is a 'standard' normal distribution N01.
static const char* function = "boost::math::normal_distribution<%1%>::normal_distribution";
RealType result;
detail::check_scale(function, sd, &result, Policy());
detail::check_location(function, mean, &result, Policy());
}
RealType mean()const
{ // alias for location.
return m_mean;
}
RealType standard_deviation()const
{ // alias for scale.
return m_sd;
}
// Synonyms, provided to allow generic use of find_location and find_scale.
RealType location()const
{ // location.
return m_mean;
}
RealType scale()const
{ // scale.
return m_sd;
}
private:
//
// Data members:
//
RealType m_mean; // distribution mean or location.
RealType m_sd; // distribution standard deviation or scale.
}; // class normal_distribution
typedef normal_distribution<double> normal;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const normal_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value.
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const normal_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + max value.
}
template <class RealType, class Policy>
inline RealType pdf(const normal_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType sd = dist.standard_deviation();
RealType mean = dist.mean();
static const char* function = "boost::math::pdf(const normal_distribution<%1%>&, %1%)";
if((boost::math::isinf)(x))
{
return 0; // pdf + and - infinity is zero.
}
// Below produces MSVC 4127 warnings, so the above used instead.
//if(std::numeric_limits<RealType>::has_infinity && abs(x) == std::numeric_limits<RealType>::infinity())
//{ // pdf + and - infinity is zero.
// return 0;
//}
RealType result;
if(false == detail::check_scale(function, sd, &result, Policy()))
{
return result;
}
if(false == detail::check_location(function, mean, &result, Policy()))
{
return result;
}
if(false == detail::check_x(function, x, &result, Policy()))
{
return result;
}
RealType exponent = x - mean;
exponent *= -exponent;
exponent /= 2 * sd * sd;
result = exp(exponent);
result /= sd * sqrt(2 * constants::pi<RealType>());
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const normal_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType sd = dist.standard_deviation();
RealType mean = dist.mean();
static const char* function = "boost::math::cdf(const normal_distribution<%1%>&, %1%)";
RealType result;
if(false == detail::check_scale(function, sd, &result, Policy()))
{
return result;
}
if(false == detail::check_location(function, mean, &result, Policy()))
{
return result;
}
if((boost::math::isinf)(x))
{
if(x < 0) return 0; // -infinity
return 1; // + infinity
}
// These produce MSVC 4127 warnings, so the above used instead.
//if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
//{ // cdf +infinity is unity.
// return 1;
//}
//if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
//{ // cdf -infinity is zero.
// return 0;
//}
if(false == detail::check_x(function, x, &result, Policy()))
{
return result;
}
RealType diff = (x - mean) / (sd * constants::root_two<RealType>());
result = boost::math::erfc(-diff, Policy()) / 2;
return result;
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const normal_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType sd = dist.standard_deviation();
RealType mean = dist.mean();
static const char* function = "boost::math::quantile(const normal_distribution<%1%>&, %1%)";
RealType result;
if(false == detail::check_scale(function, sd, &result, Policy()))
return result;
if(false == detail::check_location(function, mean, &result, Policy()))
return result;
if(false == detail::check_probability(function, p, &result, Policy()))
return result;
result= boost::math::erfc_inv(2 * p, Policy());
result = -result;
result *= sd * constants::root_two<RealType>();
result += mean;
return result;
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<normal_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType sd = c.dist.standard_deviation();
RealType mean = c.dist.mean();
RealType x = c.param;
static const char* function = "boost::math::cdf(const complement(normal_distribution<%1%>&), %1%)";
if((boost::math::isinf)(x))
{
if(x < 0) return 1; // cdf complement -infinity is unity.
return 0; // cdf complement +infinity is zero
}
// These produce MSVC 4127 warnings, so the above used instead.
//if(std::numeric_limits<RealType>::has_infinity && x == std::numeric_limits<RealType>::infinity())
//{ // cdf complement +infinity is zero.
// return 0;
//}
//if(std::numeric_limits<RealType>::has_infinity && x == -std::numeric_limits<RealType>::infinity())
//{ // cdf complement -infinity is unity.
// return 1;
//}
RealType result;
if(false == detail::check_scale(function, sd, &result, Policy()))
return result;
if(false == detail::check_location(function, mean, &result, Policy()))
return result;
if(false == detail::check_x(function, x, &result, Policy()))
return result;
RealType diff = (x - mean) / (sd * constants::root_two<RealType>());
result = boost::math::erfc(diff, Policy()) / 2;
return result;
} // cdf complement
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<normal_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType sd = c.dist.standard_deviation();
RealType mean = c.dist.mean();
static const char* function = "boost::math::quantile(const complement(normal_distribution<%1%>&), %1%)";
RealType result;
if(false == detail::check_scale(function, sd, &result, Policy()))
return result;
if(false == detail::check_location(function, mean, &result, Policy()))
return result;
RealType q = c.param;
if(false == detail::check_probability(function, q, &result, Policy()))
return result;
result = boost::math::erfc_inv(2 * q, Policy());
result *= sd * constants::root_two<RealType>();
result += mean;
return result;
} // quantile
template <class RealType, class Policy>
inline RealType mean(const normal_distribution<RealType, Policy>& dist)
{
return dist.mean();
}
template <class RealType, class Policy>
inline RealType standard_deviation(const normal_distribution<RealType, Policy>& dist)
{
return dist.standard_deviation();
}
template <class RealType, class Policy>
inline RealType mode(const normal_distribution<RealType, Policy>& dist)
{
return dist.mean();
}
template <class RealType, class Policy>
inline RealType median(const normal_distribution<RealType, Policy>& dist)
{
return dist.mean();
}
template <class RealType, class Policy>
inline RealType skewness(const normal_distribution<RealType, Policy>& /*dist*/)
{
return 0;
}
template <class RealType, class Policy>
inline RealType kurtosis(const normal_distribution<RealType, Policy>& /*dist*/)
{
return 3;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const normal_distribution<RealType, Policy>& /*dist*/)
{
return 0;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_NORMAL_HPP

View File

@@ -0,0 +1,443 @@
// 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_STATS_PARETO_HPP
#define BOOST_STATS_PARETO_HPP
// http://en.wikipedia.org/wiki/Pareto_distribution
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3661.htm
// Also:
// Weisstein, Eric W. "Pareto Distribution."
// From MathWorld--A Wolfram Web Resource.
// http://mathworld.wolfram.com/ParetoDistribution.html
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/special_functions/powm1.hpp>
#include <utility> // for BOOST_CURRENT_VALUE?
namespace boost
{
namespace math
{
namespace detail
{ // Parameter checking.
template <class RealType, class Policy>
inline bool check_pareto_location(
const char* function,
RealType location,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(location))
{ // any > 0 finite value is OK.
if (location > 0)
{
return true;
}
else
{
*result = policies::raise_domain_error<RealType>(
function,
"Location parameter is %1%, but must be > 0!", location, pol);
return false;
}
}
else
{ // Not finite.
*result = policies::raise_domain_error<RealType>(
function,
"Location parameter is %1%, but must be finite!", location, pol);
return false;
}
} // bool check_pareto_location
template <class RealType, class Policy>
inline bool check_pareto_shape(
const char* function,
RealType shape,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(shape))
{ // Any finite value > 0 is OK.
if (shape > 0)
{
return true;
}
else
{
*result = policies::raise_domain_error<RealType>(
function,
"Shape parameter is %1%, but must be > 0!", shape, pol);
return false;
}
}
else
{ // Not finite.
*result = policies::raise_domain_error<RealType>(
function,
"Shape parameter is %1%, but must be finite!", shape, pol);
return false;
}
} // bool check_pareto_shape(
template <class RealType, class Policy>
inline bool check_pareto_x(
const char* function,
RealType const& x,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(x))
{ //
if (x > 0)
{
return true;
}
else
{
*result = policies::raise_domain_error<RealType>(
function,
"x parameter is %1%, but must be > 0 !", x, pol);
return false;
}
}
else
{ // Not finite..
*result = policies::raise_domain_error<RealType>(
function,
"x parameter is %1%, but must be finite!", x, pol);
return false;
}
} // bool check_pareto_x
template <class RealType, class Policy>
inline bool check_pareto( // distribution parameters.
const char* function,
RealType location,
RealType shape,
RealType* result, const Policy& pol)
{
return check_pareto_location(function, location, result, pol)
&& check_pareto_shape(function, shape, result, pol);
} // bool check_pareto(
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class pareto_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
pareto_distribution(RealType location = 1, RealType shape = 1)
: m_location(location), m_shape(shape)
{ // Constructor.
RealType result;
detail::check_pareto("boost::math::pareto_distribution<%1%>::pareto_distribution", location, shape, &result, Policy());
}
RealType location()const
{ // AKA Xm and b
return m_location;
}
RealType shape()const
{ // AKA k and a
return m_shape;
}
private:
// Data members:
RealType m_location; // distribution location (xm)
RealType m_shape; // distribution shape (k)
};
typedef pareto_distribution<double> pareto; // Convenience to allow pareto(2., 3.);
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const pareto_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>()); // location zero to + infinity.
} // range
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const pareto_distribution<RealType, Policy>& dist)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(dist.location(), max_value<RealType>() ); // location to + infinity.
} // support
template <class RealType, class Policy>
inline RealType pdf(const pareto_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std function pow.
static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
RealType location = dist.location();
RealType shape = dist.shape();
RealType result;
if(false == (detail::check_pareto_x(function, x, &result, Policy())
&& detail::check_pareto(function, location, shape, &result, Policy())))
return result;
if (x < location)
{ // regardless of shape, pdf is zero.
return 0;
}
result = shape * pow(location, shape) / pow(x, shape+1);
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const pareto_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std function pow.
static const char* function = "boost::math::cdf(const pareto_distribution<%1%>&, %1%)";
RealType location = dist.location();
RealType shape = dist.shape();
RealType result;
if(false == (detail::check_pareto_x(function, x, &result, Policy())
&& detail::check_pareto(function, location, shape, &result, Policy())))
return result;
if (x <= location)
{ // regardless of shape, cdf is zero.
return 0;
}
// result = RealType(1) - pow((location / x), shape);
result = -boost::math::powm1(location/x, shape, Policy()); // should be more accurate.
return result;
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const pareto_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std function pow.
static const char* function = "boost::math::quantile(const pareto_distribution<%1%>&, %1%)";
RealType result;
RealType location = dist.location();
RealType shape = dist.shape();
if(false == (detail::check_probability(function, p, &result, Policy())
&& detail::check_pareto(function, location, shape, &result, Policy())))
{
return result;
}
if (p == 0)
{
return location; // x must be location (or less).
}
if (p == 1)
{
return tools::max_value<RealType>(); // x = + infinity.
}
result = location /
(pow((1 - p), 1 / shape));
// K. Krishnamoorthy, ISBN 1-58488-635-8 eq 23.1.3
return result;
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<pareto_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std function pow.
static const char* function = "boost::math::cdf(const pareto_distribution<%1%>&, %1%)";
RealType result;
RealType x = c.param;
RealType location = c.dist.location();
RealType shape = c.dist.shape();
if(false == (detail::check_pareto_x(function, x, &result, Policy())
&& detail::check_pareto(function, location, shape, &result, Policy())))
return result;
if (x <= location)
{ // regardless of shape, cdf is zero, and complement is unity.
return 1;
}
result = pow((location/x), shape);
return result;
} // cdf complement
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<pareto_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std function pow.
static const char* function = "boost::math::quantile(const pareto_distribution<%1%>&, %1%)";
RealType result;
RealType q = c.param;
RealType location = c.dist.location();
RealType shape = c.dist.shape();
if(false == (detail::check_probability(function, q, &result, Policy())
&& detail::check_pareto(function, location, shape, &result, Policy())))
{
return result;
}
if (q == 1)
{
return location; // x must be location (or less).
}
if (q == 0)
{
return tools::max_value<RealType>(); // x = + infinity.
}
result = location / (pow(q, 1 / shape));
// K. Krishnamoorthy, ISBN 1-58488-635-8 eq 23.1.3
return result;
} // quantile complement
template <class RealType, class Policy>
inline RealType mean(const pareto_distribution<RealType, Policy>& dist)
{
RealType result;
static const char* function = "boost::math::mean(const pareto_distribution<%1%>&, %1%)";
if(false == detail::check_pareto(function, dist.location(), dist.shape(), &result, Policy()))
{
return result;
}
if (dist.shape() > RealType(1))
{
return dist.shape() * dist.location() / (dist.shape() - 1);
}
else
{
using boost::math::tools::max_value;
return max_value<RealType>(); // +infinity.
}
} // mean
template <class RealType, class Policy>
inline RealType mode(const pareto_distribution<RealType, Policy>& dist)
{
return dist.location();
} // mode
template <class RealType, class Policy>
inline RealType median(const pareto_distribution<RealType, Policy>& dist)
{
RealType result;
static const char* function = "boost::math::median(const pareto_distribution<%1%>&, %1%)";
if(false == detail::check_pareto(function, dist.location(), dist.shape(), &result, Policy()))
{
return result;
}
BOOST_MATH_STD_USING
return dist.location() * pow(RealType(2), (1/dist.shape()));
} // median
template <class RealType, class Policy>
inline RealType variance(const pareto_distribution<RealType, Policy>& dist)
{
RealType result;
RealType location = dist.location();
RealType shape = dist.shape();
static const char* function = "boost::math::variance(const pareto_distribution<%1%>&, %1%)";
if(false == detail::check_pareto(function, location, shape, &result, Policy()))
{
return result;
}
if (shape > 2)
{
result = (location * location * shape) /
((shape - 1) * (shape - 1) * (shape - 2));
}
else
{
result = policies::raise_domain_error<RealType>(
function,
"variance is undefined for shape <= 2, but got %1%.", dist.shape(), Policy());
}
return result;
} // variance
template <class RealType, class Policy>
inline RealType skewness(const pareto_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING
RealType result;
RealType shape = dist.shape();
static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
if(false == detail::check_pareto(function, dist.location(), shape, &result, Policy()))
{
return result;
}
if (shape > 3)
{
result = sqrt((shape - 2) / shape) *
2 * (shape + 1) /
(shape - 3);
}
else
{
result = policies::raise_domain_error<RealType>(
function,
"skewness is undefined for shape <= 3, but got %1%.", dist.shape(), Policy());
}
return result;
} // skewness
template <class RealType, class Policy>
inline RealType kurtosis(const pareto_distribution<RealType, Policy>& dist)
{
RealType result;
RealType shape = dist.shape();
static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
if(false == detail::check_pareto(function, dist.location(), shape, &result, Policy()))
{
return result;
}
if (shape > 4)
{
result = 3 * ((shape - 2) * (3 * shape * shape + shape + 2)) /
(shape * (shape - 3) * (shape - 4));
}
else
{
result = policies::raise_domain_error<RealType>(
function,
"kurtosis_excess is undefined for shape <= 4, but got %1%.", shape, Policy());
}
return result;
} // kurtosis
template <class RealType, class Policy>
inline RealType kurtosis_excess(const pareto_distribution<RealType, Policy>& dist)
{
RealType result;
RealType shape = dist.shape();
static const char* function = "boost::math::pdf(const pareto_distribution<%1%>&, %1%)";
if(false == detail::check_pareto(function, dist.location(), shape, &result, Policy()))
{
return result;
}
if (shape > 4)
{
result = 6 * ((shape * shape * shape) + (shape * shape) - 6 * shape - 2) /
(shape * (shape - 3) * (shape - 4));
}
else
{
result = policies::raise_domain_error<RealType>(
function,
"kurtosis_excess is undefined for shape <= 4, but got %1%.", dist.shape(), Policy());
}
return result;
} // kurtosis_excess
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_PARETO_HPP

View File

@@ -0,0 +1,588 @@
// boost\math\distributions\poisson.hpp
// 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)
// Poisson distribution is a discrete probability distribution.
// It expresses the probability of a number (k) of
// events, occurrences, failures or arrivals occurring in a fixed time,
// assuming these events occur with a known average or mean rate (lambda)
// and are independent of the time since the last event.
// The distribution was discovered by Simeon-Denis Poisson (1781-1840).
// Parameter lambda is the mean number of events in the given time interval.
// The random variate k is the number of events, occurrences or arrivals.
// k argument may be integral, signed, or unsigned, or floating point.
// If necessary, it has already been promoted from an integral type.
// Note that the Poisson distribution
// (like others including the binomial, negative binomial & Bernoulli)
// is strictly defined as a discrete function:
// only integral values of k are envisaged.
// However because the method of calculation uses a continuous gamma function,
// it is convenient to treat it as if a continous function,
// and permit non-integral values of k.
// To enforce the strict mathematical model, users should use floor or ceil functions
// on k outside this function to ensure that k is integral.
// See http://en.wikipedia.org/wiki/Poisson_distribution
// http://documents.wolfram.com/v5/Add-onsLinks/StandardPackages/Statistics/DiscreteDistributions.html
#ifndef BOOST_MATH_SPECIAL_POISSON_HPP
#define BOOST_MATH_SPECIAL_POISSON_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/gamma.hpp> // for incomplete gamma. gamma_q
#include <boost/math/special_functions/trunc.hpp> // for incomplete gamma. gamma_q
#include <boost/math/distributions/complement.hpp> // complements
#include <boost/math/distributions/detail/common_error_handling.hpp> // error checks
#include <boost/math/special_functions/fpclassify.hpp> // isnan.
#include <boost/math/special_functions/factorials.hpp> // factorials.
#include <boost/math/tools/roots.hpp> // for root finding.
#include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
#include <utility>
namespace boost
{
namespace math
{
namespace detail{
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_nearest>&,
boost::uintmax_t& max_iter);
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_up>&,
boost::uintmax_t& max_iter);
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_down>&,
boost::uintmax_t& max_iter);
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_outwards>&,
boost::uintmax_t& max_iter);
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::integer_round_inwards>&,
boost::uintmax_t& max_iter);
template <class Dist>
inline typename Dist::value_type
inverse_discrete_quantile(
const Dist& dist,
const typename Dist::value_type& p,
const typename Dist::value_type& guess,
const typename Dist::value_type& multiplier,
const typename Dist::value_type& adder,
const policies::discrete_quantile<policies::real>&,
boost::uintmax_t& max_iter);
}
namespace poisson_detail
{
// Common error checking routines for Poisson distribution functions.
// These are convoluted, & apparently redundant, to try to ensure that
// checks are always performed, even if exceptions are not enabled.
template <class RealType, class Policy>
inline bool check_mean(const char* function, const RealType& mean, RealType* result, const Policy& pol)
{
if(!(boost::math::isfinite)(mean) || (mean < 0))
{
*result = policies::raise_domain_error<RealType>(
function,
"Mean argument is %1%, but must be >= 0 !", mean, pol);
return false;
}
return true;
} // bool check_mean
template <class RealType, class Policy>
inline bool check_mean_NZ(const char* function, const RealType& mean, RealType* result, const Policy& pol)
{ // mean == 0 is considered an error.
if( !(boost::math::isfinite)(mean) || (mean <= 0))
{
*result = policies::raise_domain_error<RealType>(
function,
"Mean argument is %1%, but must be > 0 !", mean, pol);
return false;
}
return true;
} // bool check_mean_NZ
template <class RealType, class Policy>
inline bool check_dist(const char* function, const RealType& mean, RealType* result, const Policy& pol)
{ // Only one check, so this is redundant really but should be optimized away.
return check_mean_NZ(function, mean, result, pol);
} // bool check_dist
template <class RealType, class Policy>
inline bool check_k(const char* function, const RealType& k, RealType* result, const Policy& pol)
{
if((k < 0) || !(boost::math::isfinite)(k))
{
*result = policies::raise_domain_error<RealType>(
function,
"Number of events k argument is %1%, but must be >= 0 !", k, pol);
return false;
}
return true;
} // bool check_k
template <class RealType, class Policy>
inline bool check_dist_and_k(const char* function, RealType mean, RealType k, RealType* result, const Policy& pol)
{
if((check_dist(function, mean, result, pol) == false) ||
(check_k(function, k, result, pol) == false))
{
return false;
}
return true;
} // bool check_dist_and_k
template <class RealType, class Policy>
inline bool check_prob(const char* function, const RealType& p, RealType* result, const Policy& pol)
{ // Check 0 <= p <= 1
if(!(boost::math::isfinite)(p) || (p < 0) || (p > 1))
{
*result = policies::raise_domain_error<RealType>(
function,
"Probability argument is %1%, but must be >= 0 and <= 1 !", p, pol);
return false;
}
return true;
} // bool check_prob
template <class RealType, class Policy>
inline bool check_dist_and_prob(const char* function, RealType mean, RealType p, RealType* result, const Policy& pol)
{
if((check_dist(function, mean, result, pol) == false) ||
(check_prob(function, p, result, pol) == false))
{
return false;
}
return true;
} // bool check_dist_and_prob
} // namespace poisson_detail
template <class RealType = double, class Policy = policies::policy<> >
class poisson_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
poisson_distribution(RealType mean = 1) : m_l(mean) // mean (lambda).
{ // Expected mean number of events that occur during the given interval.
RealType r;
poisson_detail::check_dist(
"boost::math::poisson_distribution<%1%>::poisson_distribution",
m_l,
&r, Policy());
} // poisson_distribution constructor.
RealType mean() const
{ // Private data getter function.
return m_l;
}
private:
// Data member, initialized by constructor.
RealType m_l; // mean number of occurrences.
}; // template <class RealType, class Policy> class poisson_distribution
typedef poisson_distribution<double> poisson; // Reserved name of type double.
// Non-member functions to give properties of the distribution.
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const poisson_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable k.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>()); // Max integer?
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const poisson_distribution<RealType, Policy>& /* dist */)
{ // Range of supported values for random variable k.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline RealType mean(const poisson_distribution<RealType, Policy>& dist)
{ // Mean of poisson distribution = lambda.
return dist.mean();
} // mean
template <class RealType, class Policy>
inline RealType mode(const poisson_distribution<RealType, Policy>& dist)
{ // mode.
BOOST_MATH_STD_USING // ADL of std functions.
return floor(dist.mean());
}
//template <class RealType, class Policy>
//inline RealType median(const poisson_distribution<RealType, Policy>& dist)
//{ // median = approximately lambda + 1/3 - 0.2/lambda
// RealType l = dist.mean();
// return dist.mean() + static_cast<RealType>(0.3333333333333333333333333333333333333333333333)
// - static_cast<RealType>(0.2) / l;
//} // BUT this formula appears to be out-by-one compared to quantile(half)
// Query posted on Wikipedia.
// Now implemented via quantile(half) in derived accessors.
template <class RealType, class Policy>
inline RealType variance(const poisson_distribution<RealType, Policy>& dist)
{ // variance.
return dist.mean();
}
// RealType standard_deviation(const poisson_distribution<RealType, Policy>& dist)
// standard_deviation provided by derived accessors.
template <class RealType, class Policy>
inline RealType skewness(const poisson_distribution<RealType, Policy>& dist)
{ // skewness = sqrt(l).
BOOST_MATH_STD_USING // ADL of std functions.
return 1 / sqrt(dist.mean());
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const poisson_distribution<RealType, Policy>& dist)
{ // skewness = sqrt(l).
return 1 / dist.mean(); // kurtosis_excess 1/mean from Wiki & MathWorld eq 31.
// http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess
// is more convenient because the kurtosis excess of a normal distribution is zero
// whereas the true kurtosis is 3.
} // RealType kurtosis_excess
template <class RealType, class Policy>
inline RealType kurtosis(const poisson_distribution<RealType, Policy>& dist)
{ // kurtosis is 4th moment about the mean = u4 / sd ^ 4
// http://en.wikipedia.org/wiki/Curtosis
// kurtosis can range from -2 (flat top) to +infinity (sharp peak & heavy tails).
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda35b.htm
return 3 + 1 / dist.mean(); // NIST.
// http://mathworld.wolfram.com/Kurtosis.html explains that the kurtosis excess
// is more convenient because the kurtosis excess of a normal distribution is zero
// whereas the true kurtosis is 3.
} // RealType kurtosis
template <class RealType, class Policy>
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
BOOST_MATH_STD_USING // for ADL of std functions.
RealType mean = dist.mean();
// Error check:
RealType result;
if(false == poisson_detail::check_dist_and_k(
"boost::math::pdf(const poisson_distribution<%1%>&, %1%)",
mean,
k,
&result, Policy()))
{
return result;
}
// Special case of mean zero, regardless of the number of events k.
if (mean == 0)
{ // Probability for any k is zero.
return 0;
}
if (k == 0)
{ // mean ^ k = 1, and k! = 1, so can simplify.
return exp(-mean);
}
return boost::math::gamma_p_derivative(k+1, mean, Policy());
} // pdf
template <class RealType, class Policy>
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.
// If necessary, it has already been promoted from an integral type.
// Returns the sum of the terms 0 through k of the Poisson Probability Density or Mass (pdf).
// But note that the Poisson distribution
// (like others including the binomial, negative binomial & Bernoulli)
// is strictly defined as a discrete function: only integral values of k are envisaged.
// However because of the method of calculation using a continuous gamma function,
// it is convenient to treat it as if it is a continous function
// and permit non-integral values of k.
// To enforce the strict mathematical model, users should use floor or ceil functions
// outside this function to ensure that k is integral.
// The terms are not summed directly (at least for larger k)
// instead the incomplete gamma integral is employed,
BOOST_MATH_STD_USING // for ADL of std function exp.
RealType mean = dist.mean();
// Error checks:
RealType result;
if(false == poisson_detail::check_dist_and_k(
"boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
mean,
k,
&result, Policy()))
{
return result;
}
// Special cases:
if (mean == 0)
{ // Probability for any k is zero.
return 0;
}
if (k == 0)
{ // return pdf(dist, static_cast<RealType>(0));
// but mean (and k) have already been checked,
// so this avoids unnecessary repeated checks.
return exp(-mean);
}
// For small integral k could use a finite sum -
// it's cheaper than the gamma function.
// BUT this is now done efficiently by gamma_q function.
// Calculate poisson cdf using the gamma_q function.
return gamma_q(k+1, mean, Policy());
} // binomial cdf
template <class RealType, class Policy>
RealType cdf(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
{ // Complemented Cumulative Distribution Function Poisson
// The random variate k is the number of events, occurrences or arrivals.
// k argument may be integral, signed, or unsigned, or floating point.
// If necessary, it has already been promoted from an integral type.
// But note that the Poisson distribution
// (like others including the binomial, negative binomial & Bernoulli)
// is strictly defined as a discrete function: only integral values of k are envisaged.
// However because of the method of calculation using a continuous gamma function,
// it is convenient to treat it as is it is a continous function
// and permit non-integral values of k.
// To enforce the strict mathematical model, users should use floor or ceil functions
// outside this function to ensure that k is integral.
// Returns the sum of the terms k+1 through inf of the Poisson Probability Density/Mass (pdf).
// The terms are not summed directly (at least for larger k)
// instead the incomplete gamma integral is employed,
RealType const& k = c.param;
poisson_distribution<RealType, Policy> const& dist = c.dist;
RealType mean = dist.mean();
// Error checks:
RealType result;
if(false == poisson_detail::check_dist_and_k(
"boost::math::cdf(const poisson_distribution<%1%>&, %1%)",
mean,
k,
&result, Policy()))
{
return result;
}
// Special case of mean, regardless of the number of events k.
if (mean == 0)
{ // Probability for any k is unity, complement of zero.
return 1;
}
if (k == 0)
{ // Avoid repeated checks on k and mean in gamma_p.
return -boost::math::expm1(-mean, Policy());
}
// Unlike un-complemented cdf (sum from 0 to k),
// can't use finite sum from k+1 to infinity for small integral k,
// anyway it is now done efficiently by gamma_p.
return gamma_p(k + 1, mean, Policy()); // Calculate Poisson cdf using the gamma_p function.
// CCDF = gamma_p(k+1, lambda)
} // poisson ccdf
template <class RealType, class Policy>
inline RealType quantile(const poisson_distribution<RealType, Policy>& dist, const RealType& p)
{ // Quantile (or Percent Point) Poisson function.
// Return the number of expected events k for a given probability p.
RealType result; // of Argument checks:
if(false == poisson_detail::check_prob(
"boost::math::quantile(const poisson_distribution<%1%>&, %1%)",
p,
&result, Policy()))
{
return result;
}
// Special case:
if (dist.mean() == 0)
{ // if mean = 0 then p = 0, so k can be anything?
if (false == poisson_detail::check_mean_NZ(
"boost::math::quantile(const poisson_distribution<%1%>&, %1%)",
dist.mean(),
&result, Policy()))
{
return result;
}
}
/*
BOOST_MATH_STD_USING // ADL of std functions.
// if(p == 0) NOT necessarily zero!
// Not necessarily any special value of k because is unlimited.
if (p <= exp(-dist.mean()))
{ // if p <= cdf for 0 events (== pdf for 0 events), then quantile must be zero.
return 0;
}
return gamma_q_inva(dist.mean(), p, Policy()) - 1;
*/
typedef typename Policy::discrete_quantile_type discrete_type;
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
RealType guess, factor = 8;
RealType z = dist.mean();
if(z < 1)
guess = z;
else
guess = boost::math::detail::inverse_poisson_cornish_fisher(z, p, 1-p, Policy());
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;
}
return detail::inverse_discrete_quantile(
dist,
p,
1-p,
guess,
factor,
RealType(1),
discrete_type(),
max_iter);
} // quantile
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<poisson_distribution<RealType, Policy>, RealType>& c)
{ // Quantile (or Percent Point) of Poisson function.
// Return the number of expected events k for a given
// complement of the probability q.
//
// Error checks:
RealType q = c.param;
const poisson_distribution<RealType, Policy>& dist = c.dist;
RealType result; // of argument checks.
if(false == poisson_detail::check_prob(
"boost::math::quantile(const poisson_distribution<%1%>&, %1%)",
q,
&result, Policy()))
{
return result;
}
// Special case:
if (dist.mean() == 0)
{ // if mean = 0 then p = 0, so k can be anything?
if (false == poisson_detail::check_mean_NZ(
"boost::math::quantile(const poisson_distribution<%1%>&, %1%)",
dist.mean(),
&result, Policy()))
{
return result;
}
}
/*
if (-q <= boost::math::expm1(-dist.mean()))
{ // if q <= cdf(complement for 0 events, then quantile must be zero.
return 0;
}
return gamma_p_inva(dist.mean(), q, Policy()) -1;
*/
typedef typename Policy::discrete_quantile_type discrete_type;
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
RealType guess, factor = 8;
RealType z = dist.mean();
if(z < 1)
guess = z;
else
guess = boost::math::detail::inverse_poisson_cornish_fisher(z, 1-q, q, Policy());
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;
}
return detail::inverse_discrete_quantile(
dist,
1-q,
q,
guess,
factor,
RealType(1),
discrete_type(),
max_iter);
} // quantile complement.
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#include <boost/math/distributions/detail/inv_discrete_quantile.hpp>
#endif // BOOST_MATH_SPECIAL_POISSON_HPP

View File

@@ -0,0 +1,293 @@
// 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_STATS_rayleigh_HPP
#define BOOST_STATS_rayleigh_HPP
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/config/no_tr1/cmath.hpp>
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4702) // unreachable code (return after domain_error throw).
#endif
#include <utility>
namespace boost{ namespace math{
namespace detail
{ // Error checks:
template <class RealType, class Policy>
inline bool verify_sigma(const char* function, RealType sigma, RealType* presult, const Policy& pol)
{
if(sigma <= 0)
{
*presult = policies::raise_domain_error<RealType>(
function,
"The scale parameter \"sigma\" must be > 0, but was: %1%.", sigma, pol);
return false;
}
return true;
} // bool verify_sigma
template <class RealType, class Policy>
inline bool verify_rayleigh_x(const char* function, RealType x, RealType* presult, const Policy& pol)
{
if(x < 0)
{
*presult = policies::raise_domain_error<RealType>(
function,
"The random variable must be >= 0, but was: %1%.", x, pol);
return false;
}
return true;
} // bool verify_rayleigh_x
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class rayleigh_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
rayleigh_distribution(RealType sigma = 1)
: m_sigma(sigma)
{
RealType err;
detail::verify_sigma("boost::math::rayleigh_distribution<%1%>::rayleigh_distribution", sigma, &err, Policy());
} // rayleigh_distribution
RealType sigma()const
{ // Accessor.
return m_sigma;
}
private:
RealType m_sigma;
}; // class rayleigh_distribution
typedef rayleigh_distribution<double> rayleigh;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const rayleigh_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(static_cast<RealType>(1), max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const rayleigh_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>((1), max_value<RealType>());
}
template <class RealType, class Policy>
inline RealType pdf(const rayleigh_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std function exp.
RealType sigma = dist.sigma();
RealType result;
static const char* function = "boost::math::pdf(const rayleigh_distribution<%1%>&, %1%)";
if(false == detail::verify_sigma(function, sigma, &result, Policy()))
{
return result;
}
if(false == detail::verify_rayleigh_x(function, x, &result, Policy()))
{
return result;
}
RealType sigmasqr = sigma * sigma;
result = x * (exp(-(x * x) / ( 2 * sigmasqr))) / sigmasqr;
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const rayleigh_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType result;
RealType sigma = dist.sigma();
static const char* function = "boost::math::cdf(const rayleigh_distribution<%1%>&, %1%)";
if(false == detail::verify_sigma(function, sigma, &result, Policy()))
{
return result;
}
if(false == detail::verify_rayleigh_x(function, x, &result, Policy()))
{
return result;
}
result = -boost::math::expm1(-x * x / ( 2 * sigma * sigma), Policy());
return result;
} // cdf
template <class RealType, class Policy>
inline RealType quantile(const rayleigh_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType result;
RealType sigma = dist.sigma();
static const char* function = "boost::math::quantile(const rayleigh_distribution<%1%>&, %1%)";
if(false == detail::verify_sigma(function, sigma, &result, Policy()))
return result;
if(false == detail::check_probability(function, p, &result, Policy()))
return result;
if(p == 0)
{
return 0;
}
if(p == 1)
{
return policies::raise_overflow_error<RealType>(function, 0, Policy());
}
result = sqrt(-2 * sigma * sigma * boost::math::log1p(-p, Policy()));
return result;
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<rayleigh_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
RealType result;
RealType sigma = c.dist.sigma();
static const char* function = "boost::math::cdf(const rayleigh_distribution<%1%>&, %1%)";
if(false == detail::verify_sigma(function, sigma, &result, Policy()))
{
return result;
}
RealType x = c.param;
if(false == detail::verify_rayleigh_x(function, x, &result, Policy()))
{
return result;
}
result = exp(-x * x / ( 2 * sigma * sigma));
return result;
} // cdf complement
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<rayleigh_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions, log & sqrt.
RealType result;
RealType sigma = c.dist.sigma();
static const char* function = "boost::math::quantile(const rayleigh_distribution<%1%>&, %1%)";
if(false == detail::verify_sigma(function, sigma, &result, Policy()))
{
return result;
}
RealType q = c.param;
if(false == detail::check_probability(function, q, &result, Policy()))
{
return result;
}
if(q == 1)
{
return 0;
}
if(q == 0)
{
return policies::raise_overflow_error<RealType>(function, 0, Policy());
}
result = sqrt(-2 * sigma * sigma * log(q));
return result;
} // quantile complement
template <class RealType, class Policy>
inline RealType mean(const rayleigh_distribution<RealType, Policy>& dist)
{
RealType result;
RealType sigma = dist.sigma();
static const char* function = "boost::math::mean(const rayleigh_distribution<%1%>&, %1%)";
if(false == detail::verify_sigma(function, sigma, &result, Policy()))
{
return result;
}
using boost::math::constants::root_half_pi;
return sigma * root_half_pi<RealType>();
} // mean
template <class RealType, class Policy>
inline RealType variance(const rayleigh_distribution<RealType, Policy>& dist)
{
RealType result;
RealType sigma = dist.sigma();
static const char* function = "boost::math::variance(const rayleigh_distribution<%1%>&, %1%)";
if(false == detail::verify_sigma(function, sigma, &result, Policy()))
{
return result;
}
using boost::math::constants::four_minus_pi;
return four_minus_pi<RealType>() * sigma * sigma / 2;
} // variance
template <class RealType, class Policy>
inline RealType mode(const rayleigh_distribution<RealType, Policy>& dist)
{
return dist.sigma();
}
template <class RealType, class Policy>
inline RealType median(const rayleigh_distribution<RealType, Policy>& dist)
{
using boost::math::constants::root_ln_four;
return root_ln_four<RealType>() * dist.sigma();
}
template <class RealType, class Policy>
inline RealType skewness(const rayleigh_distribution<RealType, Policy>& /*dist*/)
{
// using namespace boost::math::constants;
return static_cast<RealType>(0.63111065781893713819189935154422777984404221106391L);
// Computed using NTL at 150 bit, about 50 decimal digits.
// return 2 * root_pi<RealType>() * pi_minus_three<RealType>() / pow23_four_minus_pi<RealType>();
}
template <class RealType, class Policy>
inline RealType kurtosis(const rayleigh_distribution<RealType, Policy>& /*dist*/)
{
// using namespace boost::math::constants;
return static_cast<RealType>(3.2450893006876380628486604106197544154170667057995L);
// Computed using NTL at 150 bit, about 50 decimal digits.
// return 3 - (6 * pi<RealType>() * pi<RealType>() - 24 * pi<RealType>() + 16) /
// (four_minus_pi<RealType>() * four_minus_pi<RealType>());
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const rayleigh_distribution<RealType, Policy>& /*dist*/)
{
//using namespace boost::math::constants;
// Computed using NTL at 150 bit, about 50 decimal digits.
return static_cast<RealType>(0.2450893006876380628486604106197544154170667057995L);
// return -(6 * pi<RealType>() * pi<RealType>() - 24 * pi<RealType>() + 16) /
// (four_minus_pi<RealType>() * four_minus_pi<RealType>());
} // kurtosis
} // namespace math
} // namespace boost
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_rayleigh_HPP

View File

@@ -0,0 +1,374 @@
// Copyright John Maddock 2006.
// Copyright Paul A. Bristow 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_STATS_STUDENTS_T_HPP
#define BOOST_STATS_STUDENTS_T_HPP
// http://en.wikipedia.org/wiki/Student%27s_t_distribution
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3664.htm
#include <boost/math/distributions/fwd.hpp>
#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 <utility>
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4702) // unreachable code (return after domain_error throw).
#endif
namespace boost{ namespace math{
template <class RealType = double, class Policy = policies::policy<> >
class students_t_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
students_t_distribution(RealType i) : m_df(i)
{ // Constructor.
RealType result;
detail::check_df(
"boost::math::students_t_distribution<%1%>::students_t_distribution", m_df, &result, Policy());
} // students_t_distribution
RealType degrees_of_freedom()const
{
return m_df;
}
// Parameter estimation:
static RealType find_degrees_of_freedom(
RealType difference_from_mean,
RealType alpha,
RealType beta,
RealType sd,
RealType hint = 100);
private:
//
// Data members:
//
RealType m_df; // degrees of freedom are a real number.
};
typedef students_t_distribution<double> students_t;
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.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const students_t_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
}
template <class RealType, class Policy>
inline RealType pdf(const students_t_distribution<RealType, Policy>& dist, const RealType& t)
{
BOOST_FPU_EXCEPTION_GUARD
BOOST_MATH_STD_USING // for ADL of std functions
RealType degrees_of_freedom = dist.degrees_of_freedom();
// Error check:
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;
// 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);
}
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());
return result;
} // pdf
template <class RealType, class Policy>
inline RealType cdf(const students_t_distribution<RealType, Policy>& dist, const RealType& t)
{
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 (t == 0)
{
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;
}
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>
inline RealType quantile(const students_t_distribution<RealType, Policy>& dist, const RealType& p)
{
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:
//
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())
&& 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;
//
// This next block is disabled in favour of a faster method than
// incomplete beta inverse, code retained for future reference:
//
#if 0
//
// Calculate quantile of Student's t using the incomplete beta function inverse:
//
probability = (probability > 0.5) ? 1 - probability : probability;
RealType t, x, y;
x = ibeta_inv(degrees_of_freedom / 2, RealType(0.5), 2 * probability, &y);
if(degrees_of_freedom * y > tools::max_value<RealType>() * x)
t = tools::overflow_error<RealType>(function);
else
t = sqrt(degrees_of_freedom * y / x);
//
// Figure out sign based on the size of p:
//
if(p < 0.5)
t = -t;
return t;
#endif
//
// Depending on how many digits RealType has, this may forward
// to the incomplete beta inverse as above. Otherwise uses a
// faster method that is accurate to ~15 digits everywhere
// 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());
} // quantile
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<students_t_distribution<RealType, Policy>, RealType>& c)
{
return cdf(c.dist, -c.param);
}
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<students_t_distribution<RealType, Policy>, RealType>& c)
{
return -quantile(c.dist, c.param);
}
//
// Parameter estimation follows:
//
namespace detail{
//
// Functors for finding degrees of freedom:
//
template <class RealType, class Policy>
struct sample_size_func
{
sample_size_func(RealType a, RealType b, RealType s, RealType d)
: alpha(a), beta(b), ratio(s*s/(d*d)) {}
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));
qa += qb;
qa *= qa;
qa *= ratio;
qa -= (df + 1);
return qa;
}
RealType alpha, beta, ratio;
};
} // namespace detail
template <class RealType, class Policy>
RealType students_t_distribution<RealType, Policy>::find_degrees_of_freedom(
RealType difference_from_mean,
RealType alpha,
RealType beta,
RealType sd,
RealType hint)
{
static const char* function = "boost::math::students_t_distribution<%1%>::find_degrees_of_freedom";
//
// Check for domain errors:
//
RealType error_result;
if(false == detail::check_probability(
function, alpha, &error_result, Policy())
&& detail::check_probability(function, beta, &error_result, Policy()))
return error_result;
if(hint <= 0)
hint = 1;
detail::sample_size_func<RealType, Policy> f(alpha, beta, sd, difference_from_mean);
tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
std::pair<RealType, RealType> r = tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy());
RealType result = r.first + (r.second - r.first) / 2;
if(max_iter >= policies::get_max_root_iterations<Policy>())
{
policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
" either there is no answer to how many degrees of freedom are required"
" or the answer is infinite. Current best guess is %1%", result, Policy());
}
return result;
}
template <class RealType, class Policy>
inline RealType mean(const students_t_distribution<RealType, Policy>& )
{
return 0;
}
template <class RealType, class Policy>
inline RealType variance(const students_t_distribution<RealType, Policy>& dist)
{
// Error check:
RealType error_result;
if(false == detail::check_df(
"boost::math::variance(students_t_distribution<%1%> const&, %1%)", dist.degrees_of_freedom(), &error_result, Policy()))
return error_result;
RealType v = dist.degrees_of_freedom();
return v / (v - 2);
}
template <class RealType, class Policy>
inline RealType mode(const students_t_distribution<RealType, Policy>& /*dist*/)
{
return 0;
}
template <class RealType, class Policy>
inline RealType median(const students_t_distribution<RealType, Policy>& /*dist*/)
{
return 0;
}
template <class RealType, class Policy>
inline RealType skewness(const students_t_distribution<RealType, Policy>& dist)
{
if(dist.degrees_of_freedom() <= 3)
{
policies::raise_domain_error<RealType>(
"boost::math::skewness(students_t_distribution<%1%> const&, %1%)",
"Skewness is undefined for degrees of freedom <= 3, but got %1%.",
dist.degrees_of_freedom(), Policy());
}
return 0;
}
template <class RealType, class Policy>
inline RealType kurtosis(const students_t_distribution<RealType, Policy>& dist)
{
RealType df = dist.degrees_of_freedom();
if(df <= 3)
{
policies::raise_domain_error<RealType>(
"boost::math::kurtosis(students_t_distribution<%1%> const&, %1%)",
"Skewness is undefined for degrees of freedom <= 3, but got %1%.",
df, Policy());
}
return 3 * (df - 2) / (df - 4);
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const students_t_distribution<RealType, Policy>& dist)
{
// see http://mathworld.wolfram.com/Kurtosis.html
RealType df = dist.degrees_of_freedom();
if(df <= 3)
{
policies::raise_domain_error<RealType>(
"boost::math::kurtosis_excess(students_t_distribution<%1%> const&, %1%)",
"Skewness is undefined for degrees of freedom <= 3, but got %1%.",
df, Policy());
}
return 6 / (df - 4);
}
} // namespace math
} // namespace boost
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_STUDENTS_T_HPP

View File

@@ -0,0 +1,523 @@
// 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)
#ifndef BOOST_STATS_TRIANGULAR_HPP
#define BOOST_STATS_TRIANGULAR_HPP
// http://mathworld.wolfram.com/TriangularDistribution.html
// http://en.wikipedia.org/wiki/Triangular_distribution
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/distributions/complement.hpp>
#include <boost/math/constants/constants.hpp>
#include <utility>
namespace boost{ namespace math
{
namespace detail
{
template <class RealType, class Policy>
inline bool check_triangular_lower(
const char* function,
RealType lower,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(lower))
{ // Any finite value is OK.
return true;
}
else
{ // Not finite: infinity or NaN.
*result = policies::raise_domain_error<RealType>(
function,
"Lower parameter is %1%, but must be finite!", lower, pol);
return false;
}
} // bool check_triangular_lower(
template <class RealType, class Policy>
inline bool check_triangular_mode(
const char* function,
RealType mode,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(mode))
{ // any finite value is OK.
return true;
}
else
{ // Not finite: infinity or NaN.
*result = policies::raise_domain_error<RealType>(
function,
"Mode parameter is %1%, but must be finite!", mode, pol);
return false;
}
} // bool check_triangular_mode(
template <class RealType, class Policy>
inline bool check_triangular_upper(
const char* function,
RealType upper,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(upper))
{ // any finite value is OK.
return true;
}
else
{ // Not finite: infinity or NaN.
*result = policies::raise_domain_error<RealType>(
function,
"Upper parameter is %1%, but must be finite!", upper, pol);
return false;
}
} // bool check_triangular_upper(
template <class RealType, class Policy>
inline bool check_triangular_x(
const char* function,
RealType const& x,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(x))
{ // Any finite value is OK
return true;
}
else
{ // Not finite: infinity or NaN.
*result = policies::raise_domain_error<RealType>(
function,
"x parameter is %1%, but must be finite!", x, pol);
return false;
}
} // bool check_triangular_x
template <class RealType, class Policy>
inline bool check_triangular(
const char* function,
RealType lower,
RealType mode,
RealType upper,
RealType* result, const Policy& pol)
{
if ((check_triangular_lower(function, lower, result, pol) == false)
|| (check_triangular_mode(function, mode, result, pol) == false)
|| (check_triangular_upper(function, upper, result, pol) == false))
{ // Some parameter not finite.
return false;
}
else if (lower >= upper) // lower == upper NOT useful.
{ // lower >= upper.
*result = policies::raise_domain_error<RealType>(
function,
"lower parameter is %1%, but must be less than upper!", lower, pol);
return false;
}
else
{ // Check lower <= mode <= upper.
if (mode < lower)
{
*result = policies::raise_domain_error<RealType>(
function,
"mode parameter is %1%, but must be >= than lower!", lower, pol);
return false;
}
if (mode > upper)
{
*result = policies::raise_domain_error<RealType>(
function,
"mode parameter is %1%, but must be <= than upper!", upper, pol);
return false;
}
return true; // All OK.
}
} // bool check_triangular
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class triangular_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
triangular_distribution(RealType lower = -1, RealType mode = 0, RealType upper = 1)
: m_lower(lower), m_mode(mode), m_upper(upper) // Constructor.
{ // Evans says 'standard triangular' is lower 0, mode 1/2, upper 1,
// has median sqrt(c/2) for c <=1/2 and 1 - sqrt(1-c)/2 for c >= 1/2
// But this -1, 0, 1 is more useful in most applications to approximate normal distribution,
// where the central value is the most likely and deviations either side equally likely.
RealType result;
detail::check_triangular("boost::math::triangular_distribution<%1%>::triangular_distribution",lower, mode, upper, &result, Policy());
}
// Accessor functions.
RealType lower()const
{
return m_lower;
}
RealType mode()const
{
return m_mode;
}
RealType upper()const
{
return m_upper;
}
private:
// Data members:
RealType m_lower; // distribution lower aka a
RealType m_mode; // distribution mode aka c
RealType m_upper; // distribution upper aka b
}; // class triangular_distribution
typedef triangular_distribution<double> triangular;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const triangular_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const triangular_distribution<RealType, Policy>& dist)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
return std::pair<RealType, RealType>(dist.lower(), dist.upper());
}
template <class RealType, class Policy>
RealType pdf(const triangular_distribution<RealType, Policy>& dist, const RealType& x)
{
static const char* function = "boost::math::pdf(const triangular_distribution<%1%>&, %1%)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_triangular_x(function, x, &result, Policy()))
{
return result;
}
if((x < lower) || (x > upper))
{
return 0;
}
if (x == lower)
{ // (mode - lower) == 0 which would lead to divide by zero!
return (mode == lower) ? 2 / (upper - lower) : 0;
}
else if (x == upper)
{
return (mode == upper) ? 2 / (upper - lower) : 0;
}
else if (x <= mode)
{
return 2 * (x - lower) / ((upper - lower) * (mode - lower));
}
else
{ // (x > mode)
return 2 * (upper - x) / ((upper - lower) * (upper - mode));
}
} // RealType pdf(const triangular_distribution<RealType, Policy>& dist, const RealType& x)
template <class RealType, class Policy>
inline RealType cdf(const triangular_distribution<RealType, Policy>& dist, const RealType& x)
{
static const char* function = "boost::math::cdf(const triangular_distribution<%1%>&, %1%)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_triangular_x(function, x, &result, Policy()))
{
return result;
}
if((x <= lower))
{
return 0;
}
if (x >= upper)
{
return 1;
}
// else lower < x < upper
if (x <= mode)
{
return ((x - lower) * (x - lower)) / ((upper - lower) * (mode - lower));
}
else
{
return 1 - (upper - x) * (upper - x) / ((upper - lower) * (upper - mode));
}
} // RealType cdf(const triangular_distribution<RealType, Policy>& dist, const RealType& x)
template <class RealType, class Policy>
RealType quantile(const triangular_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions (sqrt).
static const char* function = "boost::math::quantile(const triangular_distribution<%1%>&, %1%)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result; // of checks
if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_probability(function, p, &result, Policy()))
{
return result;
}
if(p == 0)
{
return lower;
}
if(p == 1)
{
return upper;
}
RealType p0 = (mode - lower) / (upper - lower);
RealType q = 1 - p;
if (p < p0)
{
result = sqrt((upper - lower) * (mode - lower) * p) + lower;
}
else if (p == p0)
{
result = mode;
}
else // p > p0
{
result = upper - sqrt((upper - lower) * (upper - mode) * q);
}
return result;
} // RealType quantile(const triangular_distribution<RealType, Policy>& dist, const RealType& q)
template <class RealType, class Policy>
RealType cdf(const complemented2_type<triangular_distribution<RealType, Policy>, RealType>& c)
{
static const char* function = "boost::math::cdf(const triangular_distribution<%1%>&, %1%)";
RealType lower = c.dist.lower();
RealType mode = c.dist.mode();
RealType upper = c.dist.upper();
RealType x = c.param;
RealType result; // of checks.
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_triangular_x(function, x, &result, Policy()))
{
return result;
}
if (x <= lower)
{
return 1;
}
if (x >= upper)
{
return 0;
}
if (x <= mode)
{
return 1 - ((x - lower) * (x - lower)) / ((upper - lower) * (mode - lower));
}
else
{
return (upper - x) * (upper - x) / ((upper - lower) * (upper - mode));
}
} // RealType cdf(const complemented2_type<triangular_distribution<RealType, Policy>, RealType>& c)
template <class RealType, class Policy>
RealType quantile(const complemented2_type<triangular_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // Aid ADL for sqrt.
static const char* function = "boost::math::quantile(const triangular_distribution<%1%>&, %1%)";
RealType l = c.dist.lower();
RealType m = c.dist.mode();
RealType u = c.dist.upper();
RealType q = c.param; // probability 0 to 1.
RealType result; // of checks.
if(false == detail::check_triangular(function, l, m, u, &result, Policy()))
{
return result;
}
if(false == detail::check_probability(function, q, &result, Policy()))
{
return result;
}
if(q == 0)
{
return u;
}
if(q == 1)
{
return l;
}
RealType lower = c.dist.lower();
RealType mode = c.dist.mode();
RealType upper = c.dist.upper();
RealType p = 1 - q;
RealType p0 = (mode - lower) / (upper - lower);
if(p < p0)
{
RealType s = (upper - lower) * (mode - lower);
s *= p;
result = sqrt((upper - lower) * (mode - lower) * p) + lower;
}
else if (p == p0)
{
result = mode;
}
else // p > p0
{
result = upper - sqrt((upper - lower) * (upper - mode) * q);
}
return result;
} // RealType quantile(const complemented2_type<triangular_distribution<RealType, Policy>, RealType>& c)
template <class RealType, class Policy>
inline RealType mean(const triangular_distribution<RealType, Policy>& dist)
{
static const char* function = "boost::math::mean(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
return (lower + upper + mode) / 3;
} // RealType mean(const triangular_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType variance(const triangular_distribution<RealType, Policy>& dist)
{
static const char* function = "boost::math::mean(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_triangular(function, lower, mode, upper, &result, Policy()))
{
return result;
}
return (lower * lower + upper * upper + mode * mode - lower * upper - lower * mode - upper * mode) / 18;
} // RealType variance(const triangular_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType mode(const triangular_distribution<RealType, Policy>& dist)
{
static const char* function = "boost::math::mode(const triangular_distribution<%1%>&)";
RealType mode = dist.mode();
RealType result; // of checks.
if(false == detail::check_triangular_mode(function, mode, &result, Policy()))
{ // This should never happen!
return result;
}
return mode;
} // RealType mode
template <class RealType, class Policy>
inline RealType median(const triangular_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // ADL of std functions.
static const char* function = "boost::math::median(const triangular_distribution<%1%>&)";
RealType mode = dist.mode();
RealType result; // of checks.
if(false == detail::check_triangular_mode(function, mode, &result, Policy()))
{ // This should never happen!
return result;
}
RealType lower = dist.lower();
RealType upper = dist.upper();
if (mode < (upper - lower) / 2)
{
return lower + sqrt((upper - lower) * (mode - lower)) / constants::root_two<RealType>();
}
else
{
return upper - sqrt((upper - lower) * (upper - mode)) / constants::root_two<RealType>();
}
} // RealType mode
template <class RealType, class Policy>
inline RealType skewness(const triangular_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
using namespace boost::math::constants; // for root_two
static const char* function = "boost::math::skewness(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType mode = dist.mode();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
return root_two<RealType>() * (lower + upper - 2 * mode) * (2 * lower - upper - mode) * (lower - 2 * upper + mode) /
(5 * pow((lower * lower + upper + upper + mode * mode - lower * upper - lower * mode - upper * mode), RealType(3)/RealType(2)));
} // RealType skewness(const triangular_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType kurtosis(const triangular_distribution<RealType, Policy>& dist)
{ // These checks may be belt and braces as should have been checked on construction?
static const char* function = "boost::math::kurtosis(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType mode = dist.mode();
RealType result; // of checks.
if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
return static_cast<RealType>(12)/5; // 12/5 = 2.4;
} // RealType kurtosis_excess(const triangular_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType kurtosis_excess(const triangular_distribution<RealType, Policy>& dist)
{ // These checks may be belt and braces as should have been checked on construction?
static const char* function = "boost::math::kurtosis_excess(const triangular_distribution<%1%>&)";
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType mode = dist.mode();
RealType result; // of checks.
if(false == detail::check_triangular(function,lower, mode, upper, &result, Policy()))
{
return result;
}
return static_cast<RealType>(-3)/5; // - 3/5 = -0.6
// Assuming mathworld really means kurtosis excess? Wikipedia now corrected to match this.
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_TRIANGULAR_HPP

View File

@@ -0,0 +1,379 @@
// Copyright John Maddock 2006.
// Copyright Paul A. Bristow 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)
// TODO deal with infinity as special better - or remove.
//
#ifndef BOOST_STATS_UNIFORM_HPP
#define BOOST_STATS_UNIFORM_HPP
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3668.htm
// http://mathworld.wolfram.com/UniformDistribution.html
// http://documents.wolfram.com/calculationcenter/v2/Functions/ListsMatrices/Statistics/UniformDistribution.html
// http://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/distributions/complement.hpp>
#include <utility>
namespace boost{ namespace math
{
namespace detail
{
template <class RealType, class Policy>
inline bool check_uniform_lower(
const char* function,
RealType lower,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(lower))
{ // any finite value is OK.
return true;
}
else
{ // Not finite.
*result = policies::raise_domain_error<RealType>(
function,
"Lower parameter is %1%, but must be finite!", lower, pol);
return false;
}
} // bool check_uniform_lower(
template <class RealType, class Policy>
inline bool check_uniform_upper(
const char* function,
RealType upper,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(upper))
{ // Any finite value is OK.
return true;
}
else
{ // Not finite.
*result = policies::raise_domain_error<RealType>(
function,
"Upper parameter is %1%, but must be finite!", upper, pol);
return false;
}
} // bool check_uniform_upper(
template <class RealType, class Policy>
inline bool check_uniform_x(
const char* function,
RealType const& x,
RealType* result, const Policy& pol)
{
if((boost::math::isfinite)(x))
{ // Any finite value is OK
return true;
}
else
{ // Not finite..
*result = policies::raise_domain_error<RealType>(
function,
"x parameter is %1%, but must be finite!", x, pol);
return false;
}
} // bool check_uniform_x
template <class RealType, class Policy>
inline bool check_uniform(
const char* function,
RealType lower,
RealType upper,
RealType* result, const Policy& pol)
{
if((check_uniform_lower(function, lower, result, pol) == false)
|| (check_uniform_upper(function, upper, result, pol) == false))
{
return false;
}
else if (lower >= upper) // If lower == upper then 1 / (upper-lower) = 1/0 = +infinity!
{ // upper and lower have been checked before, so must be lower >= upper.
*result = policies::raise_domain_error<RealType>(
function,
"lower parameter is %1%, but must be less than upper!", lower, pol);
return false;
}
else
{ // All OK,
return true;
}
} // bool check_uniform(
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class uniform_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
uniform_distribution(RealType lower = 0, RealType upper = 1) // Constructor.
: m_lower(lower), m_upper(upper) // Default is standard uniform distribution.
{
RealType result;
detail::check_uniform("boost::math::uniform_distribution<%1%>::uniform_distribution", lower, upper, &result, Policy());
}
// Accessor functions.
RealType lower()const
{
return m_lower;
}
RealType upper()const
{
return m_upper;
}
private:
// Data members:
RealType m_lower; // distribution lower aka a.
RealType m_upper; // distribution upper aka b.
}; // class uniform_distribution
typedef uniform_distribution<double> uniform;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const uniform_distribution<RealType, Policy>& /* dist */)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>()); // - to + 'infinity'.
// Note RealType infinity is NOT permitted, only max_value.
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const uniform_distribution<RealType, Policy>& dist)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(dist.lower(), dist.upper());
}
template <class RealType, class Policy>
inline RealType pdf(const uniform_distribution<RealType, Policy>& dist, const RealType& x)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::pdf(const uniform_distribution<%1%>&, %1%)", lower, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_uniform_x("boost::math::pdf(const uniform_distribution<%1%>&, %1%)", x, &result, Policy()))
{
return result;
}
if((x < lower) || (x > upper) )
{
return 0;
}
else
{
return 1 / (upper - lower);
}
} // RealType pdf(const uniform_distribution<RealType, Policy>& dist, const RealType& x)
template <class RealType, class Policy>
inline RealType cdf(const uniform_distribution<RealType, Policy>& dist, const RealType& x)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::cdf(const uniform_distribution<%1%>&, %1%)",lower, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_uniform_x("boost::math::cdf(const uniform_distribution<%1%>&, %1%)", x, &result, Policy()))
{
return result;
}
if (x < lower)
{
return 0;
}
if (x > upper)
{
return 1;
}
return (x - lower) / (upper - lower); // lower <= x <= upper
} // RealType cdf(const uniform_distribution<RealType, Policy>& dist, const RealType& x)
template <class RealType, class Policy>
inline RealType quantile(const uniform_distribution<RealType, Policy>& dist, const RealType& p)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks
if(false == detail::check_uniform("boost::math::quantile(const uniform_distribution<%1%>&, %1%)",lower, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_probability("boost::math::quantile(const uniform_distribution<%1%>&, %1%)", p, &result, Policy()))
{
return result;
}
if(p == 0)
{
return lower;
}
if(p == 1)
{
return upper;
}
return p * (upper - lower) + lower;
} // RealType quantile(const uniform_distribution<RealType, Policy>& dist, const RealType& p)
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<uniform_distribution<RealType, Policy>, RealType>& c)
{
RealType lower = c.dist.lower();
RealType upper = c.dist.upper();
RealType x = c.param;
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::cdf(const uniform_distribution<%1%>&, %1%)", lower, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_uniform_x("boost::math::cdf(const uniform_distribution<%1%>&, %1%)", x, &result, Policy()))
{
return result;
}
if (x < lower)
{
return 0;
}
if (x > upper)
{
return 1;
}
return (upper - x) / (upper - lower);
} // RealType cdf(const complemented2_type<uniform_distribution<RealType, Policy>, RealType>& c)
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<uniform_distribution<RealType, Policy>, RealType>& c)
{
RealType lower = c.dist.lower();
RealType upper = c.dist.upper();
RealType q = c.param;
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::quantile(const uniform_distribution<%1%>&, %1%)", lower, upper, &result, Policy()))
{
return result;
}
if(false == detail::check_probability("boost::math::quantile(const uniform_distribution<%1%>&, %1%)", q, &result, Policy()))
if(q == 0)
{
return lower;
}
if(q == 1)
{
return upper;
}
return -q * (upper - lower) + upper;
} // RealType quantile(const complemented2_type<uniform_distribution<RealType, Policy>, RealType>& c)
template <class RealType, class Policy>
inline RealType mean(const uniform_distribution<RealType, Policy>& dist)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::mean(const uniform_distribution<%1%>&)", lower, upper, &result, Policy()))
{
return result;
}
return (lower + upper ) / 2;
} // RealType mean(const uniform_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType variance(const uniform_distribution<RealType, Policy>& dist)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::variance(const uniform_distribution<%1%>&)", lower, upper, &result, Policy()))
{
return result;
}
return (upper - lower) * ( upper - lower) / 12;
// for standard uniform = 0.833333333333333333333333333333333333333333;
} // RealType variance(const uniform_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType mode(const uniform_distribution<RealType, Policy>& dist)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::mode(const uniform_distribution<%1%>&)", lower, upper, &result, Policy()))
{
return result;
}
result = lower; // Any value [lower, upper] but arbitrarily choose lower.
return result;
}
template <class RealType, class Policy>
inline RealType median(const uniform_distribution<RealType, Policy>& dist)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::median(const uniform_distribution<%1%>&)", lower, upper, &result, Policy()))
{
return result;
}
return (lower + upper) / 2; //
}
template <class RealType, class Policy>
inline RealType skewness(const uniform_distribution<RealType, Policy>& dist)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::skewness(const uniform_distribution<%1%>&)",lower, upper, &result, Policy()))
{
return result;
}
return 0;
} // RealType skewness(const uniform_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType kurtosis_excess(const uniform_distribution<RealType, Policy>& dist)
{
RealType lower = dist.lower();
RealType upper = dist.upper();
RealType result; // of checks.
if(false == detail::check_uniform("boost::math::kurtosis_execess(const uniform_distribution<%1%>&)", lower, upper, &result, Policy()))
{
return result;
}
return static_cast<RealType>(-6)/5; // -6/5 = -1.2;
} // RealType kurtosis_excess(const uniform_distribution<RealType, Policy>& dist)
template <class RealType, class Policy>
inline RealType kurtosis(const uniform_distribution<RealType, Policy>& dist)
{
return kurtosis_excess(dist) + 3;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_UNIFORM_HPP

View File

@@ -0,0 +1,387 @@
// 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_STATS_WEIBULL_HPP
#define BOOST_STATS_WEIBULL_HPP
// http://www.itl.nist.gov/div898/handbook/eda/section3/eda3668.htm
// http://mathworld.wolfram.com/WeibullDistribution.html
#include <boost/math/distributions/fwd.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/distributions/detail/common_error_handling.hpp>
#include <boost/math/distributions/complement.hpp>
#include <utility>
namespace boost{ namespace math
{
namespace detail{
template <class RealType, class Policy>
inline bool check_weibull_shape(
const char* function,
RealType shape,
RealType* result, const Policy& pol)
{
if((shape < 0) || !(boost::math::isfinite)(shape))
{
*result = policies::raise_domain_error<RealType>(
function,
"Shape parameter is %1%, but must be > 0 !", shape, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_weibull_x(
const char* function,
RealType const& x,
RealType* result, const Policy& pol)
{
if((x < 0) || !(boost::math::isfinite)(x))
{
*result = policies::raise_domain_error<RealType>(
function,
"Random variate is %1% but must be >= 0 !", x, pol);
return false;
}
return true;
}
template <class RealType, class Policy>
inline bool check_weibull(
const char* function,
RealType scale,
RealType shape,
RealType* result, const Policy& pol)
{
return check_scale(function, scale, result, pol) && check_weibull_shape(function, shape, result, pol);
}
} // namespace detail
template <class RealType = double, class Policy = policies::policy<> >
class weibull_distribution
{
public:
typedef RealType value_type;
typedef Policy policy_type;
weibull_distribution(RealType shape, RealType scale = 1)
: m_shape(shape), m_scale(scale)
{
RealType result;
detail::check_weibull("boost::math::weibull_distribution<%1%>::weibull_distribution", scale, shape, &result, Policy());
}
RealType shape()const
{
return m_shape;
}
RealType scale()const
{
return m_scale;
}
private:
//
// Data members:
//
RealType m_shape; // distribution shape
RealType m_scale; // distribution scale
};
typedef weibull_distribution<double> weibull;
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> range(const weibull_distribution<RealType, Policy>& /*dist*/)
{ // Range of permissible values for random variable x.
using boost::math::tools::max_value;
return std::pair<RealType, RealType>(0, max_value<RealType>());
}
template <class RealType, class Policy>
inline const std::pair<RealType, RealType> support(const weibull_distribution<RealType, Policy>& /*dist*/)
{ // Range of supported values for random variable x.
// This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
using boost::math::tools::max_value;
using boost::math::tools::min_value;
return std::pair<RealType, RealType>(min_value<RealType>(), max_value<RealType>());
// A discontinuity at x == 0, so only support down to min_value.
}
template <class RealType, class Policy>
inline RealType pdf(const weibull_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::pdf(const weibull_distribution<%1%>, %1%)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_weibull_x(function, x, &result, Policy()))
return result;
if(x == 0)
{ // Special case, but x == min, pdf = 1 for shape = 1,
return 0;
}
result = exp(-pow(x / scale, shape));
result *= pow(x / scale, shape) * shape / x;
return result;
}
template <class RealType, class Policy>
inline RealType cdf(const weibull_distribution<RealType, Policy>& dist, const RealType& x)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(const weibull_distribution<%1%>, %1%)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_weibull_x(function, x, &result, Policy()))
return result;
result = -boost::math::expm1(-pow(x / scale, shape), Policy());
return result;
}
template <class RealType, class Policy>
inline RealType quantile(const weibull_distribution<RealType, Policy>& dist, const RealType& p)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const weibull_distribution<%1%>, %1%)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_probability(function, p, &result, Policy()))
return result;
if(p == 1)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
result = scale * pow(-boost::math::log1p(-p, Policy()), 1 / shape);
return result;
}
template <class RealType, class Policy>
inline RealType cdf(const complemented2_type<weibull_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::cdf(const weibull_distribution<%1%>, %1%)";
RealType shape = c.dist.shape();
RealType scale = c.dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_weibull_x(function, c.param, &result, Policy()))
return result;
result = exp(-pow(c.param / scale, shape));
return result;
}
template <class RealType, class Policy>
inline RealType quantile(const complemented2_type<weibull_distribution<RealType, Policy>, RealType>& c)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::quantile(const weibull_distribution<%1%>, %1%)";
RealType shape = c.dist.shape();
RealType scale = c.dist.scale();
RealType q = c.param;
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
return result;
if(false == detail::check_probability(function, q, &result, Policy()))
return result;
if(q == 0)
return policies::raise_overflow_error<RealType>(function, 0, Policy());
result = scale * pow(-log(q), 1 / shape);
return result;
}
template <class RealType, class Policy>
inline RealType mean(const weibull_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::mean(const weibull_distribution<%1%>)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
return result;
result = scale * boost::math::tgamma(1 + 1 / shape, Policy());
return result;
}
template <class RealType, class Policy>
inline RealType variance(const weibull_distribution<RealType, Policy>& dist)
{
RealType shape = dist.shape();
RealType scale = dist.scale();
static const char* function = "boost::math::variance(const weibull_distribution<%1%>)";
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
{
return result;
}
result = boost::math::tgamma(1 + 1 / shape, Policy());
result *= -result;
result += boost::math::tgamma(1 + 2 / shape, Policy());
result *= scale * scale;
return result;
}
template <class RealType, class Policy>
inline RealType mode(const weibull_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std function pow.
static const char* function = "boost::math::mode(const weibull_distribution<%1%>)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
{
return result;
}
if(shape <= 1)
return 0;
result = scale * pow((shape - 1) / shape, 1 / shape);
return result;
}
template <class RealType, class Policy>
inline RealType median(const weibull_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std function pow.
static const char* function = "boost::math::median(const weibull_distribution<%1%>)";
RealType shape = dist.shape(); // Wikipedia k
RealType scale = dist.scale(); // Wikipedia lambda
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
{
return result;
}
using boost::math::constants::ln_two;
result = scale * pow(ln_two<RealType>(), 1 / shape);
return result;
}
template <class RealType, class Policy>
inline RealType skewness(const weibull_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::skewness(const weibull_distribution<%1%>)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
{
return result;
}
RealType g1, g2, g3, d;
g1 = boost::math::tgamma(1 + 1 / shape, Policy());
g2 = boost::math::tgamma(1 + 2 / shape, Policy());
g3 = boost::math::tgamma(1 + 3 / shape, Policy());
d = pow(g2 - g1 * g1, RealType(1.5));
result = (2 * g1 * g1 * g1 - 3 * g1 * g2 + g3) / d;
return result;
}
template <class RealType, class Policy>
inline RealType kurtosis_excess(const weibull_distribution<RealType, Policy>& dist)
{
BOOST_MATH_STD_USING // for ADL of std functions
static const char* function = "boost::math::kurtosis_excess(const weibull_distribution<%1%>)";
RealType shape = dist.shape();
RealType scale = dist.scale();
RealType result;
if(false == detail::check_weibull(function, scale, shape, &result, Policy()))
return result;
RealType g1, g2, g3, g4, d, g1_2, g1_4;
g1 = boost::math::tgamma(1 + 1 / shape, Policy());
g2 = boost::math::tgamma(1 + 2 / shape, Policy());
g3 = boost::math::tgamma(1 + 3 / shape, Policy());
g4 = boost::math::tgamma(1 + 4 / shape, Policy());
g1_2 = g1 * g1;
g1_4 = g1_2 * g1_2;
d = g2 - g1_2;
d *= d;
result = -6 * g1_4 + 12 * g1_2 * g2 - 3 * g2 * g2 - 4 * g1 * g3 + g4;
result /= d;
return result;
}
template <class RealType, class Policy>
inline RealType kurtosis(const weibull_distribution<RealType, Policy>& dist)
{
return kurtosis_excess(dist) + 3;
}
} // namespace math
} // namespace boost
// This include must be at the end, *after* the accessors
// for this distribution have been defined, in order to
// keep compilers that support two-phase lookup happy.
#include <boost/math/distributions/detail/derived_accessors.hpp>
#endif // BOOST_STATS_WEIBULL_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,644 @@
// 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_POLICY_ERROR_HANDLING_HPP
#define BOOST_MATH_POLICY_ERROR_HANDLING_HPP
#include <stdexcept>
#include <iomanip>
#include <string>
#include <cerrno>
#include <boost/config/no_tr1/cmath.hpp>
#include <stdexcept>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/policy.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/cstdint.hpp>
#ifdef BOOST_MSVC
# pragma warning(push) // Quiet warnings in boost/format.hpp
# pragma warning(disable: 4996) // _SCL_SECURE_NO_DEPRECATE
# pragma warning(disable: 4512) // assignment operator could not be generated.
// And warnings in error handling:
# pragma warning(disable: 4702) // unreachable code
// Note that this only occurs when the compiler can deduce code is unreachable,
// for example when policy macros are used to ignore errors rather than throw.
#endif
#include <boost/format.hpp>
namespace boost{ namespace math{
class evaluation_error : public std::runtime_error
{
public:
evaluation_error(const std::string& s) : std::runtime_error(s){}
};
class rounding_error : public std::runtime_error
{
public:
rounding_error(const std::string& s) : std::runtime_error(s){}
};
namespace policies{
//
// Forward declarations of user error handlers,
// it's up to the user to provide the definition of these:
//
template <class T>
T user_domain_error(const char* function, const char* message, const T& val);
template <class T>
T user_pole_error(const char* function, const char* message, const T& val);
template <class T>
T user_overflow_error(const char* function, const char* message, const T& val);
template <class T>
T user_underflow_error(const char* function, const char* message, const T& val);
template <class T>
T user_denorm_error(const char* function, const char* message, const T& val);
template <class T>
T user_evaluation_error(const char* function, const char* message, const T& val);
template <class T>
T user_rounding_error(const char* function, const char* message, const T& val);
template <class T>
T user_indeterminate_result_error(const char* function, const char* message, const T& val);
namespace detail
{
//
// Helper function to avoid binding rvalue to non-const-reference,
// in other words a warning suppression mechansim:
//
template <class Formatter, class Group>
inline std::string do_format(Formatter f, const Group& g)
{
return (f % g).str();
}
template <class E, class T>
void raise_error(const char* function, const char* message)
{
if(function == 0)
function = "Unknown function operating on type %1%";
if(message == 0)
message = "Cause unknown";
std::string msg("Error in function ");
msg += (boost::format(function) % typeid(T).name()).str();
msg += ": ";
msg += message;
E e(msg);
boost::throw_exception(e);
}
template <class E, class T>
void raise_error(const char* function, const char* message, const T& val)
{
if(function == 0)
function = "Unknown function operating on type %1%";
if(message == 0)
message = "Cause unknown: error caused by bad argument with value %1%";
std::string msg("Error in function ");
msg += (boost::format(function) % typeid(T).name()).str();
msg += ": ";
msg += message;
int prec = 2 + (boost::math::policies::digits<T, boost::math::policies::policy<> >() * 30103UL) / 100000UL;
msg = do_format(boost::format(msg), boost::io::group(std::setprecision(prec), val));
E e(msg);
boost::throw_exception(e);
}
template <class T>
inline T raise_domain_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>&)
{
raise_error<std::domain_error, T>(function, message, val);
// we never get here:
return std::numeric_limits<T>::quiet_NaN();
}
template <class T>
inline T raise_domain_error(
const char* ,
const char* ,
const T& ,
const ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>&)
{
// This may or may not do the right thing, but the user asked for the error
// to be ignored so here we go anyway:
return std::numeric_limits<T>::quiet_NaN();
}
template <class T>
inline T raise_domain_error(
const char* ,
const char* ,
const T& ,
const ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>&)
{
errno = EDOM;
// This may or may not do the right thing, but the user asked for the error
// to be silent so here we go anyway:
return std::numeric_limits<T>::quiet_NaN();
}
template <class T>
inline T raise_domain_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::domain_error< ::boost::math::policies::user_error>&)
{
return user_domain_error(function, message, val);
}
template <class T>
inline T raise_pole_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::pole_error< ::boost::math::policies::throw_on_error>&)
{
return boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::throw_on_error>());
}
template <class T>
inline T raise_pole_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::pole_error< ::boost::math::policies::ignore_error>&)
{
return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::ignore_error>());
}
template <class T>
inline T raise_pole_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::pole_error< ::boost::math::policies::errno_on_error>&)
{
return ::boost::math::policies::detail::raise_domain_error(function, message, val, ::boost::math::policies::domain_error< ::boost::math::policies::errno_on_error>());
}
template <class T>
inline T raise_pole_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::pole_error< ::boost::math::policies::user_error>&)
{
return user_pole_error(function, message, val);
}
template <class T>
inline T raise_overflow_error(
const char* function,
const char* message,
const ::boost::math::policies::overflow_error< ::boost::math::policies::throw_on_error>&)
{
raise_error<std::overflow_error, T>(function, message ? message : "numeric overflow");
// we never get here:
return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
}
template <class T>
inline T raise_overflow_error(
const char* ,
const char* ,
const ::boost::math::policies::overflow_error< ::boost::math::policies::ignore_error>&)
{
// This may or may not do the right thing, but the user asked for the error
// to be ignored so here we go anyway:
return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
}
template <class T>
inline T raise_overflow_error(
const char* ,
const char* ,
const ::boost::math::policies::overflow_error< ::boost::math::policies::errno_on_error>&)
{
errno = ERANGE;
// This may or may not do the right thing, but the user asked for the error
// to be silent so here we go anyway:
return std::numeric_limits<T>::has_infinity ? std::numeric_limits<T>::infinity() : boost::math::tools::max_value<T>();
}
template <class T>
inline T raise_overflow_error(
const char* function,
const char* message,
const ::boost::math::policies::overflow_error< ::boost::math::policies::user_error>&)
{
return user_overflow_error(function, message, std::numeric_limits<T>::infinity());
}
template <class T>
inline T raise_underflow_error(
const char* function,
const char* message,
const ::boost::math::policies::underflow_error< ::boost::math::policies::throw_on_error>&)
{
raise_error<std::underflow_error, T>(function, message ? message : "numeric underflow");
// we never get here:
return 0;
}
template <class T>
inline T raise_underflow_error(
const char* ,
const char* ,
const ::boost::math::policies::underflow_error< ::boost::math::policies::ignore_error>&)
{
// This may or may not do the right thing, but the user asked for the error
// to be ignored so here we go anyway:
return T(0);
}
template <class T>
inline T raise_underflow_error(
const char* /* function */,
const char* /* message */,
const ::boost::math::policies::underflow_error< ::boost::math::policies::errno_on_error>&)
{
errno = ERANGE;
// This may or may not do the right thing, but the user asked for the error
// to be silent so here we go anyway:
return T(0);
}
template <class T>
inline T raise_underflow_error(
const char* function,
const char* message,
const ::boost::math::policies::underflow_error< ::boost::math::policies::user_error>&)
{
return user_underflow_error(function, message, T(0));
}
template <class T>
inline T raise_denorm_error(
const char* function,
const char* message,
const T& /* val */,
const ::boost::math::policies::denorm_error< ::boost::math::policies::throw_on_error>&)
{
raise_error<std::underflow_error, T>(function, message ? message : "denormalised result");
// we never get here:
return T(0);
}
template <class T>
inline T raise_denorm_error(
const char* ,
const char* ,
const T& val,
const ::boost::math::policies::denorm_error< ::boost::math::policies::ignore_error>&)
{
// This may or may not do the right thing, but the user asked for the error
// to be ignored so here we go anyway:
return val;
}
template <class T>
inline T raise_denorm_error(
const char* ,
const char* ,
const T& val,
const ::boost::math::policies::denorm_error< ::boost::math::policies::errno_on_error>&)
{
errno = ERANGE;
// This may or may not do the right thing, but the user asked for the error
// to be silent so here we go anyway:
return val;
}
template <class T>
inline T raise_denorm_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::denorm_error< ::boost::math::policies::user_error>&)
{
return user_denorm_error(function, message, val);
}
template <class T>
inline T raise_evaluation_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::evaluation_error< ::boost::math::policies::throw_on_error>&)
{
raise_error<boost::math::evaluation_error, T>(function, message, val);
// we never get here:
return T(0);
}
template <class T>
inline T raise_evaluation_error(
const char* ,
const char* ,
const T& val,
const ::boost::math::policies::evaluation_error< ::boost::math::policies::ignore_error>&)
{
// This may or may not do the right thing, but the user asked for the error
// to be ignored so here we go anyway:
return val;
}
template <class T>
inline T raise_evaluation_error(
const char* ,
const char* ,
const T& val,
const ::boost::math::policies::evaluation_error< ::boost::math::policies::errno_on_error>&)
{
errno = EDOM;
// This may or may not do the right thing, but the user asked for the error
// to be silent so here we go anyway:
return val;
}
template <class T>
inline T raise_evaluation_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::evaluation_error< ::boost::math::policies::user_error>&)
{
return user_evaluation_error(function, message, val);
}
template <class T>
inline T raise_rounding_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::rounding_error< ::boost::math::policies::throw_on_error>&)
{
raise_error<boost::math::rounding_error, T>(function, message, val);
// we never get here:
return T(0);
}
template <class T>
inline T raise_rounding_error(
const char* ,
const char* ,
const T& val,
const ::boost::math::policies::rounding_error< ::boost::math::policies::ignore_error>&)
{
// This may or may not do the right thing, but the user asked for the error
// to be ignored so here we go anyway:
return val;
}
template <class T>
inline T raise_rounding_error(
const char* ,
const char* ,
const T& val,
const ::boost::math::policies::rounding_error< ::boost::math::policies::errno_on_error>&)
{
errno = ERANGE;
// This may or may not do the right thing, but the user asked for the error
// to be silent so here we go anyway:
return val;
}
template <class T>
inline T raise_rounding_error(
const char* function,
const char* message,
const T& val,
const ::boost::math::policies::rounding_error< ::boost::math::policies::user_error>&)
{
return user_rounding_error(function, message, val);
}
template <class T, class R>
inline T raise_indeterminate_result_error(
const char* function,
const char* message,
const T& val,
const R& ,
const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::throw_on_error>&)
{
raise_error<std::domain_error, T>(function, message, val);
// we never get here:
return std::numeric_limits<T>::quiet_NaN();
}
template <class T, class R>
inline T raise_indeterminate_result_error(
const char* ,
const char* ,
const T& ,
const R& result,
const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::ignore_error>&)
{
// This may or may not do the right thing, but the user asked for the error
// to be ignored so here we go anyway:
return result;
}
template <class T, class R>
inline T raise_indeterminate_result_error(
const char* ,
const char* ,
const T& ,
const R& result,
const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::errno_on_error>&)
{
errno = EDOM;
// This may or may not do the right thing, but the user asked for the error
// to be silent so here we go anyway:
return result;
}
template <class T, class R>
inline T raise_indeterminate_result_error(
const char* function,
const char* message,
const T& val,
const R& ,
const ::boost::math::policies::indeterminate_result_error< ::boost::math::policies::user_error>&)
{
return user_indeterminate_result_error(function, message, val);
}
} // namespace detail
template <class T, class Policy>
inline T raise_domain_error(const char* function, const char* message, const T& val, const Policy&)
{
typedef typename Policy::domain_error_type policy_type;
return detail::raise_domain_error(
function, message ? message : "Domain Error evaluating function at %1%",
val, policy_type());
}
template <class T, class Policy>
inline T raise_pole_error(const char* function, const char* message, const T& val, const Policy&)
{
typedef typename Policy::pole_error_type policy_type;
return detail::raise_pole_error(
function, message ? message : "Evaluation of function at pole %1%",
val, policy_type());
}
template <class T, class Policy>
inline T raise_overflow_error(const char* function, const char* message, const Policy&)
{
typedef typename Policy::overflow_error_type policy_type;
return detail::raise_overflow_error<T>(
function, message ? message : "Overflow Error",
policy_type());
}
template <class T, class Policy>
inline T raise_underflow_error(const char* function, const char* message, const Policy&)
{
typedef typename Policy::underflow_error_type policy_type;
return detail::raise_underflow_error<T>(
function, message ? message : "Underflow Error",
policy_type());
}
template <class T, class Policy>
inline T raise_denorm_error(const char* function, const char* message, const T& val, const Policy&)
{
typedef typename Policy::denorm_error_type policy_type;
return detail::raise_denorm_error<T>(
function, message ? message : "Denorm Error",
val,
policy_type());
}
template <class T, class Policy>
inline T raise_evaluation_error(const char* function, const char* message, const T& val, const Policy&)
{
typedef typename Policy::evaluation_error_type policy_type;
return detail::raise_evaluation_error(
function, message ? message : "Internal Evaluation Error, best value so far was %1%",
val, policy_type());
}
template <class T, class Policy>
inline T raise_rounding_error(const char* function, const char* message, const T& val, const Policy&)
{
typedef typename Policy::rounding_error_type policy_type;
return detail::raise_rounding_error(
function, message ? message : "Value %1% can not be represented in the target integer type.",
val, policy_type());
}
template <class T, class R, class Policy>
inline T raise_indeterminate_result_error(const char* function, const char* message, const T& val, const R& result, const Policy&)
{
typedef typename Policy::indeterminate_result_error_type policy_type;
return detail::raise_indeterminate_result_error(
function, message ? message : "Indeterminate result with value %1%",
val, result, policy_type());
}
//
// checked_narrowing_cast:
//
namespace detail
{
template <class R, class T, class Policy>
inline bool check_overflow(T val, R* result, const char* function, const Policy& pol)
{
BOOST_MATH_STD_USING
if(fabs(val) > tools::max_value<R>())
{
*result = static_cast<R>(boost::math::policies::detail::raise_overflow_error<R>(function, 0, pol));
return true;
}
return false;
}
template <class R, class T, class Policy>
inline bool check_underflow(T val, R* result, const char* function, const Policy& pol)
{
if((val != 0) && (static_cast<R>(val) == 0))
{
*result = static_cast<R>(boost::math::policies::detail::raise_underflow_error<R>(function, 0, pol));
return true;
}
return false;
}
template <class R, class T, class Policy>
inline bool check_denorm(T val, R* result, const char* function, const Policy& pol)
{
BOOST_MATH_STD_USING
if((fabs(val) < static_cast<T>(tools::min_value<R>())) && (static_cast<R>(val) != 0))
{
*result = static_cast<R>(boost::math::policies::detail::raise_denorm_error<R>(function, 0, static_cast<R>(val), pol));
return true;
}
return false;
}
// Default instantiations with ignore_error policy.
template <class R, class T>
inline bool check_overflow(T /* val */, R* /* result */, const char* /* function */, const overflow_error<ignore_error>&){ return false; }
template <class R, class T>
inline bool check_underflow(T /* val */, R* /* result */, const char* /* function */, const underflow_error<ignore_error>&){ return false; }
template <class R, class T>
inline bool check_denorm(T /* val */, R* /* result*/, const char* /* function */, const denorm_error<ignore_error>&){ return false; }
} // namespace detail
template <class R, class Policy, class T>
inline R checked_narrowing_cast(T val, const char* function)
{
typedef typename Policy::overflow_error_type overflow_type;
typedef typename Policy::underflow_error_type underflow_type;
typedef typename Policy::denorm_error_type denorm_type;
//
// Most of what follows will evaluate to a no-op:
//
R result;
if(detail::check_overflow<R>(val, &result, function, overflow_type()))
return result;
if(detail::check_underflow<R>(val, &result, function, underflow_type()))
return result;
if(detail::check_denorm<R>(val, &result, function, denorm_type()))
return result;
return static_cast<R>(val);
}
template <class Policy>
inline void check_series_iterations(const char* function, boost::uintmax_t max_iter, const Policy& pol)
{
if(max_iter >= policies::get_max_series_iterations<Policy>())
raise_evaluation_error<boost::uintmax_t>(
function,
"Series evaluation exceeded %1% iterations, giving up now.", max_iter, pol);
}
} //namespace policies
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
}} // namespaces boost/math
#endif // BOOST_MATH_POLICY_ERROR_HANDLING_HPP

View File

@@ -0,0 +1,870 @@
// Copyright John Maddock 2007.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_POLICY_HPP
#define BOOST_MATH_POLICY_HPP
#include <boost/mpl/list.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/remove_if.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/comparison.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#include <boost/assert.hpp>
#include <boost/math/tools/config.hpp>
#include <limits>
// Sadly we do need the .h versions of these to be sure of getting
// FLT_MANT_DIG etc.
#include <limits.h>
#include <stdlib.h>
#include <stddef.h>
#include <math.h>
namespace boost{ namespace math{
namespace tools{
template <class T>
int digits(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(T));
}
namespace policies{
//
// Define macros for our default policies, if they're not defined already:
//
#ifndef BOOST_MATH_DOMAIN_ERROR_POLICY
#define BOOST_MATH_DOMAIN_ERROR_POLICY throw_on_error
#endif
#ifndef BOOST_MATH_POLE_ERROR_POLICY
#define BOOST_MATH_POLE_ERROR_POLICY throw_on_error
#endif
#ifndef BOOST_MATH_OVERFLOW_ERROR_POLICY
#define BOOST_MATH_OVERFLOW_ERROR_POLICY throw_on_error
#endif
#ifndef BOOST_MATH_EVALUATION_ERROR_POLICY
#define BOOST_MATH_EVALUATION_ERROR_POLICY throw_on_error
#endif
#ifndef BOOST_MATH_ROUNDING_ERROR_POLICY
#define BOOST_MATH_ROUNDING_ERROR_POLICY throw_on_error
#endif
#ifndef BOOST_MATH_UNDERFLOW_ERROR_POLICY
#define BOOST_MATH_UNDERFLOW_ERROR_POLICY ignore_error
#endif
#ifndef BOOST_MATH_DENORM_ERROR_POLICY
#define BOOST_MATH_DENORM_ERROR_POLICY ignore_error
#endif
#ifndef BOOST_MATH_INDETERMINATE_RESULT_ERROR_POLICY
#define BOOST_MATH_INDETERMINATE_RESULT_ERROR_POLICY ignore_error
#endif
#ifndef BOOST_MATH_DIGITS10_POLICY
#define BOOST_MATH_DIGITS10_POLICY 0
#endif
#ifndef BOOST_MATH_PROMOTE_FLOAT_POLICY
#define BOOST_MATH_PROMOTE_FLOAT_POLICY true
#endif
#ifndef BOOST_MATH_PROMOTE_DOUBLE_POLICY
#ifdef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
#define BOOST_MATH_PROMOTE_DOUBLE_POLICY false
#else
#define BOOST_MATH_PROMOTE_DOUBLE_POLICY true
#endif
#endif
#ifndef BOOST_MATH_DISCRETE_QUANTILE_POLICY
#define BOOST_MATH_DISCRETE_QUANTILE_POLICY integer_round_outwards
#endif
#ifndef BOOST_MATH_ASSERT_UNDEFINED_POLICY
#define BOOST_MATH_ASSERT_UNDEFINED_POLICY true
#endif
#ifndef BOOST_MATH_MAX_SERIES_ITERATION_POLICY
#define BOOST_MATH_MAX_SERIES_ITERATION_POLICY 1000000
#endif
#ifndef BOOST_MATH_MAX_ROOT_ITERATION_POLICY
#define BOOST_MATH_MAX_ROOT_ITERATION_POLICY 200
#endif
#if !defined(__BORLANDC__) \
&& !(defined(__GNUC__) && (__GNUC__ == 3) && (__GNUC_MINOR__ <= 2))
#define BOOST_MATH_META_INT(type, name, Default)\
template <type N = Default> struct name : public boost::mpl::int_<N>{};\
namespace detail{\
template <type N>\
char test_is_valid_arg(const name<N>*);\
char test_is_default_arg(const name<Default>*);\
template <class T> struct is_##name##_imp\
{\
template <type N> static char test(const name<N>*);\
static double test(...);\
BOOST_STATIC_CONSTANT(bool, value = sizeof(test(static_cast<T*>(0))) == 1);\
};\
}\
template <class T> struct is_##name : public boost::mpl::bool_< ::boost::math::policies::detail::is_##name##_imp<T>::value>{};
#define BOOST_MATH_META_BOOL(name, Default)\
template <bool N = Default> struct name : public boost::mpl::bool_<N>{};\
namespace detail{\
template <bool N>\
char test_is_valid_arg(const name<N>*);\
char test_is_default_arg(const name<Default>*);\
template <class T> struct is_##name##_imp\
{\
template <bool N> static char test(const name<N>*);\
static double test(...);\
BOOST_STATIC_CONSTANT(bool, value = sizeof(test(static_cast<T*>(0))) == 1);\
};\
}\
template <class T> struct is_##name : public boost::mpl::bool_< ::boost::math::policies::detail::is_##name##_imp<T>::value>{};
#else
#define BOOST_MATH_META_INT(Type, name, Default)\
template <Type N = Default> struct name : public boost::mpl::int_<N>{};\
namespace detail{\
template <Type N>\
char test_is_valid_arg(const name<N>*);\
char test_is_default_arg(const name<Default>*);\
template <class T> struct is_##name##_tester\
{\
template <Type N> static char test(const name<N>&);\
static double test(...);\
};\
template <class T> struct is_##name##_imp\
{\
static T inst;\
BOOST_STATIC_CONSTANT(bool, value = sizeof( ::boost::math::policies::detail::is_##name##_tester<T>::test(inst)) == 1);\
};\
}\
template <class T> struct is_##name : public boost::mpl::bool_< ::boost::math::policies::detail::is_##name##_imp<T>::value>\
{\
template <class U> struct apply{ typedef is_##name<U> type; };\
};
#define BOOST_MATH_META_BOOL(name, Default)\
template <bool N = Default> struct name : public boost::mpl::bool_<N>{};\
namespace detail{\
template <bool N>\
char test_is_valid_arg(const name<N>*);\
char test_is_default_arg(const name<Default>*);\
template <class T> struct is_##name##_tester\
{\
template <bool N> static char test(const name<N>&);\
static double test(...);\
};\
template <class T> struct is_##name##_imp\
{\
static T inst;\
BOOST_STATIC_CONSTANT(bool, value = sizeof( ::boost::math::policies::detail::is_##name##_tester<T>::test(inst)) == 1);\
};\
}\
template <class T> struct is_##name : public boost::mpl::bool_< ::boost::math::policies::detail::is_##name##_imp<T>::value>\
{\
template <class U> struct apply{ typedef is_##name<U> type; };\
};
#endif
//
// Begin by defining policy types for error handling:
//
enum error_policy_type
{
throw_on_error = 0,
errno_on_error = 1,
ignore_error = 2,
user_error = 3
};
BOOST_MATH_META_INT(error_policy_type, domain_error, BOOST_MATH_DOMAIN_ERROR_POLICY)
BOOST_MATH_META_INT(error_policy_type, pole_error, BOOST_MATH_POLE_ERROR_POLICY)
BOOST_MATH_META_INT(error_policy_type, overflow_error, BOOST_MATH_OVERFLOW_ERROR_POLICY)
BOOST_MATH_META_INT(error_policy_type, underflow_error, BOOST_MATH_UNDERFLOW_ERROR_POLICY)
BOOST_MATH_META_INT(error_policy_type, denorm_error, BOOST_MATH_DENORM_ERROR_POLICY)
BOOST_MATH_META_INT(error_policy_type, evaluation_error, BOOST_MATH_EVALUATION_ERROR_POLICY)
BOOST_MATH_META_INT(error_policy_type, rounding_error, BOOST_MATH_ROUNDING_ERROR_POLICY)
BOOST_MATH_META_INT(error_policy_type, indeterminate_result_error, BOOST_MATH_INDETERMINATE_RESULT_ERROR_POLICY)
//
// Policy types for internal promotion:
//
BOOST_MATH_META_BOOL(promote_float, BOOST_MATH_PROMOTE_FLOAT_POLICY)
BOOST_MATH_META_BOOL(promote_double, BOOST_MATH_PROMOTE_DOUBLE_POLICY)
BOOST_MATH_META_BOOL(assert_undefined, BOOST_MATH_ASSERT_UNDEFINED_POLICY)
//
// Policy types for discrete quantiles:
//
enum discrete_quantile_policy_type
{
real,
integer_round_outwards,
integer_round_inwards,
integer_round_down,
integer_round_up,
integer_round_nearest
};
BOOST_MATH_META_INT(discrete_quantile_policy_type, discrete_quantile, BOOST_MATH_DISCRETE_QUANTILE_POLICY)
//
// Precision:
//
BOOST_MATH_META_INT(int, digits10, BOOST_MATH_DIGITS10_POLICY)
BOOST_MATH_META_INT(int, digits2, 0)
//
// Iterations:
//
BOOST_MATH_META_INT(unsigned long, max_series_iterations, BOOST_MATH_MAX_SERIES_ITERATION_POLICY)
BOOST_MATH_META_INT(unsigned long, max_root_iterations, BOOST_MATH_MAX_ROOT_ITERATION_POLICY)
//
// Define the names for each possible policy:
//
#define BOOST_MATH_PARAMETER(name)\
BOOST_PARAMETER_TEMPLATE_KEYWORD(name##_name)\
BOOST_PARAMETER_NAME(name##_name)
struct default_policy{};
namespace detail{
//
// Trait to work out bits precision from digits10 and digits2:
//
template <class Digits10, class Digits2>
struct precision
{
//
// Now work out the precision:
//
typedef typename mpl::if_c<
(Digits10::value == 0),
digits2<0>,
digits2<((Digits10::value + 1) * 1000L) / 301L>
>::type digits2_type;
public:
#ifdef __BORLANDC__
typedef typename mpl::if_c<
(Digits2::value > ::boost::math::policies::detail::precision<Digits10,Digits2>::digits2_type::value),
Digits2, digits2_type>::type type;
#else
typedef typename mpl::if_c<
(Digits2::value > digits2_type::value),
Digits2, digits2_type>::type type;
#endif
};
template <class A, class B, bool b>
struct select_result
{
typedef A type;
};
template <class A, class B>
struct select_result<A, B, false>
{
typedef typename mpl::deref<B>::type type;
};
template <class Seq, class Pred, class DefaultType>
struct find_arg
{
private:
typedef typename mpl::find_if<Seq, Pred>::type iter;
typedef typename mpl::end<Seq>::type end_type;
public:
typedef typename select_result<
DefaultType, iter,
::boost::is_same<iter, end_type>::value>::type type;
};
double test_is_valid_arg(...);
double test_is_default_arg(...);
char test_is_valid_arg(const default_policy*);
char test_is_default_arg(const default_policy*);
template <class T>
struct is_valid_policy_imp
{
BOOST_STATIC_CONSTANT(bool, value = sizeof(test_is_valid_arg(static_cast<T*>(0))) == 1);
};
template <class T>
struct is_default_policy_imp
{
BOOST_STATIC_CONSTANT(bool, value = sizeof(test_is_default_arg(static_cast<T*>(0))) == 1);
};
template <class T> struct is_valid_policy
: public mpl::bool_<
::boost::math::policies::detail::is_valid_policy_imp<T>::value>
{};
template <class T> struct is_default_policy
: public mpl::bool_<
::boost::math::policies::detail::is_default_policy_imp<T>::value>
{
template <class U>
struct apply
{
typedef is_default_policy<U> type;
};
};
template <class Seq, class T, int N>
struct append_N
{
typedef typename mpl::push_back<Seq, T>::type new_seq;
typedef typename append_N<new_seq, T, N-1>::type type;
};
template <class Seq, class T>
struct append_N<Seq, T, 0>
{
typedef Seq type;
};
//
// Traits class to work out what template parameters our default
// policy<> class will have when modified for forwarding:
//
template <bool f, bool d>
struct default_args
{
typedef promote_float<false> arg1;
typedef promote_double<false> arg2;
};
template <>
struct default_args<false, false>
{
typedef default_policy arg1;
typedef default_policy arg2;
};
template <>
struct default_args<true, false>
{
typedef promote_float<false> arg1;
typedef default_policy arg2;
};
template <>
struct default_args<false, true>
{
typedef promote_double<false> arg1;
typedef default_policy arg2;
};
typedef default_args<BOOST_MATH_PROMOTE_FLOAT_POLICY, BOOST_MATH_PROMOTE_DOUBLE_POLICY>::arg1 forwarding_arg1;
typedef default_args<BOOST_MATH_PROMOTE_FLOAT_POLICY, BOOST_MATH_PROMOTE_DOUBLE_POLICY>::arg2 forwarding_arg2;
} // detail
//
// Now define the policy type with enough arguments to handle all
// the policies:
//
template <class A1 = default_policy,
class A2 = default_policy,
class A3 = default_policy,
class A4 = default_policy,
class A5 = default_policy,
class A6 = default_policy,
class A7 = default_policy,
class A8 = default_policy,
class A9 = default_policy,
class A10 = default_policy,
class A11 = default_policy,
class A12 = default_policy,
class A13 = default_policy>
struct policy
{
private:
//
// Validate all our arguments:
//
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A1>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A2>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A3>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A4>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A5>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A6>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A7>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A8>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A9>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A10>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A11>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A12>::value);
BOOST_STATIC_ASSERT(::boost::math::policies::detail::is_valid_policy<A13>::value);
//
// Typelist of the arguments:
//
typedef mpl::list<A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13> arg_list;
public:
typedef typename detail::find_arg<arg_list, is_domain_error<mpl::_1>, domain_error<> >::type domain_error_type;
typedef typename detail::find_arg<arg_list, is_pole_error<mpl::_1>, pole_error<> >::type pole_error_type;
typedef typename detail::find_arg<arg_list, is_overflow_error<mpl::_1>, overflow_error<> >::type overflow_error_type;
typedef typename detail::find_arg<arg_list, is_underflow_error<mpl::_1>, underflow_error<> >::type underflow_error_type;
typedef typename detail::find_arg<arg_list, is_denorm_error<mpl::_1>, denorm_error<> >::type denorm_error_type;
typedef typename detail::find_arg<arg_list, is_evaluation_error<mpl::_1>, evaluation_error<> >::type evaluation_error_type;
typedef typename detail::find_arg<arg_list, is_rounding_error<mpl::_1>, rounding_error<> >::type rounding_error_type;
typedef typename detail::find_arg<arg_list, is_indeterminate_result_error<mpl::_1>, indeterminate_result_error<> >::type indeterminate_result_error_type;
private:
//
// Now work out the precision:
//
typedef typename detail::find_arg<arg_list, is_digits10<mpl::_1>, digits10<> >::type digits10_type;
typedef typename detail::find_arg<arg_list, is_digits2<mpl::_1>, digits2<> >::type bits_precision_type;
public:
typedef typename detail::precision<digits10_type, bits_precision_type>::type precision_type;
//
// Internal promotion:
//
typedef typename detail::find_arg<arg_list, is_promote_float<mpl::_1>, promote_float<> >::type promote_float_type;
typedef typename detail::find_arg<arg_list, is_promote_double<mpl::_1>, promote_double<> >::type promote_double_type;
//
// Discrete quantiles:
//
typedef typename detail::find_arg<arg_list, is_discrete_quantile<mpl::_1>, discrete_quantile<> >::type discrete_quantile_type;
//
// Mathematically undefined properties:
//
typedef typename detail::find_arg<arg_list, is_assert_undefined<mpl::_1>, discrete_quantile<> >::type assert_undefined_type;
//
// Max iterations:
//
typedef typename detail::find_arg<arg_list, is_max_series_iterations<mpl::_1>, max_series_iterations<> >::type max_series_iterations_type;
typedef typename detail::find_arg<arg_list, is_max_root_iterations<mpl::_1>, max_root_iterations<> >::type max_root_iterations_type;
};
//
// These full specializations are defined to reduce the amount of
// template instantiations that have to take place when using the default
// policies, they have quite a large impact on compile times:
//
template <>
struct policy<default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy>
{
public:
typedef domain_error<> domain_error_type;
typedef pole_error<> pole_error_type;
typedef overflow_error<> overflow_error_type;
typedef underflow_error<> underflow_error_type;
typedef denorm_error<> denorm_error_type;
typedef evaluation_error<> evaluation_error_type;
typedef rounding_error<> rounding_error_type;
typedef indeterminate_result_error<> indeterminate_result_error_type;
#if BOOST_MATH_DIGITS10_POLICY == 0
typedef digits2<> precision_type;
#else
typedef detail::precision<digits10<>, digits2<> >::type precision_type;
#endif
typedef promote_float<> promote_float_type;
typedef promote_double<> promote_double_type;
typedef discrete_quantile<> discrete_quantile_type;
typedef assert_undefined<> assert_undefined_type;
typedef max_series_iterations<> max_series_iterations_type;
typedef max_root_iterations<> max_root_iterations_type;
};
template <>
struct policy<detail::forwarding_arg1, detail::forwarding_arg2, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy, default_policy>
{
public:
typedef domain_error<> domain_error_type;
typedef pole_error<> pole_error_type;
typedef overflow_error<> overflow_error_type;
typedef underflow_error<> underflow_error_type;
typedef denorm_error<> denorm_error_type;
typedef evaluation_error<> evaluation_error_type;
typedef rounding_error<> rounding_error_type;
typedef indeterminate_result_error<> indeterminate_result_error_type;
#if BOOST_MATH_DIGITS10_POLICY == 0
typedef digits2<> precision_type;
#else
typedef detail::precision<digits10<>, digits2<> >::type precision_type;
#endif
typedef promote_float<false> promote_float_type;
typedef promote_double<false> promote_double_type;
typedef discrete_quantile<> discrete_quantile_type;
typedef assert_undefined<> assert_undefined_type;
typedef max_series_iterations<> max_series_iterations_type;
typedef max_root_iterations<> max_root_iterations_type;
};
template <class Policy,
class A1 = default_policy,
class A2 = default_policy,
class A3 = default_policy,
class A4 = default_policy,
class A5 = default_policy,
class A6 = default_policy,
class A7 = default_policy,
class A8 = default_policy,
class A9 = default_policy,
class A10 = default_policy,
class A11 = default_policy,
class A12 = default_policy,
class A13 = default_policy>
struct normalise
{
private:
typedef mpl::list<A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11,A12,A13> arg_list;
typedef typename detail::find_arg<arg_list, is_domain_error<mpl::_1>, typename Policy::domain_error_type >::type domain_error_type;
typedef typename detail::find_arg<arg_list, is_pole_error<mpl::_1>, typename Policy::pole_error_type >::type pole_error_type;
typedef typename detail::find_arg<arg_list, is_overflow_error<mpl::_1>, typename Policy::overflow_error_type >::type overflow_error_type;
typedef typename detail::find_arg<arg_list, is_underflow_error<mpl::_1>, typename Policy::underflow_error_type >::type underflow_error_type;
typedef typename detail::find_arg<arg_list, is_denorm_error<mpl::_1>, typename Policy::denorm_error_type >::type denorm_error_type;
typedef typename detail::find_arg<arg_list, is_evaluation_error<mpl::_1>, typename Policy::evaluation_error_type >::type evaluation_error_type;
typedef typename detail::find_arg<arg_list, is_rounding_error<mpl::_1>, typename Policy::rounding_error_type >::type rounding_error_type;
typedef typename detail::find_arg<arg_list, is_indeterminate_result_error<mpl::_1>, typename Policy::indeterminate_result_error_type >::type indeterminate_result_error_type;
//
// Now work out the precision:
//
typedef typename detail::find_arg<arg_list, is_digits10<mpl::_1>, digits10<> >::type digits10_type;
typedef typename detail::find_arg<arg_list, is_digits2<mpl::_1>, typename Policy::precision_type >::type bits_precision_type;
typedef typename detail::precision<digits10_type, bits_precision_type>::type precision_type;
//
// Internal promotion:
//
typedef typename detail::find_arg<arg_list, is_promote_float<mpl::_1>, typename Policy::promote_float_type >::type promote_float_type;
typedef typename detail::find_arg<arg_list, is_promote_double<mpl::_1>, typename Policy::promote_double_type >::type promote_double_type;
//
// Discrete quantiles:
//
typedef typename detail::find_arg<arg_list, is_discrete_quantile<mpl::_1>, typename Policy::discrete_quantile_type >::type discrete_quantile_type;
//
// Mathematically undefined properties:
//
typedef typename detail::find_arg<arg_list, is_assert_undefined<mpl::_1>, discrete_quantile<> >::type assert_undefined_type;
//
// Max iterations:
//
typedef typename detail::find_arg<arg_list, is_max_series_iterations<mpl::_1>, max_series_iterations<> >::type max_series_iterations_type;
typedef typename detail::find_arg<arg_list, is_max_root_iterations<mpl::_1>, max_root_iterations<> >::type max_root_iterations_type;
//
// Define a typelist of the policies:
//
typedef mpl::vector<
domain_error_type,
pole_error_type,
overflow_error_type,
underflow_error_type,
denorm_error_type,
evaluation_error_type,
rounding_error_type,
indeterminate_result_error_type,
precision_type,
promote_float_type,
promote_double_type,
discrete_quantile_type,
assert_undefined_type,
max_series_iterations_type,
max_root_iterations_type> result_list;
//
// Remove all the policies that are the same as the default:
//
typedef typename mpl::remove_if<result_list, detail::is_default_policy<mpl::_> >::type reduced_list;
//
// Pad out the list with defaults:
//
typedef typename detail::append_N<reduced_list, default_policy, (14 - ::boost::mpl::size<reduced_list>::value)>::type result_type;
public:
typedef policy<
typename mpl::at<result_type, mpl::int_<0> >::type,
typename mpl::at<result_type, mpl::int_<1> >::type,
typename mpl::at<result_type, mpl::int_<2> >::type,
typename mpl::at<result_type, mpl::int_<3> >::type,
typename mpl::at<result_type, mpl::int_<4> >::type,
typename mpl::at<result_type, mpl::int_<5> >::type,
typename mpl::at<result_type, mpl::int_<6> >::type,
typename mpl::at<result_type, mpl::int_<7> >::type,
typename mpl::at<result_type, mpl::int_<8> >::type,
typename mpl::at<result_type, mpl::int_<9> >::type,
typename mpl::at<result_type, mpl::int_<10> >::type,
typename mpl::at<result_type, mpl::int_<11> >::type,
typename mpl::at<result_type, mpl::int_<12> >::type > type;
};
//
// Full specialisation to speed up compilation of the common case:
//
template <>
struct normalise<policy<>,
promote_float<false>,
promote_double<false>,
discrete_quantile<>,
assert_undefined<>,
default_policy,
default_policy,
default_policy,
default_policy,
default_policy,
default_policy,
default_policy>
{
typedef policy<detail::forwarding_arg1, detail::forwarding_arg2> type;
};
inline policy<> make_policy()
{ return policy<>(); }
template <class A1>
inline typename normalise<policy<>, A1>::type make_policy(const A1&)
{
typedef typename normalise<policy<>, A1>::type result_type;
return result_type();
}
template <class A1, class A2>
inline typename normalise<policy<>, A1, A2>::type make_policy(const A1&, const A2&)
{
typedef typename normalise<policy<>, A1, A2>::type result_type;
return result_type();
}
template <class A1, class A2, class A3>
inline typename normalise<policy<>, A1, A2, A3>::type make_policy(const A1&, const A2&, const A3&)
{
typedef typename normalise<policy<>, A1, A2, A3>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4>
inline typename normalise<policy<>, A1, A2, A3, A4>::type make_policy(const A1&, const A2&, const A3&, const A4&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4, class A5>
inline typename normalise<policy<>, A1, A2, A3, A4, A5>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4, A5>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4, class A5, class A6>
inline typename normalise<policy<>, A1, A2, A3, A4, A5, A6>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4, A5, A6>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7>
inline typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8>
inline typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&, const A8&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9>
inline typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8, A9>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&, const A8&, const A9&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8, A9>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10>
inline typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&, const A8&, const A9&, const A10&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10>::type result_type;
return result_type();
}
template <class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9, class A10, class A11>
inline typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::type make_policy(const A1&, const A2&, const A3&, const A4&, const A5&, const A6&, const A7&, const A8&, const A9&, const A10&, const A11&)
{
typedef typename normalise<policy<>, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11>::type result_type;
return result_type();
}
//
// Traits class to handle internal promotion:
//
template <class Real, class Policy>
struct evaluation
{
typedef Real type;
};
template <class Policy>
struct evaluation<float, Policy>
{
typedef typename mpl::if_<typename Policy::promote_float_type, double, float>::type type;
};
template <class Policy>
struct evaluation<double, Policy>
{
typedef typename mpl::if_<typename Policy::promote_double_type, long double, double>::type type;
};
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
template <class Real>
struct basic_digits : public mpl::int_<0>{ };
template <>
struct basic_digits<float> : public mpl::int_<FLT_MANT_DIG>{ };
template <>
struct basic_digits<double> : public mpl::int_<DBL_MANT_DIG>{ };
template <>
struct basic_digits<long double> : public mpl::int_<LDBL_MANT_DIG>{ };
template <class Real, class Policy>
struct precision
{
typedef typename Policy::precision_type precision_type;
typedef basic_digits<Real> digits_t;
typedef typename mpl::if_<
mpl::equal_to<digits_t, mpl::int_<0> >,
// Possibly unknown precision:
precision_type,
typename mpl::if_<
mpl::or_<mpl::less_equal<digits_t, precision_type>, mpl::less_equal<precision_type, mpl::int_<0> > >,
// Default case, full precision for RealType:
digits2< ::std::numeric_limits<Real>::digits>,
// User customised precision:
precision_type
>::type
>::type type;
};
template <class Policy>
struct precision<float, Policy>
{
typedef digits2<FLT_MANT_DIG> type;
};
template <class Policy>
struct precision<double, Policy>
{
typedef digits2<DBL_MANT_DIG> type;
};
template <class Policy>
struct precision<long double, Policy>
{
typedef digits2<LDBL_MANT_DIG> type;
};
#else
template <class Real, class Policy>
struct precision
{
#ifndef __BORLANDC__
typedef typename Policy::precision_type precision_type;
typedef typename mpl::if_c<
((::std::numeric_limits<Real>::is_specialized == 0) || (::std::numeric_limits<Real>::digits == 0)),
// Possibly unknown precision:
precision_type,
typename mpl::if_c<
((::std::numeric_limits<Real>::digits <= precision_type::value)
|| (Policy::precision_type::value <= 0)),
// Default case, full precision for RealType:
digits2< ::std::numeric_limits<Real>::digits>,
// User customised precision:
precision_type
>::type
>::type type;
#else
typedef typename Policy::precision_type precision_type;
typedef mpl::int_< ::std::numeric_limits<Real>::digits> digits_t;
typedef mpl::bool_< ::std::numeric_limits<Real>::is_specialized> spec_t;
typedef typename mpl::if_<
mpl::or_<mpl::equal_to<spec_t, mpl::false_>, mpl::equal_to<digits_t, mpl::int_<0> > >,
// Possibly unknown precision:
precision_type,
typename mpl::if_<
mpl::or_<mpl::less_equal<digits_t, precision_type>, mpl::less_equal<precision_type, mpl::int_<0> > >,
// Default case, full precision for RealType:
digits2< ::std::numeric_limits<Real>::digits>,
// User customised precision:
precision_type
>::type
>::type type;
#endif
};
#endif
namespace detail{
template <class T, class Policy>
inline int digits_imp(mpl::true_ const&)
{
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
BOOST_STATIC_ASSERT( ::std::numeric_limits<T>::is_specialized);
#else
BOOST_ASSERT(::std::numeric_limits<T>::is_specialized);
#endif
typedef typename boost::math::policies::precision<T, Policy>::type p_t;
return p_t::value;
}
template <class T, class Policy>
inline int digits_imp(mpl::false_ const&)
{
return tools::digits<T>();
}
} // namespace detail
template <class T, class Policy>
inline int digits()
{
typedef mpl::bool_< std::numeric_limits<T>::is_specialized > tag_type;
return detail::digits_imp<T, Policy>(tag_type());
}
template <class Policy>
inline unsigned long get_max_series_iterations()
{
typedef typename Policy::max_series_iterations_type iter_type;
return iter_type::value;
}
template <class Policy>
inline unsigned long get_max_root_iterations()
{
typedef typename Policy::max_root_iterations_type iter_type;
return iter_type::value;
}
namespace detail{
template <class A1,
class A2,
class A3,
class A4,
class A5,
class A6,
class A7,
class A8,
class A9,
class A10,
class A11>
char test_is_policy(const policy<A1,A2,A3,A4,A5,A6,A7,A8,A9,A10,A11>*);
double test_is_policy(...);
template <class P>
struct is_policy_imp
{
BOOST_STATIC_CONSTANT(bool, value = (sizeof(test_is_policy(static_cast<P*>(0))) == 1));
};
}
template <class P>
struct is_policy : public mpl::bool_< ::boost::math::policies::detail::is_policy_imp<P>::value> {};
}}} // namespaces
#endif // BOOST_MATH_POLICY_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
// 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/expint.hpp>
#include <boost/math/special_functions/expm1.hpp>
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/fpclassify.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/hermite.hpp>
#include <boost/math/special_functions/hypot.hpp>
#include <boost/math/special_functions/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>
#include <boost/math/special_functions/zeta.hpp>
#include <boost/math/special_functions/modf.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/special_functions/pow.hpp>
#include <boost/math/special_functions/next.hpp>
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_HPP

View File

@@ -0,0 +1,114 @@
// boost asinh.hpp header file
// (C) Copyright Eric Ford 2001 & Hubert Holin.
// (C) Copyright John Maddock 2008.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_ACOSH_HPP
#define BOOST_ACOSH_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/log1p.hpp>
// This is the inverse of the hyperbolic cosine function.
namespace boost
{
namespace math
{
namespace detail
{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::log;
using ::std::numeric_limits;
#endif
template<typename T, typename Policy>
inline T acosh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if(x < 1)
{
return policies::raise_domain_error<T>(
"boost::math::acosh<%1%>(%1%)",
"acosh requires x >= 1, but got x = %1%.", x, pol);
}
else if ((x - 1) >= tools::root_epsilon<T>())
{
if (x > 1 / tools::root_epsilon<T>())
{
// http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/06/01/0001/
// approximation by laurent series in 1/x at 0+ order from -1 to 0
return( log( x * 2) );
}
else if(x < 1.5f)
{
// This is just a rearrangement of the standard form below
// devised to minimse loss of precision when x ~ 1:
T y = x - 1;
return boost::math::log1p(y + sqrt(y * y + 2 * y), pol);
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcCosh/02/
return( log( x + sqrt(x * x - 1) ) );
}
}
else
{
// see http://functions.wolfram.com/ElementaryFunctions/ArcCosh/06/01/04/01/0001/
T y = x - 1;
// approximation by taylor series in y at 0 up to order 2
T result = sqrt(2 * y) * (1 + y /12 + 3 * y * y / 160);
return result;
}
}
}
template<typename T, typename Policy>
inline typename tools::promote_args<T>::type acosh(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::acosh_imp(static_cast<value_type>(x), forwarding_policy()),
"boost::math::acosh<%1%>(%1%)");
}
template<typename T>
inline typename tools::promote_args<T>::type acosh(T x)
{
return boost::math::acosh(x, policies::policy<>());
}
}
}
#endif /* BOOST_ACOSH_HPP */

View File

@@ -0,0 +1,116 @@
// boost asinh.hpp header file
// (C) Copyright Eric Ford & Hubert Holin 2001.
// (C) Copyright John Maddock 2008.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_ASINH_HPP
#define BOOST_ASINH_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/sqrt1pm1.hpp>
#include <boost/math/special_functions/log1p.hpp>
// This is the inverse of the hyperbolic sine function.
namespace boost
{
namespace math
{
namespace detail{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::log;
using ::std::numeric_limits;
#endif
template<typename T, class Policy>
inline T asinh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
if (x >= tools::forth_root_epsilon<T>())
{
if (x > 1 / tools::root_epsilon<T>())
{
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/06/01/0001/
// approximation by laurent series in 1/x at 0+ order from -1 to 1
return log(x * 2) + 1/ (4 * x * x);
}
else if(x < 0.5f)
{
// As below, but rearranged to preserve digits:
return boost::math::log1p(x + boost::math::sqrt1pm1(x * x, pol), pol);
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/02/
return( log( x + sqrt(x*x+1) ) );
}
}
else if (x <= -tools::forth_root_epsilon<T>())
{
return(-asinh(-x));
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcSinh/06/01/03/01/0001/
// approximation by taylor series in x at 0 up to order 2
T result = x;
if (abs(x) >= tools::root_epsilon<T>())
{
T x3 = x*x*x;
// approximation by taylor series in x at 0 up to order 4
result -= x3/static_cast<T>(6);
}
return(result);
}
}
}
template<typename T>
inline typename tools::promote_args<T>::type asinh(T x)
{
return boost::math::asinh(x, policies::policy<>());
}
template<typename T, typename Policy>
inline typename tools::promote_args<T>::type asinh(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::asinh_imp(static_cast<value_type>(x), forwarding_policy()),
"boost::math::asinh<%1%>(%1%)");
}
}
}
#endif /* BOOST_ASINH_HPP */

View File

@@ -0,0 +1,128 @@
// boost atanh.hpp header file
// (C) Copyright Hubert Holin 2001.
// (C) Copyright John Maddock 2008.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See http://www.boost.org for updates, documentation, and revision history.
#ifndef BOOST_ATANH_HPP
#define BOOST_ATANH_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/config.hpp>
#include <boost/math/tools/precision.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/special_functions/log1p.hpp>
// This is the inverse of the hyperbolic tangent function.
namespace boost
{
namespace math
{
namespace detail
{
#if defined(__GNUC__) && (__GNUC__ < 3)
// gcc 2.x ignores function scope using declarations,
// put them in the scope of the enclosing namespace instead:
using ::std::abs;
using ::std::sqrt;
using ::std::log;
using ::std::numeric_limits;
#endif
// This is the main fare
template<typename T, typename Policy>
inline T atanh_imp(const T x, const Policy& pol)
{
BOOST_MATH_STD_USING
static const char* function = "boost::math::atanh<%1%>(%1%)";
if(x < -1)
{
return policies::raise_domain_error<T>(
function,
"atanh requires x >= -1, but got x = %1%.", x, pol);
}
else if(x < -1 + tools::epsilon<T>())
{
// -Infinity:
return -policies::raise_overflow_error<T>(function, 0, pol);
}
else if(x > 1 - tools::epsilon<T>())
{
// Infinity:
return -policies::raise_overflow_error<T>(function, 0, pol);
}
else if(x > 1)
{
return policies::raise_domain_error<T>(
function,
"atanh requires x <= 1, but got x = %1%.", x, pol);
}
else if(abs(x) >= tools::forth_root_epsilon<T>())
{
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/02/
if(abs(x) < 0.5f)
return (boost::math::log1p(x, pol) - boost::math::log1p(-x, pol)) / 2;
return(log( (1 + x) / (1 - x) ) / 2);
}
else
{
// http://functions.wolfram.com/ElementaryFunctions/ArcTanh/06/01/03/01/
// approximation by taylor series in x at 0 up to order 2
T result = x;
if (abs(x) >= tools::root_epsilon<T>())
{
T x3 = x*x*x;
// approximation by taylor series in x at 0 up to order 4
result += x3/static_cast<T>(3);
}
return(result);
}
}
}
template<typename T, typename Policy>
inline typename tools::promote_args<T>::type atanh(T x, const Policy&)
{
typedef typename tools::promote_args<T>::type result_type;
typedef typename policies::evaluation<result_type, Policy>::type value_type;
typedef typename policies::normalise<
Policy,
policies::promote_float<false>,
policies::promote_double<false>,
policies::discrete_quantile<>,
policies::assert_undefined<> >::type forwarding_policy;
return policies::checked_narrowing_cast<result_type, forwarding_policy>(
detail::atanh_imp(static_cast<value_type>(x), forwarding_policy()),
"boost::math::atanh<%1%>(%1%)");
}
template<typename T>
inline typename tools::promote_args<T>::type atanh(T x)
{
return boost::math::atanh(x, policies::policy<>());
}
}
}
#endif /* BOOST_ATANH_HPP */

View File

@@ -0,0 +1,510 @@
// Copyright (c) 2007 John Maddock
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This header just defines the function entry points, and adds dispatch
// to the right implementation method. Most of the implementation details
// are in separate headers and copyright Xiaogang Zhang.
//
#ifndef BOOST_MATH_BESSEL_HPP
#define BOOST_MATH_BESSEL_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_jy.hpp>
#include <boost/math/special_functions/detail/bessel_jn.hpp>
#include <boost/math/special_functions/detail/bessel_yn.hpp>
#include <boost/math/special_functions/detail/bessel_ik.hpp>
#include <boost/math/special_functions/detail/bessel_i0.hpp>
#include <boost/math/special_functions/detail/bessel_i1.hpp>
#include <boost/math/special_functions/detail/bessel_kn.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
#include <boost/math/special_functions/sinc.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/promotion.hpp>
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>();
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
T zero = 0;
T result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter, zero);
#else
T result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter);
#endif
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>();
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
T zero = 0;
T result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter, zero);
#else
T result = boost::math::tools::sum_series(s, boost::math::policies::digits<T, Policy>(), max_iter);
#endif
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(iround(v, pol) & 1)
r = -r;
return r;
}
else
return policies::raise_domain_error<T>(
function,
"Got x = %1%, but we need x >= 0", x, pol);
}
if(x == 0)
return (v == 0) ? 1 : (v > 0) ? 0 :
policies::raise_domain_error<T>(
function,
"Got v = %1%, but require v >= 0 or a negative integer: the result would be complex.", v, pol);
if((v >= 0) && ((x < 1) || (v > x * x / 4)))
{
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(iround(v, pol), x, pol);
}
return cyl_bessel_j_imp(v, x, bessel_no_int_tag(), pol);
}
template <class T, class Policy>
inline T cyl_bessel_j_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING
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(iround(v, pol) & 1)
r = -r;
return r;
}
else
return policies::raise_domain_error<T>(
"boost::math::cyl_bessel_i<%1%>(%1%,%1%)",
"Got x = %1%, but we need x >= 0", x, pol);
}
if(x == 0)
{
return (v == 0) ? 1 : 0;
}
if(v == 0.5f)
{
// common special case, note try and avoid overflow in exp(x):
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(itrunc(v), x, pol);
}
return cyl_bessel_k_imp(v, x, bessel_no_int_tag(), pol);
}
template <class T, class Policy>
inline T cyl_bessel_k_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
{
return bessel_kn(v, x, pol);
}
template <class T, class Policy>
inline T cyl_neumann_imp(T v, T x, const bessel_no_int_tag&, const Policy& pol)
{
static const char* function = "boost::math::cyl_neumann<%1%>(%1%,%1%)";
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
if(x <= 0)
{
return (v == 0) && (x == 0) ?
policies::raise_overflow_error<T>(function, 0, pol)
: policies::raise_domain_error<T>(
function,
"Got x = %1%, but result is complex for x <= 0", x, pol);
}
T j, y;
bessel_jy(v, x, &j, &y, need_y, pol);
//
// Post evaluation check for internal overflow during evaluation,
// can occur when x is small and v is large, in which case the result
// is -INF:
//
if(!(boost::math::isfinite)(y))
return -policies::raise_overflow_error<T>(function, 0, pol);
return y;
}
template <class T, class Policy>
inline T cyl_neumann_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
if(floor(v) == v)
{
if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
{
T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
if((v < 0) && (itrunc(v, pol) & 1))
r = -r;
BOOST_MATH_INSTRUMENT_VARIABLE(r);
return r;
}
else
{
T r = bessel_yn(itrunc(v, pol), x, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(r);
return r;
}
}
T r = cyl_neumann_imp<T>(v, x, bessel_no_int_tag(), pol);
BOOST_MATH_INSTRUMENT_VARIABLE(r);
return r;
}
template <class T, class Policy>
inline T cyl_neumann_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
{
BOOST_MATH_STD_USING
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
BOOST_MATH_INSTRUMENT_VARIABLE(v);
BOOST_MATH_INSTRUMENT_VARIABLE(x);
if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
{
T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
if((v < 0) && (v & 1))
r = -r;
return r;
}
else
return bessel_yn(v, x, pol);
}
template <class T, class Policy>
inline T sph_neumann_imp(unsigned v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
static const char* function = "boost::math::sph_neumann<%1%>(%1%,%1%)";
//
// Nothing much to do here but check for errors, and
// evaluate the function's definition directly:
//
if(x < 0)
return policies::raise_domain_error<T>(
function,
"Got x = %1%, but function requires x > 0.", x, pol);
if(x < 2 * tools::min_value<T>())
return -policies::raise_overflow_error<T>(function, 0, pol);
T result = cyl_neumann_imp(T(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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,80 @@
// Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SF_BINOMIAL_HPP
#define BOOST_MATH_SF_BINOMIAL_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/factorials.hpp>
#include <boost/math/special_functions/beta.hpp>
#include <boost/math/policies/error_handling.hpp>
namespace boost{ namespace math{
template <class T, class Policy>
T binomial_coefficient(unsigned n, unsigned k, const Policy& pol)
{
BOOST_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

View File

@@ -0,0 +1,77 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SF_CBRT_HPP
#define BOOST_MATH_SF_CBRT_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/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

View File

@@ -0,0 +1,68 @@
// Copyright (c) 2007 John Maddock
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_COS_PI_HPP
#define BOOST_MATH_COS_PI_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/trunc.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/constants/constants.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T, class Policy>
T cos_pi_imp(T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
// cos of pi*x:
bool invert = false;
if(x < 0.5)
return cos(constants::pi<T>() * x);
if(x < 1)
{
x = -x;
}
T rem = floor(x);
if(itrunc(rem, pol) & 1)
invert = !invert;
rem = x - rem;
if(rem > 0.5f)
{
rem = 1 - rem;
invert = !invert;
}
if(rem == 0.5f)
return 0;
rem = cos(constants::pi<T>() * rem);
return invert ? -rem : rem;
}
} // namespace detail
template <class T, class Policy>
inline typename tools::promote_args<T>::type cos_pi(T x, const Policy& pol)
{
typedef typename tools::promote_args<T>::type result_type;
return boost::math::detail::cos_pi_imp<result_type>(x, pol);
}
template <class T>
inline typename tools::promote_args<T>::type cos_pi(T x)
{
return boost::math::cos_pi(x, policies::policy<>());
}
} // namespace math
} // namespace boost
#endif

View File

@@ -0,0 +1,101 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_I0_HPP
#define BOOST_MATH_BESSEL_I0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/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

View File

@@ -0,0 +1,104 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_I1_HPP
#define BOOST_MATH_BESSEL_I1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/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

View File

@@ -0,0 +1,337 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_IK_HPP
#define BOOST_MATH_BESSEL_IK_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/round.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/config.hpp>
// Modified Bessel functions of the first and second kind of fractional order
namespace boost { namespace math {
namespace detail {
// Calculate K(v, x) and K(v+1, x) by method analogous to
// Temme, Journal of Computational Physics, vol 21, 343 (1976)
template <typename T, typename Policy>
int temme_ik(T v, T x, T* K, T* K1, const Policy& pol)
{
T f, h, p, q, coef, sum, sum1, tolerance;
T a, b, c, d, sigma, gamma1, gamma2;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
// |x| <= 2, Temme series converge rapidly
// |x| > 2, the larger the |x|, the slower the convergence
BOOST_ASSERT(abs(x) <= 2);
BOOST_ASSERT(abs(v) <= 0.5f);
T gp = boost::math::tgamma1pm1(v, pol);
T gm = boost::math::tgamma1pm1(-v, pol);
a = log(x / 2);
b = exp(v * a);
sigma = -a * v;
c = abs(v) < tools::epsilon<T>() ?
1 : boost::math::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 = iround(v, pol);
u = v - n; // -1/2 <= u < 1/2
BOOST_MATH_INSTRUMENT_VARIABLE(n);
BOOST_MATH_INSTRUMENT_VARIABLE(u);
if (x < 0)
{
*I = *K = policies::raise_domain_error<T>(function,
"Got x = %1% but real argument x must be non-negative, complex number result not supported.", x, pol);
return 1;
}
if (x == 0)
{
Iv = (v == 0) ? static_cast<T>(1) : static_cast<T>(0);
if(kind & need_k)
{
Kv = policies::raise_overflow_error<T>(function, 0, pol);
}
else
{
Kv = std::numeric_limits<T>::quiet_NaN(); // any value will do
}
if(reflect && (kind & need_i))
{
T z = (u + n % 2);
Iv = boost::math::sin_pi(z, pol) == 0 ?
Iv :
policies::raise_overflow_error<T>(function, 0, pol); // reflection formula
}
*I = Iv;
*K = Kv;
return 0;
}
// x is positive until reflection
W = 1 / x; // Wronskian
if (x <= 2) // x in (0, 2]
{
temme_ik(u, x, &Ku, &Ku1, pol); // Temme series
}
else // x in (2, \infty)
{
CF2_ik(u, x, &Ku, &Ku1, pol); // continued fraction CF2_ik
}
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>()) * boost::math::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

View File

@@ -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_J0_HPP
#define BOOST_MATH_BESSEL_J0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/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

View File

@@ -0,0 +1,157 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_J1_HPP
#define BOOST_MATH_BESSEL_J1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/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

View File

@@ -0,0 +1,91 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_JN_HPP
#define BOOST_MATH_BESSEL_JN_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_j0.hpp>
#include <boost/math/special_functions/detail/bessel_j1.hpp>
#include <boost/math/special_functions/detail/bessel_jy.hpp>
// 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

View File

@@ -0,0 +1,366 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_JY_HPP
#define BOOST_MATH_BESSEL_JY_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/gamma.hpp>
#include <boost/math/special_functions/sign.hpp>
#include <boost/math/special_functions/hypot.hpp>
#include <boost/math/special_functions/sin_pi.hpp>
#include <boost/math/special_functions/cos_pi.hpp>
#include <boost/math/special_functions/detail/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 = boost::math::tgamma1pm1(v, pol);
T gm = boost::math::tgamma1pm1(-v, pol);
T spv = boost::math::sin_pi(v, pol);
T spv2 = boost::math::sin_pi(v/2, pol);
T xp = pow(x/2, v);
a = log(x / 2);
sigma = -a * v;
d = abs(sigma) < tools::epsilon<T>() ?
T(1) : sinh(sigma) / sigma;
e = abs(v) < tools::epsilon<T>() ? 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 = iround(v, pol);
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 = boost::math::cos_pi(z, pol) * Jv - boost::math::sin_pi(z, pol) * Yv; // reflection formula
*Y = boost::math::sin_pi(z, pol) * Jv + boost::math::cos_pi(z, pol) * Yv;
}
else
{
*J = Jv;
*Y = Yv;
}
return 0;
}
} // namespace detail
}} // namespaces
#endif // BOOST_MATH_BESSEL_JY_HPP

View File

@@ -0,0 +1,302 @@
// Copyright (c) 2007 John Maddock
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This is a partial header, do not include on it's own!!!
//
// Contains asymptotic expansions for Bessel J(v,x) and Y(v,x)
// functions, as x -> INF.
//
#ifndef BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
#define BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/factorials.hpp>
namespace boost{ namespace math{ namespace detail{
template <class T>
inline T asymptotic_bessel_j_large_x_P(T v, T x)
{
// A&S 9.2.9
T s = 1;
T mu = 4 * v * v;
T ez2 = 8 * x;
ez2 *= ez2;
s -= (mu-1) * (mu-9) / (2 * ez2);
s += (mu-1) * (mu-9) * (mu-25) * (mu - 49) / (24 * ez2 * ez2);
return s;
}
template <class T>
inline T asymptotic_bessel_j_large_x_Q(T v, T x)
{
// A&S 9.2.10
T s = 0;
T mu = 4 * v * v;
T ez = 8*x;
s += (mu-1) / ez;
s -= (mu-1) * (mu-9) * (mu-25) / (6 * ez*ez*ez);
return s;
}
template <class T>
inline T asymptotic_bessel_j_large_x(T v, T x)
{
//
// See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
//
// Also A&S 9.2.5
//
BOOST_MATH_STD_USING // ADL of std names
T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
return sqrt(2 / (constants::pi<T>() * x))
* (asymptotic_bessel_j_large_x_P(v, x) * cos(chi)
- asymptotic_bessel_j_large_x_Q(v, x) * sin(chi));
}
template <class T>
inline T asymptotic_bessel_y_large_x(T v, T x)
{
//
// See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
//
// Also A&S 9.2.5
//
BOOST_MATH_STD_USING // ADL of std names
T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
return sqrt(2 / (constants::pi<T>() * x))
* (asymptotic_bessel_j_large_x_P(v, x) * sin(chi)
- asymptotic_bessel_j_large_x_Q(v, x) * cos(chi));
}
template <class T>
inline T asymptotic_bessel_amplitude(T v, T x)
{
// Calculate the amplitude of J(v, x) and Y(v, x) for large
// x: see A&S 9.2.28.
BOOST_MATH_STD_USING
T s = 1;
T mu = 4 * v * v;
T txq = 2 * x;
txq *= txq;
s += (mu - 1) / (2 * txq);
s += 3 * (mu - 1) * (mu - 9) / (txq * txq * 8);
s += 15 * (mu - 1) * (mu - 9) * (mu - 25) / (txq * txq * txq * 8 * 6);
return sqrt(s * 2 / (constants::pi<T>() * x));
}
template <class T>
T asymptotic_bessel_phase_mx(T v, T x)
{
//
// Calculate the phase of J(v, x) and Y(v, x) for large x.
// See A&S 9.2.29.
// Note that the result returned is the phase less x.
//
T mu = 4 * v * v;
T denom = 4 * x;
T denom_mult = denom * denom;
T s = -constants::pi<T>() * (v / 2 + 0.25f);
s += (mu - 1) / (2 * denom);
denom *= denom_mult;
s += (mu - 1) * (mu - 25) / (6 * denom);
denom *= denom_mult;
s += (mu - 1) * (mu * mu - 114 * mu + 1073) / (5 * denom);
denom *= denom_mult;
s += (mu - 1) * (5 * mu * mu * mu - 1535 * mu * mu + 54703 * mu - 375733) / (14 * denom);
return s;
}
template <class T>
inline T asymptotic_bessel_y_large_x_2(T v, T x)
{
// See A&S 9.2.19.
BOOST_MATH_STD_USING
// Get the phase and amplitude:
T ampl = asymptotic_bessel_amplitude(v, x);
T phase = asymptotic_bessel_phase_mx(v, x);
//
// 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 / boost::math::sin_pi(v, pol)) * pow(x / 2, -v) / boost::math::tgamma(1 - v, pol);
T q = (v / boost::math::sin_pi(v, pol)) * pow(x / 2, v) / boost::math::tgamma(1 + v, pol);
T f = (p - q) / v;
T g_prefix = boost::math::sin_pi(v / 2, pol);
g_prefix *= g_prefix * 2 / v;
T g = f + g_prefix * q;
T h = p;
T c_mult = -x * x / 4;
T y(c * g), y1(c * h);
for(int k = 1; k < policies::get_max_series_iterations<Policy>(); ++k)
{
f = (k * f + p + q) / (k*k - v*v);
p /= k - v;
q /= k + v;
c *= c_mult / k;
T c1 = pow(-x * x / 4, k) / factorial<T>(k, pol);
g = f + g_prefix * q;
h = -k * g + p;
y += c * g;
y1 += c * h;
if(c * g / tools::epsilon<T>() < y)
break;
}
*Y = -y;
*Y1 = (-2 / x) * y1;
}
template <class T, class Policy>
T asymptotic_bessel_i_large_x(T v, T x, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
T s = 1;
T mu = 4 * v * v;
T ex = 8 * x;
T num = mu - 1;
T denom = ex;
s -= num / denom;
num *= mu - 9;
denom *= ex * 2;
s += num / denom;
num *= mu - 25;
denom *= ex * 3;
s -= num / denom;
// Try and avoid overflow to the last minute:
T e = exp(x/2);
s = e * (e * s / sqrt(2 * x * constants::pi<T>()));
return (boost::math::isfinite)(s) ?
s : policies::raise_overflow_error<T>("boost::math::asymptotic_bessel_i_large_x<%1%>(%1%,%1%)", 0, pol);
}
}}} // namespaces
#endif

View File

@@ -0,0 +1,121 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_K0_HPP
#define BOOST_MATH_BESSEL_K0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/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

View File

@@ -0,0 +1,117 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_K1_HPP
#define BOOST_MATH_BESSEL_K1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/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

View File

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

View File

@@ -0,0 +1,182 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_Y0_HPP
#define BOOST_MATH_BESSEL_Y0_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_j0.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/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

View File

@@ -0,0 +1,155 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_Y1_HPP
#define BOOST_MATH_BESSEL_Y1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_j1.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/tools/rational.hpp>
#include <boost/math/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

View File

@@ -0,0 +1,84 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_BESSEL_YN_HPP
#define BOOST_MATH_BESSEL_YN_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/detail/bessel_y0.hpp>
#include <boost/math/special_functions/detail/bessel_y1.hpp>
#include <boost/math/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

View File

@@ -0,0 +1,469 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SF_ERF_INV_HPP
#define BOOST_MATH_SF_ERF_INV_HPP
#ifdef _MSC_VER
#pragma once
#endif
namespace boost{ namespace math{
namespace detail{
//
// The inverse erf and erfc functions share a common implementation,
// this version is for 80-bit long double's and smaller:
//
template <class T, class Policy>
T erf_inv_imp(const T& p, const T& q, const Policy&, const boost::mpl::int_<64>*)
{
BOOST_MATH_STD_USING // for ADL of std names.
T result = 0;
if(p <= 0.5)
{
//
// Evaluate inverse erf using the rational approximation:
//
// x = p(p+10)(Y+R(p))
//
// Where Y is a constant, and R(p) is optimised for a low
// absolute error compared to |Y|.
//
// double: Max error found: 2.001849e-18
// long double: Max error found: 1.017064e-20
// Maximum Deviation Found (actual error term at infinite precision) 8.030e-21
//
static const float Y = 0.0891314744949340820313f;
static const T P[] = {
-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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,939 @@
// Copyright John Maddock 2006.
// Copyright Paul A. Bristow 2007
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
#define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/beta.hpp>
#include <boost/math/special_functions/erf.hpp>
#include <boost/math/tools/roots.hpp>
#include <boost/math/special_functions/detail/t_distribution_inv.hpp>
namespace boost{ namespace math{ namespace detail{
//
// Helper object used by root finding
// code to convert eta to x.
//
template <class T>
struct temme_root_finder
{
temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {}
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) co12[] = { 1, -13, 13 };
workspace[3] = tools::evaluate_polynomial(co12, workspace[0], 3) / (36 * s * c);
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co13[] = { 1, 21, -69, 46 };
workspace[4] = tools::evaluate_polynomial(co13, workspace[0], 4) / (270 * workspace[0] * c * c);
x = tools::evaluate_polynomial(workspace, eta, 5);
#ifdef BOOST_INSTRUMENT
std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl;
#endif
}
else
{
//
// If eta is large we need to solve Eq 3.2 more directly,
// begin by getting an initial approximation for x from
// the last equation on page 155, this is a polynomial in u:
//
T u = exp(lu);
workspace[0] = u;
workspace[1] = alpha;
workspace[2] = 0;
workspace[3] = 3 * alpha * (3 * alpha + 1) / 6;
workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24;
workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120;
x = tools::evaluate_polynomial(workspace, u, 6);
//
// At this point we may or may not have the right answer, Eq-3.2 has
// two solutions for x for any given eta, however the mapping in 3.2
// is 1:1 with the sign of eta and x-sin^2(theta) being the same.
// So we can check if we have the right root of 3.2, and if not
// switch x for 1-x. This transformation is motivated by the fact
// that the distribution is *almost* symetric so 1-x will be in the right
// ball park for the solution:
//
if((x - s_2) * eta < 0)
x = 1 - x;
#ifdef BOOST_INSTRUMENT
std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl;
#endif
}
//
// The final step is a few Newton-Raphson iterations to
// clean up our approximation for x, this is pretty cheap
// in general, and very cheap compared to an incomplete beta
// evaluation. The limits set on x come from the observation
// that the sign of eta and x-sin^2(theta) are the same.
//
T lower, upper;
if(eta < 0)
{
lower = 0;
upper = s_2;
}
else
{
lower = s_2;
upper = 1;
}
//
// If our initial approximation is out of bounds then bisect:
//
if((x < lower) || (x > upper))
x = (lower+upper) / 2;
//
// And iterate:
//
x = tools::newton_raphson_iterate(
temme_root_finder<T>(-lu, alpha), x, lower, upper, policies::digits<T, Policy>() / 2);
return x;
}
//
// See:
// "Asymptotic Inversion of the Incomplete Beta Function"
// N.M. Temme
// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
// Section 4.
//
template <class T, class Policy>
T temme_method_3_ibeta_inverse(T a, T b, T p, T q, const Policy& pol)
{
BOOST_MATH_STD_USING // ADL of std names
//
// Begin by getting an initial approximation for the quantity
// eta from the dominant part of the incomplete beta:
//
T eta0;
if(p < q)
eta0 = boost::math::gamma_q_inv(b, p, pol);
else
eta0 = boost::math::gamma_p_inv(b, q, pol);
eta0 /= a;
//
// Define the variables and powers we'll need later on:
//
T mu = b / a;
T w = sqrt(1 + mu);
T w_2 = w * w;
T w_3 = w_2 * w;
T w_4 = w_2 * w_2;
T w_5 = w_3 * w_2;
T w_6 = w_3 * w_3;
T w_7 = w_4 * w_3;
T w_8 = w_4 * w_4;
T w_9 = w_5 * w_4;
T w_10 = w_5 * w_5;
T d = eta0 - mu;
T d_2 = d * d;
T d_3 = d_2 * d;
T d_4 = d_2 * d_2;
T w1 = w + 1;
T w1_2 = w1 * w1;
T w1_3 = w1 * w1_2;
T w1_4 = w1_2 * w1_2;
//
// Now we need to compute the purturbation error terms that
// convert eta0 to eta, these are all polynomials of polynomials.
// Probably these should be re-written to use tabulated data
// (see examples above), but it's less of a win in this case as we
// need to calculate the individual powers for the denominator terms
// anyway, so we might as well use them for the numerator-polynomials
// as well....
//
// Refer to p154-p155 for the details of these expansions:
//
T e1 = (w + 2) * (w - 1) / (3 * w);
e1 += (w_3 + 9 * w_2 + 21 * w + 5) * d / (36 * w_2 * w1);
e1 -= (w_4 - 13 * w_3 + 69 * w_2 + 167 * w + 46) * d_2 / (1620 * w1_2 * w_3);
e1 -= (7 * w_5 + 21 * w_4 + 70 * w_3 + 26 * w_2 - 93 * w - 31) * d_3 / (6480 * w1_3 * w_4);
e1 -= (75 * w_6 + 202 * w_5 + 188 * w_4 - 888 * w_3 - 1345 * w_2 + 118 * w + 138) * d_4 / (272160 * w1_4 * w_5);
T e2 = (28 * w_4 + 131 * w_3 + 402 * w_2 + 581 * w + 208) * (w - 1) / (1620 * w1 * w_3);
e2 -= (35 * w_6 - 154 * w_5 - 623 * w_4 - 1636 * w_3 - 3983 * w_2 - 3514 * w - 925) * d / (12960 * w1_2 * w_4);
e2 -= (2132 * w_7 + 7915 * w_6 + 16821 * w_5 + 35066 * w_4 + 87490 * w_3 + 141183 * w_2 + 95993 * w + 21640) * d_2 / (816480 * w_5 * w1_3);
e2 -= (11053 * w_8 + 53308 * w_7 + 117010 * w_6 + 163924 * w_5 + 116188 * w_4 - 258428 * w_3 - 677042 * w_2 - 481940 * w - 105497) * d_3 / (14696640 * w1_4 * w_6);
T e3 = -((3592 * w_7 + 8375 * w_6 - 1323 * w_5 - 29198 * w_4 - 89578 * w_3 - 154413 * w_2 - 116063 * w - 29632) * (w - 1)) / (816480 * w_5 * w1_2);
e3 -= (442043 * w_9 + 2054169 * w_8 + 3803094 * w_7 + 3470754 * w_6 + 2141568 * w_5 - 2393568 * w_4 - 19904934 * w_3 - 34714674 * w_2 - 23128299 * w - 5253353) * d / (146966400 * w_6 * w1_3);
e3 -= (116932 * w_10 + 819281 * w_9 + 2378172 * w_8 + 4341330 * w_7 + 6806004 * w_6 + 10622748 * w_5 + 18739500 * w_4 + 30651894 * w_3 + 30869976 * w_2 + 15431867 * w + 2919016) * d_2 / (146966400 * w1_4 * w_7);
//
// Combine eta0 and the error terms to compute eta (Second eqaution p155):
//
T eta = eta0 + e1 / a + e2 / (a * a) + e3 / (a * a * a);
//
// Now we need to solve Eq 4.2 to obtain x. For any given value of
// eta there are two solutions to this equation, and since the distribtion
// may be very skewed, these are not related by x ~ 1-x we used when
// implementing section 3 above. However we know that:
//
// cross < x <= 1 ; iff eta < mu
// x == cross ; iff eta == mu
// 0 <= x < cross ; iff eta > mu
//
// Where cross == 1 / (1 + mu)
// Many thanks to Prof Temme for clarifying this point.
//
// Therefore we'll just jump straight into Newton iterations
// to solve Eq 4.2 using these bounds, and simple bisection
// as the first guess, in practice this converges pretty quickly
// and we only need a few digits correct anyway:
//
if(eta <= 0)
eta = tools::min_value<T>();
T u = eta - mu * log(eta) + (1 + mu) * log(1 + mu) - mu;
T cross = 1 / (1 + mu);
T lower = eta < mu ? cross : 0;
T upper = eta < mu ? 1 : cross;
T x = (lower + upper) / 2;
x = tools::newton_raphson_iterate(
temme_root_finder<T>(u, mu), x, lower, upper, policies::digits<T, Policy>() / 2);
#ifdef BOOST_INSTRUMENT
std::cout << "Estimating x with Temme method 3: " << x << std::endl;
#endif
return x;
}
template <class T, class Policy>
struct ibeta_roots
{
ibeta_roots(T _a, T _b, T t, bool inv = false)
: a(_a), b(_b), target(t), invert(inv) {}
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)
{
typedef typename remove_cv<RT1>::type dummy;
return ibetac_inv(a, b, q, static_cast<dummy*>(0), policies::policy<>());
}
template <class RT1, class RT2, class RT3, class Policy>
inline typename tools::promote_args<RT1, RT2, RT3>::type
ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy& pol)
{
typedef typename remove_cv<RT1>::type dummy;
return ibetac_inv(a, b, q, static_cast<dummy*>(0), pol);
}
} // namespace math
} // namespace boost
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP

View File

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

View File

@@ -0,0 +1,769 @@
// Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This file implements the asymptotic expansions of the incomplete
// gamma functions P(a, x) and Q(a, x), used when a is large and
// x ~ a.
//
// The primary reference is:
//
// "The Asymptotic Expansion of the Incomplete Gamma Functions"
// N. M. Temme.
// Siam J. Math Anal. Vol 10 No 4, July 1979, p757.
//
// A different way of evaluating these expansions,
// plus a lot of very useful background information is in:
//
// "A Set of Algorithms For the Incomplete Gamma Functions."
// N. M. Temme.
// Probability in the Engineering and Informational Sciences,
// 8, 1994, 291.
//
// An alternative implementation is in:
//
// "Computation of the Incomplete Gamma Function Ratios and their Inverse."
// A. R. Didonato and A. H. Morris.
// ACM TOMS, Vol 12, No 4, Dec 1986, p377.
//
// There are various versions of the same code below, each accurate
// to a different precision. To understand the code, refer to Didonato
// and Morris, from Eq 17 and 18 onwards.
//
// The coefficients used here are not taken from Didonato and Morris:
// the domain over which these expansions are used is slightly different
// to theirs, and their constants are not quite accurate enough for
// 128-bit long double's. Instead the coefficients were calculated
// using the methods described by Temme p762 from Eq 3.8 onwards.
// The values obtained agree with those obtained by Didonato and Morris
// (at least to the first 30 digits that they provide).
// At double precision the degrees of polynomial required for full
// machine precision are close to those recomended to Didonato and Morris,
// but of course many more terms are needed for larger types.
//
#ifndef BOOST_MATH_DETAIL_IGAMMA_LARGE
#define BOOST_MATH_DETAIL_IGAMMA_LARGE
#ifdef _MSC_VER
#pragma once
#endif
namespace boost{ namespace math{ namespace detail{
// This version will never be called (at runtime), it's a stub used
// when T is unsuitable to be passed to these routines:
//
template <class T, class Policy>
inline T igamma_temme_large(T, T, const Policy& /* pol */, mpl::int_<0> const *)
{
// stub function, should never actually be called
BOOST_ASSERT(0);
return 0;
}
//
// This version is accurate for up to 64-bit mantissa's,
// (80-bit long double, or 10^-20).
//
template <class T, class Policy>
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<64> const *)
{
BOOST_MATH_STD_USING // ADL of std functions
T sigma = (x - a) / a;
T phi = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[13];
static const T C0[] = {
-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 = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[10];
static const T C0[] = {
static_cast<T>(-0.33333333333333333L),
static_cast<T>(0.083333333333333333L),
static_cast<T>(-0.014814814814814815L),
static_cast<T>(0.0011574074074074074L),
static_cast<T>(0.0003527336860670194L),
static_cast<T>(-0.00017875514403292181L),
static_cast<T>(0.39192631785224378e-4L),
static_cast<T>(-0.21854485106799922e-5L),
static_cast<T>(-0.185406221071516e-5L),
static_cast<T>(0.8296711340953086e-6L),
static_cast<T>(-0.17665952736826079e-6L),
static_cast<T>(0.67078535434014986e-8L),
static_cast<T>(0.10261809784240308e-7L),
static_cast<T>(-0.43820360184533532e-8L),
static_cast<T>(0.91476995822367902e-9L),
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
static_cast<T>(-0.0018518518518518519L),
static_cast<T>(-0.0034722222222222222L),
static_cast<T>(0.0026455026455026455L),
static_cast<T>(-0.00099022633744855967L),
static_cast<T>(0.00020576131687242798L),
static_cast<T>(-0.40187757201646091e-6L),
static_cast<T>(-0.18098550334489978e-4L),
static_cast<T>(0.76491609160811101e-5L),
static_cast<T>(-0.16120900894563446e-5L),
static_cast<T>(0.46471278028074343e-8L),
static_cast<T>(0.1378633446915721e-6L),
static_cast<T>(-0.5752545603517705e-7L),
static_cast<T>(0.11951628599778147e-7L),
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
static_cast<T>(0.0041335978835978836L),
static_cast<T>(-0.0026813271604938272L),
static_cast<T>(0.00077160493827160494L),
static_cast<T>(0.20093878600823045e-5L),
static_cast<T>(-0.00010736653226365161L),
static_cast<T>(0.52923448829120125e-4L),
static_cast<T>(-0.12760635188618728e-4L),
static_cast<T>(0.34235787340961381e-7L),
static_cast<T>(0.13721957309062933e-5L),
static_cast<T>(-0.6298992138380055e-6L),
static_cast<T>(0.14280614206064242e-6L),
};
workspace[2] = tools::evaluate_polynomial(C2, z);
static const T C3[] = {
static_cast<T>(0.00064943415637860082L),
static_cast<T>(0.00022947209362139918L),
static_cast<T>(-0.00046918949439525571L),
static_cast<T>(0.00026772063206283885L),
static_cast<T>(-0.75618016718839764e-4L),
static_cast<T>(-0.23965051138672967e-6L),
static_cast<T>(0.11082654115347302e-4L),
static_cast<T>(-0.56749528269915966e-5L),
static_cast<T>(0.14230900732435884e-5L),
};
workspace[3] = tools::evaluate_polynomial(C3, z);
static const T C4[] = {
static_cast<T>(-0.0008618882909167117L),
static_cast<T>(0.00078403922172006663L),
static_cast<T>(-0.00029907248030319018L),
static_cast<T>(-0.14638452578843418e-5L),
static_cast<T>(0.66414982154651222e-4L),
static_cast<T>(-0.39683650471794347e-4L),
static_cast<T>(0.11375726970678419e-4L),
};
workspace[4] = tools::evaluate_polynomial(C4, z);
static const T C5[] = {
static_cast<T>(-0.00033679855336635815L),
static_cast<T>(-0.69728137583658578e-4L),
static_cast<T>(0.00027727532449593921L),
static_cast<T>(-0.00019932570516188848L),
static_cast<T>(0.67977804779372078e-4L),
static_cast<T>(0.1419062920643967e-6L),
static_cast<T>(-0.13594048189768693e-4L),
static_cast<T>(0.80184702563342015e-5L),
static_cast<T>(-0.22914811765080952e-5L),
};
workspace[5] = tools::evaluate_polynomial(C5, z);
static const T C6[] = {
static_cast<T>(0.00053130793646399222L),
static_cast<T>(-0.00059216643735369388L),
static_cast<T>(0.00027087820967180448L),
static_cast<T>(0.79023532326603279e-6L),
static_cast<T>(-0.81539693675619688e-4L),
static_cast<T>(0.56116827531062497e-4L),
static_cast<T>(-0.18329116582843376e-4L),
};
workspace[6] = tools::evaluate_polynomial(C6, z);
static const T C7[] = {
static_cast<T>(0.00034436760689237767L),
static_cast<T>(0.51717909082605922e-4L),
static_cast<T>(-0.00033493161081142236L),
static_cast<T>(0.0002812695154763237L),
static_cast<T>(-0.00010976582244684731L),
};
workspace[7] = tools::evaluate_polynomial(C7, z);
static const T C8[] = {
static_cast<T>(-0.00065262391859530942L),
static_cast<T>(0.00083949872067208728L),
static_cast<T>(-0.00043829709854172101L),
};
workspace[8] = tools::evaluate_polynomial(C8, z);
workspace[9] = static_cast<T>(-0.00059676129019274625L);
T result = tools::evaluate_polynomial(workspace, 1/a);
result *= exp(-y) / sqrt(2 * constants::pi<T>() * a);
if(x < a)
result = -result;
result += boost::math::erfc(sqrt(y), pol) / 2;
return result;
}
//
// This one is accurate for 24-bit mantissa's
// (IEEE float precision, or 10^-8)
//
template <class T, class Policy>
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<24> const *)
{
BOOST_MATH_STD_USING // ADL of std functions
T sigma = (x - a) / a;
T phi = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[3];
static const T C0[] = {
static_cast<T>(-0.333333333L),
static_cast<T>(0.0833333333L),
static_cast<T>(-0.0148148148L),
static_cast<T>(0.00115740741L),
static_cast<T>(0.000352733686L),
static_cast<T>(-0.000178755144L),
static_cast<T>(0.391926318e-4L),
};
workspace[0] = tools::evaluate_polynomial(C0, z);
static const T C1[] = {
static_cast<T>(-0.00185185185L),
static_cast<T>(-0.00347222222L),
static_cast<T>(0.00264550265L),
static_cast<T>(-0.000990226337L),
static_cast<T>(0.000205761317L),
};
workspace[1] = tools::evaluate_polynomial(C1, z);
static const T C2[] = {
static_cast<T>(0.00413359788L),
static_cast<T>(-0.00268132716L),
static_cast<T>(0.000771604938L),
};
workspace[2] = tools::evaluate_polynomial(C2, z);
T result = tools::evaluate_polynomial(workspace, 1/a);
result *= exp(-y) / sqrt(2 * constants::pi<T>() * a);
if(x < a)
result = -result;
result += boost::math::erfc(sqrt(y), pol) / 2;
return result;
}
//
// And finally, a version for 113-bit mantissa's
// (128-bit long doubles, or 10^-34).
// Note this one has been optimised for a > 200
// It's use for a < 200 is not recomended, that would
// require many more terms in the polynomials.
//
template <class T, class Policy>
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<113> const *)
{
BOOST_MATH_STD_USING // ADL of std functions
T sigma = (x - a) / a;
T phi = -boost::math::log1pmx(sigma, pol);
T y = a * phi;
T z = sqrt(2 * phi);
if(x < a)
z = -z;
T workspace[14];
static const T C0[] = {
-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

View File

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

View File

@@ -0,0 +1,512 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
#define BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
#ifdef _MSC_VER
#pragma once
#endif
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

View File

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

View File

@@ -0,0 +1,172 @@
// 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
#ifdef _MSC_VER
#pragma once
#endif
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

View File

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

View File

@@ -0,0 +1,402 @@
// Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SP_UC_FACTORIALS_HPP
#define BOOST_MATH_SP_UC_FACTORIALS_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/array.hpp>
#ifdef BOOST_MSVC
#pragma warning(push) // Temporary until lexical cast fixed.
#pragma warning(disable: 4127 4701)
#endif
#include <boost/lexical_cast.hpp>
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <boost/config/no_tr1/cmath.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
namespace boost { namespace math
{
// Forward declarations:
template <class T>
struct max_factorial;
// efinitions:
template <>
inline float unchecked_factorial<float>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(float))
{
static const boost::array<float, 35> factorials = {{
1.0F,
1.0F,
2.0F,
6.0F,
24.0F,
120.0F,
720.0F,
5040.0F,
40320.0F,
362880.0F,
3628800.0F,
39916800.0F,
479001600.0F,
6227020800.0F,
87178291200.0F,
1307674368000.0F,
20922789888000.0F,
355687428096000.0F,
6402373705728000.0F,
121645100408832000.0F,
0.243290200817664e19F,
0.5109094217170944e20F,
0.112400072777760768e22F,
0.2585201673888497664e23F,
0.62044840173323943936e24F,
0.15511210043330985984e26F,
0.403291461126605635584e27F,
0.10888869450418352160768e29F,
0.304888344611713860501504e30F,
0.8841761993739701954543616e31F,
0.26525285981219105863630848e33F,
0.822283865417792281772556288e34F,
0.26313083693369353016721801216e36F,
0.868331761881188649551819440128e37F,
0.29523279903960414084761860964352e39F,
}};
return factorials[i];
}
template <>
struct max_factorial<float>
{
BOOST_STATIC_CONSTANT(unsigned, value = 34);
};
template <>
inline long double unchecked_factorial<long double>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(long double))
{
static const boost::array<long double, 171> factorials = {{
1L,
1L,
2L,
6L,
24L,
120L,
720L,
5040L,
40320L,
362880.0L,
3628800.0L,
39916800.0L,
479001600.0L,
6227020800.0L,
87178291200.0L,
1307674368000.0L,
20922789888000.0L,
355687428096000.0L,
6402373705728000.0L,
121645100408832000.0L,
0.243290200817664e19L,
0.5109094217170944e20L,
0.112400072777760768e22L,
0.2585201673888497664e23L,
0.62044840173323943936e24L,
0.15511210043330985984e26L,
0.403291461126605635584e27L,
0.10888869450418352160768e29L,
0.304888344611713860501504e30L,
0.8841761993739701954543616e31L,
0.26525285981219105863630848e33L,
0.822283865417792281772556288e34L,
0.26313083693369353016721801216e36L,
0.868331761881188649551819440128e37L,
0.29523279903960414084761860964352e39L,
0.103331479663861449296666513375232e41L,
0.3719933267899012174679994481508352e42L,
0.137637530912263450463159795815809024e44L,
0.5230226174666011117600072241000742912e45L,
0.203978820811974433586402817399028973568e47L,
0.815915283247897734345611269596115894272e48L,
0.3345252661316380710817006205344075166515e50L,
0.1405006117752879898543142606244511569936e52L,
0.6041526306337383563735513206851399750726e53L,
0.265827157478844876804362581101461589032e55L,
0.1196222208654801945619631614956577150644e57L,
0.5502622159812088949850305428800254892962e58L,
0.2586232415111681806429643551536119799692e60L,
0.1241391559253607267086228904737337503852e62L,
0.6082818640342675608722521633212953768876e63L,
0.3041409320171337804361260816606476884438e65L,
0.1551118753287382280224243016469303211063e67L,
0.8065817517094387857166063685640376697529e68L,
0.427488328406002556429801375338939964969e70L,
0.2308436973392413804720927426830275810833e72L,
0.1269640335365827592596510084756651695958e74L,
0.7109985878048634518540456474637249497365e75L,
0.4052691950487721675568060190543232213498e77L,
0.2350561331282878571829474910515074683829e79L,
0.1386831185456898357379390197203894063459e81L,
0.8320987112741390144276341183223364380754e82L,
0.507580213877224798800856812176625227226e84L,
0.3146997326038793752565312235495076408801e86L,
0.1982608315404440064116146708361898137545e88L,
0.1268869321858841641034333893351614808029e90L,
0.8247650592082470666723170306785496252186e91L,
0.5443449390774430640037292402478427526443e93L,
0.3647111091818868528824985909660546442717e95L,
0.2480035542436830599600990418569171581047e97L,
0.1711224524281413113724683388812728390923e99L,
0.1197857166996989179607278372168909873646e101L,
0.8504785885678623175211676442399260102886e102L,
0.6123445837688608686152407038527467274078e104L,
0.4470115461512684340891257138125051110077e106L,
0.3307885441519386412259530282212537821457e108L,
0.2480914081139539809194647711659403366093e110L,
0.188549470166605025498793226086114655823e112L,
0.1451830920282858696340707840863082849837e114L,
0.1132428117820629783145752115873204622873e116L,
0.8946182130782975286851441715398316520698e117L,
0.7156945704626380229481153372318653216558e119L,
0.5797126020747367985879734231578109105412e121L,
0.4753643337012841748421382069894049466438e123L,
0.3945523969720658651189747118012061057144e125L,
0.3314240134565353266999387579130131288001e127L,
0.2817104114380550276949479442260611594801e129L,
0.2422709538367273238176552320344125971528e131L,
0.210775729837952771721360051869938959523e133L,
0.1854826422573984391147968456455462843802e135L,
0.1650795516090846108121691926245361930984e137L,
0.1485715964481761497309522733620825737886e139L,
0.1352001527678402962551665687594951421476e141L,
0.1243841405464130725547532432587355307758e143L,
0.1156772507081641574759205162306240436215e145L,
0.1087366156656743080273652852567866010042e147L,
0.103299784882390592625997020993947270954e149L,
0.9916779348709496892095714015418938011582e150L,
0.9619275968248211985332842594956369871234e152L,
0.942689044888324774562618574305724247381e154L,
0.9332621544394415268169923885626670049072e156L,
0.9332621544394415268169923885626670049072e158L,
0.9425947759838359420851623124482936749562e160L,
0.9614466715035126609268655586972595484554e162L,
0.990290071648618040754671525458177334909e164L,
0.1029901674514562762384858386476504428305e167L,
0.1081396758240290900504101305800329649721e169L,
0.1146280563734708354534347384148349428704e171L,
0.1226520203196137939351751701038733888713e173L,
0.132464181945182897449989183712183259981e175L,
0.1443859583202493582204882102462797533793e177L,
0.1588245541522742940425370312709077287172e179L,
0.1762952551090244663872161047107075788761e181L,
0.1974506857221074023536820372759924883413e183L,
0.2231192748659813646596607021218715118256e185L,
0.2543559733472187557120132004189335234812e187L,
0.2925093693493015690688151804817735520034e189L,
0.339310868445189820119825609358857320324e191L,
0.396993716080872089540195962949863064779e193L,
0.4684525849754290656574312362808384164393e195L,
0.5574585761207605881323431711741977155627e197L,
0.6689502913449127057588118054090372586753e199L,
0.8094298525273443739681622845449350829971e201L,
0.9875044200833601362411579871448208012564e203L,
0.1214630436702532967576624324188129585545e206L,
0.1506141741511140879795014161993280686076e208L,
0.1882677176888926099743767702491600857595e210L,
0.237217324288004688567714730513941708057e212L,
0.3012660018457659544809977077527059692324e214L,
0.3856204823625804217356770659234636406175e216L,
0.4974504222477287440390234150412680963966e218L,
0.6466855489220473672507304395536485253155e220L,
0.8471580690878820510984568758152795681634e222L,
0.1118248651196004307449963076076169029976e225L,
0.1487270706090685728908450891181304809868e227L,
0.1992942746161518876737324194182948445223e229L,
0.269047270731805048359538766214698040105e231L,
0.3659042881952548657689727220519893345429e233L,
0.5012888748274991661034926292112253883237e235L,
0.6917786472619488492228198283114910358867e237L,
0.9615723196941089004197195613529725398826e239L,
0.1346201247571752460587607385894161555836e242L,
0.1898143759076170969428526414110767793728e244L,
0.2695364137888162776588507508037290267094e246L,
0.3854370717180072770521565736493325081944e248L,
0.5550293832739304789551054660550388118e250L,
0.80479260574719919448490292577980627711e252L,
0.1174997204390910823947958271638517164581e255L,
0.1727245890454638911203498659308620231933e257L,
0.2556323917872865588581178015776757943262e259L,
0.380892263763056972698595524350736933546e261L,
0.571338395644585459047893286526105400319e263L,
0.8627209774233240431623188626544191544816e265L,
0.1311335885683452545606724671234717114812e268L,
0.2006343905095682394778288746989117185662e270L,
0.308976961384735088795856467036324046592e272L,
0.4789142901463393876335775239063022722176e274L,
0.7471062926282894447083809372938315446595e276L,
0.1172956879426414428192158071551315525115e279L,
0.1853271869493734796543609753051078529682e281L,
0.2946702272495038326504339507351214862195e283L,
0.4714723635992061322406943211761943779512e285L,
0.7590705053947218729075178570936729485014e287L,
0.1229694218739449434110178928491750176572e290L,
0.2004401576545302577599591653441552787813e292L,
0.3287218585534296227263330311644146572013e294L,
0.5423910666131588774984495014212841843822e296L,
0.9003691705778437366474261723593317460744e298L,
0.1503616514864999040201201707840084015944e301L,
0.2526075744973198387538018869171341146786e303L,
0.4269068009004705274939251888899566538069e305L,
0.7257415615307998967396728211129263114717e307L,
}};
return factorials[i];
}
template <>
struct max_factorial<long double>
{
BOOST_STATIC_CONSTANT(unsigned, value = 170);
};
template <>
inline double unchecked_factorial<double>(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(double))
{
return static_cast<double>(boost::math::unchecked_factorial<long double>(i));
}
template <>
struct max_factorial<double>
{
BOOST_STATIC_CONSTANT(unsigned,
value = ::boost::math::max_factorial<long double>::value);
};
template <class T>
inline T unchecked_factorial(unsigned i BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(T))
{
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

View File

@@ -0,0 +1,450 @@
// (C) Copyright John Maddock 2006.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_MATH_SF_DIGAMMA_HPP
#define BOOST_MATH_SF_DIGAMMA_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/tools/rational.hpp>
#include <boost/math/tools/promotion.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/mpl/comparison.hpp>
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

View File

@@ -0,0 +1,187 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2006 John Maddock
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to ensure
// that the code continues to work no matter how many digits
// type T has.
#ifndef BOOST_MATH_ELLINT_1_HPP
#define BOOST_MATH_ELLINT_1_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integrals (complete and incomplete) of the first kind
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math {
template <class T1, class T2, class Policy>
typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const Policy& pol);
namespace detail{
template <typename T, typename Policy>
T ellint_k_imp(T k, const Policy& pol);
// Elliptic integral (Legendre form) of the first kind
template <typename T, typename Policy>
T ellint_f_imp(T phi, T k, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
static const char* function = "boost::math::ellint_f<%1%>(%1%,%1%)";
BOOST_MATH_INSTRUMENT_VARIABLE(phi);
BOOST_MATH_INSTRUMENT_VARIABLE(k);
BOOST_MATH_INSTRUMENT_VARIABLE(function);
if (abs(k) > 1)
{
return policies::raise_domain_error<T>(function,
"Got k = %1%, function requires |k| <= 1", k, pol);
}
bool invert = false;
if(phi < 0)
{
BOOST_MATH_INSTRUMENT_VARIABLE(phi);
phi = fabs(phi);
invert = true;
}
T result;
if(phi >= tools::max_value<T>())
{
// Need to handle infinity as a special case:
result = policies::raise_overflow_error<T>(function, 0, pol);
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else if(phi > 1 / tools::epsilon<T>())
{
// Phi is so large that phi%pi is necessarily zero (or garbage),
// just return the second part of the duplication formula:
result = 2 * phi * ellint_k_imp(k, pol) / constants::pi<T>();
BOOST_MATH_INSTRUMENT_VARIABLE(result);
}
else
{
// Carlson's algorithm works only for |phi| <= pi/2,
// use the integrand's periodicity to normalize phi
//
// Xiaogang's original code used a cast to long long here
// but that fails if T has more digits than a long long,
// so rewritten to use fmod instead:
//
BOOST_MATH_INSTRUMENT_CODE("pi/2 = " << constants::pi<T>() / 2);
T rphi = boost::math::tools::fmod_workaround(phi, constants::pi<T>() / 2);
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
T m = floor((2 * phi) / constants::pi<T>());
BOOST_MATH_INSTRUMENT_VARIABLE(m);
int s = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
s = -1;
rphi = constants::pi<T>() / 2 - rphi;
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
}
T sinp = sin(rphi);
T cosp = cos(rphi);
BOOST_MATH_INSTRUMENT_VARIABLE(sinp);
BOOST_MATH_INSTRUMENT_VARIABLE(cosp);
result = s * sinp * ellint_rf_imp(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

View File

@@ -0,0 +1,168 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2006 John Maddock
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to ensure
// that the code continues to work no matter how many digits
// type T has.
#ifndef BOOST_MATH_ELLINT_2_HPP
#define BOOST_MATH_ELLINT_2_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/ellint_rd.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integrals (complete and incomplete) of the second kind
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math {
template <class T1, class T2, class Policy>
typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol);
namespace detail{
template <typename T, typename Policy>
T ellint_e_imp(T k, const Policy& pol);
// Elliptic integral (Legendre form) of the second kind
template <typename T, typename Policy>
T ellint_e_imp(T phi, T k, const Policy& pol)
{
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
bool invert = false;
if(phi < 0)
{
phi = fabs(phi);
invert = true;
}
T result;
if(phi >= tools::max_value<T>())
{
// Need to handle infinity as a special case:
result = policies::raise_overflow_error<T>("boost::math::ellint_e<%1%>(%1%,%1%)", 0, pol);
}
else if(phi > 1 / tools::epsilon<T>())
{
// Phi is so large that phi%pi is necessarily zero (or garbage),
// just return the second part of the duplication formula:
result = 2 * phi * ellint_e_imp(k, pol) / constants::pi<T>();
}
else
{
// Carlson's algorithm works only for |phi| <= pi/2,
// use the integrand's periodicity to normalize phi
//
// Xiaogang's original code used a cast to long long here
// but that fails if T has more digits than a long long,
// so rewritten to use fmod instead:
//
T rphi = boost::math::tools::fmod_workaround(phi, constants::pi<T>() / 2);
T m = floor((2 * phi) / constants::pi<T>());
int s = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
s = -1;
rphi = constants::pi<T>() / 2 - rphi;
}
T sinp = sin(rphi);
T cosp = cos(rphi);
T x = cosp * cosp;
T t = k * k * sinp * sinp;
T y = 1 - t;
T z = 1;
result = s * sinp * (ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3);
if(m != 0)
result += m * ellint_e_imp(k, pol);
}
return invert ? -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

View File

@@ -0,0 +1,329 @@
// Copyright (c) 2006 Xiaogang Zhang
// Copyright (c) 2006 John Maddock
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to correctly
// handle the various corner cases.
//
#ifndef BOOST_MATH_ELLINT_3_HPP
#define BOOST_MATH_ELLINT_3_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/ellint_rf.hpp>
#include <boost/math/special_functions/ellint_rj.hpp>
#include <boost/math/special_functions/ellint_1.hpp>
#include <boost/math/special_functions/ellint_2.hpp>
#include <boost/math/special_functions/log1p.hpp>
#include <boost/math/constants/constants.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/workaround.hpp>
// Elliptic integrals (complete and incomplete) of the third kind
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math {
namespace detail{
template <typename T, typename Policy>
T ellint_pi_imp(T v, T k, T vc, const Policy& pol);
// Elliptic integral (Legendre form) of the third kind
template <typename T, typename Policy>
T ellint_pi_imp(T v, T phi, T k, T vc, const Policy& pol)
{
// Note vc = 1-v presumably without cancellation error.
T value, x, y, z, p, t;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
using namespace boost::math::constants;
static const char* function = "boost::math::ellint_3<%1%>(%1%,%1%,%1%)";
if (abs(k) > 1)
{
return policies::raise_domain_error<T>(function,
"Got k = %1%, function requires |k| <= 1", k, pol);
}
T sphi = sin(fabs(phi));
if(v > 1 / (sphi * sphi))
{
// Complex result is a domain error:
return policies::raise_domain_error<T>(function,
"Got v = %1%, but result is complex for v > 1 / sin^2(phi)", v, pol);
}
// Special cases first:
if(v == 0)
{
// A&S 17.7.18 & 19
return (k == 0) ? phi : ellint_f_imp(phi, k, pol);
}
if(phi == constants::pi<T>() / 2)
{
// Have to filter this case out before the next
// special case, otherwise we might get an infinity from
// tan(phi).
// Also note that since we can't represent PI/2 exactly
// in a T, this is a bit of a guess as to the users true
// intent...
//
return ellint_pi_imp(v, k, vc, pol);
}
if(k == 0)
{
// A&S 17.7.20:
if(v < 1)
{
T vcr = sqrt(vc);
return atan(vcr * tan(phi)) / vcr;
}
else if(v == 1)
{
return tan(phi);
}
else
{
// v > 1:
T vcr = sqrt(-vc);
T arg = vcr * tan(phi);
return (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * vcr);
}
}
if(v < 0)
{
//
// If we don't shift to 0 <= v <= 1 we get
// cancellation errors later on. Use
// A&S 17.7.15/16 to shift to v > 0:
//
T k2 = k * k;
T N = (k2 - v) / (1 - v);
T Nm1 = (1 - k2) / (1 - v);
T p2 = sqrt(-v * (k2 - v) / (1 - v));
T delta = sqrt(1 - k2 * sphi * sphi);
T result = ellint_pi_imp(N, phi, k, Nm1, pol);
result *= sqrt(Nm1 * (1 - k2 / N));
result += ellint_f_imp(phi, k, pol) * k2 / p2;
result += atan((p2/2) * sin(2 * phi) / delta);
result /= sqrt((1 - v) * (1 - k2 / v));
return result;
}
#if 0 // disabled but retained for future reference: see below.
if(v > 1)
{
//
// If v > 1 we can use the identity in A&S 17.7.7/8
// to shift to 0 <= v <= 1. Unfortunately this
// identity appears only to function correctly when
// 0 <= phi <= pi/2, but it's when phi is outside that
// range that we really need it: That's when
// Carlson's formula fails, and what's more the periodicity
// reduction used below on phi doesn't work when v > 1.
//
// So we're stuck... the code is archived here in case
// some bright spart can figure out the fix.
//
T k2 = k * k;
T N = k2 / v;
T Nm1 = (v - k2) / v;
T p1 = sqrt((-vc) * (1 - k2 / v));
T delta = sqrt(1 - k2 * sphi * sphi);
//
// These next two terms have a large amount of cancellation
// so it's not clear if this relation is useable even if
// the issues with phi > pi/2 can be fixed:
//
T result = -ellint_pi_imp(N, phi, k, Nm1);
result += ellint_f_imp(phi, k);
//
// This log term gives the complex result when
// n > 1/sin^2(phi)
// However that case is dealt with as an error above,
// so we should always get a real result here:
//
result += log((delta + p1 * tan(phi)) / (delta - p1 * tan(phi))) / (2 * p1);
return result;
}
#endif
// Carlson's algorithm works only for |phi| <= pi/2,
// use the integrand's periodicity to normalize phi
//
// Xiaogang's original code used a cast to long long here
// but that fails if T has more digits than a long long,
// so rewritten to use fmod instead:
//
if(fabs(phi) > 1 / tools::epsilon<T>())
{
if(v > 1)
return policies::raise_domain_error<T>(
function,
"Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol);
//
// Phi is so large that phi%pi is necessarily zero (or garbage),
// just return the second part of the duplication formula:
//
value = 2 * fabs(phi) * ellint_pi_imp(v, k, vc, pol) / constants::pi<T>();
}
else
{
T rphi = boost::math::tools::fmod_workaround(fabs(phi), constants::pi<T>() / 2);
T m = floor((2 * fabs(phi)) / constants::pi<T>());
int sign = 1;
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
{
m += 1;
sign = -1;
rphi = constants::pi<T>() / 2 - rphi;
}
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>
typename detail::ellint_3_result<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi)
{
typedef typename policies::is_policy<T3>::type tag_type;
return detail::ellint_3(k, v, phi, tag_type());
}
template <class T1, class T2>
inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v)
{
return ellint_3(k, v, policies::policy<>());
}
}} // namespaces
#endif // BOOST_MATH_ELLINT_3_HPP

View File

@@ -0,0 +1,115 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to correctly
// handle the y < 0 case.
//
#ifndef BOOST_MATH_ELLINT_RC_HPP
#define BOOST_MATH_ELLINT_RC_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/special_functions/math_fwd.hpp>
// Carlson's degenerate elliptic integral
// R_C(x, y) = R_F(x, y, y) = 0.5 * \int_{0}^{\infty} (t+x)^{-1/2} (t+y)^{-1} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rc_imp(T x, T y, const Policy& pol)
{
T value, S, u, lambda, tolerance, prefix;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rc<%1%>(%1%,%1%)";
if(x < 0)
{
return policies::raise_domain_error<T>(function,
"Argument x must be non-negative but got %1%", x, pol);
}
if(y == 0)
{
return policies::raise_domain_error<T>(function,
"Argument y must not be zero but got %1%", y, pol);
}
// error scales as the 6th power of tolerance
tolerance = pow(4 * tools::epsilon<T>(), T(1) / 6);
// for y < 0, the integral is singular, return Cauchy principal value
if (y < 0)
{
prefix = sqrt(x / (x - y));
x = x - y;
y = -y;
}
else
prefix = 1;
// duplication:
k = 1;
do
{
u = (x + y + y) / 3;
S = y / u - 1; // 1 - x / u = 2 * S
if (2 * abs(S) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
lambda = 2 * sx * sy + y;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
++k;
}while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations(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

View File

@@ -0,0 +1,130 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it slightly to fit into the
// Boost.Math conceptual framework better.
#ifndef BOOST_MATH_ELLINT_RD_HPP
#define BOOST_MATH_ELLINT_RD_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
// Carlson's elliptic integral of the second kind
// R_D(x, y, z) = R_J(x, y, z, z) = 1.5 * \int_{0}^{\infty} [(t+x)(t+y)]^{-1/2} (t+z)^{-3/2} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rd_imp(T x, T y, T z, const Policy& pol)
{
T value, u, lambda, sigma, factor, tolerance;
T X, Y, Z, EA, EB, EC, ED, EE, S1, S2;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)";
if (x < 0)
{
return policies::raise_domain_error<T>(function,
"Argument x must be >= 0, but got %1%", x, pol);
}
if (y < 0)
{
return policies::raise_domain_error<T>(function,
"Argument y must be >= 0, but got %1%", y, pol);
}
if (z <= 0)
{
return policies::raise_domain_error<T>(function,
"Argument z must be > 0, but got %1%", z, pol);
}
if (x + y == 0)
{
return policies::raise_domain_error<T>(function,
"At most one argument can be zero, but got, x + y = %1%", x+y, pol);
}
// error scales as the 6th power of tolerance
tolerance = pow(tools::epsilon<T>() / 3, T(1)/6);
// duplication
sigma = 0;
factor = 1;
k = 1;
do
{
u = (x + y + z + z + z) / 5;
X = (u - x) / u;
Y = (u - y) / u;
Z = (u - z) / u;
if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
T sz = sqrt(z);
lambda = sy * (sx + sz) + sz * sx; //sqrt(x * y) + sqrt(y * z) + sqrt(z * x);
sigma += factor / (sz * (z + lambda));
factor /= 4;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
++k;
}
while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations(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

View File

@@ -0,0 +1,132 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to handle
// types longer than 80-bit reals.
//
#ifndef BOOST_MATH_ELLINT_RF_HPP
#define BOOST_MATH_ELLINT_RF_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
// Carlson's elliptic integral of the first kind
// R_F(x, y, z) = 0.5 * \int_{0}^{\infty} [(t+x)(t+y)(t+z)]^{-1/2} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rf_imp(T x, T y, T z, const Policy& pol)
{
T value, X, Y, Z, E2, E3, u, lambda, tolerance;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)";
if (x < 0 || y < 0 || z < 0)
{
return policies::raise_domain_error<T>(function,
"domain error, all arguments must be non-negative, "
"only sensible result is %1%.",
std::numeric_limits<T>::quiet_NaN(), pol);
}
if (x + y == 0 || y + z == 0 || z + x == 0)
{
return policies::raise_domain_error<T>(function,
"domain error, at most one argument can be zero, "
"only sensible result is %1%.",
std::numeric_limits<T>::quiet_NaN(), pol);
}
// Carlson scales error as the 6th power of tolerance,
// but this seems not to work for types larger than
// 80-bit reals, this heuristic seems to work OK:
if(policies::digits<T, Policy>() > 64)
{
tolerance = pow(tools::epsilon<T>(), T(1)/4.25f);
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
}
else
{
tolerance = pow(4*tools::epsilon<T>(), T(1)/6);
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
}
// duplication
k = 1;
do
{
u = (x + y + z) / 3;
X = (u - x) / u;
Y = (u - y) / u;
Z = (u - z) / u;
// Termination condition:
if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
T sz = sqrt(z);
lambda = sy * (sx + sz) + sz * sx;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
++k;
}
while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations(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

View File

@@ -0,0 +1,179 @@
// Copyright (c) 2006 Xiaogang Zhang
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// History:
// XZ wrote the original of this file as part of the Google
// Summer of Code 2006. JM modified it to fit into the
// Boost.Math conceptual framework better, and to correctly
// handle the p < 0 case.
//
#ifndef BOOST_MATH_ELLINT_RJ_HPP
#define BOOST_MATH_ELLINT_RJ_HPP
#ifdef _MSC_VER
#pragma once
#endif
#include <boost/math/special_functions/math_fwd.hpp>
#include <boost/math/tools/config.hpp>
#include <boost/math/policies/error_handling.hpp>
#include <boost/math/special_functions/ellint_rc.hpp>
// Carlson's elliptic integral of the third kind
// R_J(x, y, z, p) = 1.5 * \int_{0}^{\infty} (t+p)^{-1} [(t+x)(t+y)(t+z)]^{-1/2} dt
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
namespace boost { namespace math { namespace detail{
template <typename T, typename Policy>
T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
{
T value, u, lambda, alpha, beta, sigma, factor, tolerance;
T X, Y, Z, P, EA, EB, EC, E2, E3, S1, S2, S3;
unsigned long k;
BOOST_MATH_STD_USING
using namespace boost::math::tools;
static const char* function = "boost::math::ellint_rj<%1%>(%1%,%1%,%1%)";
if (x < 0)
{
return policies::raise_domain_error<T>(function,
"Argument x must be non-negative, but got x = %1%", x, pol);
}
if(y < 0)
{
return policies::raise_domain_error<T>(function,
"Argument y must be non-negative, but got y = %1%", y, pol);
}
if(z < 0)
{
return policies::raise_domain_error<T>(function,
"Argument z must be non-negative, but got z = %1%", z, pol);
}
if(p == 0)
{
return policies::raise_domain_error<T>(function,
"Argument p must not be zero, but got p = %1%", p, pol);
}
if (x + y == 0 || y + z == 0 || z + x == 0)
{
return policies::raise_domain_error<T>(function,
"At most one argument can be zero, "
"only possible result is %1%.", std::numeric_limits<T>::quiet_NaN(), pol);
}
// error scales as the 6th power of tolerance
tolerance = pow(T(1) * tools::epsilon<T>() / 3, T(1) / 6);
// for p < 0, the integral is singular, return Cauchy principal value
if (p < 0)
{
//
// We must ensure that (z - y) * (y - x) is positive.
// Since the integral is symmetrical in x, y and z
// we can just permute the values:
//
if(x > y)
std::swap(x, y);
if(y > z)
std::swap(y, z);
if(x > y)
std::swap(x, y);
T q = -p;
T pmy = (z - y) * (y - x) / (y + q); // p - y
BOOST_ASSERT(pmy >= 0);
T p = pmy + y;
value = boost::math::ellint_rj(x, y, z, p, pol);
value *= pmy;
value -= 3 * boost::math::ellint_rf(x, y, z, pol);
value += 3 * sqrt((x * y * z) / (x * z + p * q)) * boost::math::ellint_rc(x * z + p * q, p * q, pol);
value /= (y + q);
return value;
}
// duplication
sigma = 0;
factor = 1;
k = 1;
do
{
u = (x + y + z + p + p) / 5;
X = (u - x) / u;
Y = (u - y) / u;
Z = (u - z) / u;
P = (u - p) / u;
if ((tools::max)(abs(X), abs(Y), abs(Z), abs(P)) < tolerance)
break;
T sx = sqrt(x);
T sy = sqrt(y);
T sz = sqrt(z);
lambda = sy * (sx + sz) + sz * sx;
alpha = p * (sx + sy + sz) + sx * sy * sz;
alpha *= alpha;
beta = p * (p + lambda) * (p + lambda);
sigma += factor * boost::math::ellint_rc(alpha, beta, pol);
factor /= 4;
x = (x + lambda) / 4;
y = (y + lambda) / 4;
z = (z + lambda) / 4;
p = (p + lambda) / 4;
++k;
}
while(k < policies::get_max_series_iterations<Policy>());
// Check to see if we gave up too soon:
policies::check_series_iterations(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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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