mirror of
https://github.com/boostorg/math.git
synced 2026-01-30 08:02:11 +00:00
Full merge from trunk at revision 41356 of entire boost-root tree.
[SVN r41369]
This commit is contained in:
707
include/boost/math/bindings/rr.hpp
Normal file
707
include/boost/math/bindings/rr.hpp
Normal file
@@ -0,0 +1,707 @@
|
||||
// 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 <cmath>
|
||||
#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(unsigned long long c)
|
||||
{
|
||||
assign_large_int(c);
|
||||
}
|
||||
RR(long long 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=(long long c) { assign_large_int(c); return *this; }
|
||||
RR& operator=(unsigned long long 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;
|
||||
}
|
||||
|
||||
} // namespace ntl
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_REAL_CONCEPT_HPP
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <boost/config.hpp> // for BOOST_NESTED_TEMPLATE, etc.
|
||||
#include <boost/limits.hpp> // for std::numeric_limits
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
|
||||
namespace boost
|
||||
@@ -114,6 +115,69 @@ namespace detail
|
||||
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
|
||||
@@ -228,6 +292,46 @@ namespace detail
|
||||
};
|
||||
#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( unsigned long long );
|
||||
#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( long long, unsigned long long );
|
||||
#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 >
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
// inverse trig complex functions, it also contains all the includes
|
||||
// that we need to implement all these functions.
|
||||
//
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#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
|
||||
|
||||
204
include/boost/math/concepts/distributions.hpp
Normal file
204
include/boost/math/concepts/distributions.hpp
Normal 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
|
||||
|
||||
388
include/boost/math/concepts/real_concept.hpp
Normal file
388
include/boost/math/concepts/real_concept.hpp
Normal file
@@ -0,0 +1,388 @@
|
||||
// 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".
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/math/tools/real_cast.hpp>
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/policies/policy.hpp>
|
||||
#include <ostream>
|
||||
#include <istream>
|
||||
#include <cmath>
|
||||
#include <math.h> // fmodl
|
||||
|
||||
#ifndef BOOST_MATH_REAL_CONCEPT_HPP
|
||||
#define BOOST_MATH_REAL_CONCEPT_HPP
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace concepts
|
||||
{
|
||||
|
||||
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(BOOST_HAS_LONG_LONG) || defined(__DECCXX) || defined(__SUNPRO_CC)
|
||||
real_concept(unsigned long long c) : m_value(static_cast<long double>(c)){}
|
||||
real_concept(long long c) : m_value(static_cast<long double>(c)){}
|
||||
#elif defined(BOOST_HAS_MS_INT64)
|
||||
real_concept(unsigned __int64 c) : m_value(static_cast<long double>(c)){}
|
||||
real_concept(__int64 c) : m_value(static_cast<long double>(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=(long long c) { m_value = static_cast<long double>(c); return *this; }
|
||||
real_concept& operator=(unsigned long long c) { m_value = static_cast<long double>(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:
|
||||
long double 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; }
|
||||
|
||||
private:
|
||||
long double 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(); }
|
||||
|
||||
#if 0
|
||||
// Non-member mixed compare:
|
||||
template <class T>
|
||||
inline bool operator == (const T& a, const real_concept& b)
|
||||
{
|
||||
return a == b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator != (const T& a, const real_concept& b)
|
||||
{
|
||||
return a != b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator < (const T& a, const real_concept& b)
|
||||
{
|
||||
return a < b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator > (const T& a, const real_concept& b)
|
||||
{
|
||||
return a > b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator <= (const T& a, const real_concept& b)
|
||||
{
|
||||
return a <= b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator >= (const T& a, const real_concept& b)
|
||||
{
|
||||
return a >= b.value();
|
||||
}
|
||||
#endif // Non-member mixed compare:
|
||||
|
||||
// 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
|
||||
#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)
|
||||
{
|
||||
long double ip;
|
||||
long double 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<long double>(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()); }
|
||||
|
||||
// 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)
|
||||
std::string s;
|
||||
long double d;
|
||||
is >> s;
|
||||
std::sscanf(s.c_str(), "%Lf", &d);
|
||||
a = d;
|
||||
return is;
|
||||
#else
|
||||
long double v;
|
||||
is >> v;
|
||||
a = v;
|
||||
return is;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace concepts
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline concepts::real_concept max_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
|
||||
{
|
||||
return max_value<long double>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline concepts::real_concept min_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
|
||||
{
|
||||
return min_value<long double>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline concepts::real_concept log_max_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
|
||||
{
|
||||
return log_max_value<long double>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline concepts::real_concept log_min_value<concepts::real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::real_concept))
|
||||
{
|
||||
return log_min_value<long double>();
|
||||
}
|
||||
|
||||
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<long double>::epsilon();
|
||||
#else
|
||||
return tools::epsilon<long double>();
|
||||
#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 long double,
|
||||
// unless std::numeric_limits<T>::is_specialized to provide digits.
|
||||
return tools::digits<long double>();
|
||||
// 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
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_REAL_CONCEPT_HPP
|
||||
|
||||
|
||||
356
include/boost/math/concepts/std_real_concept.hpp
Normal file
356
include/boost/math/concepts/std_real_concept.hpp
Normal file
@@ -0,0 +1,356 @@
|
||||
// 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/tools/real_cast.hpp>
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/policies/policy.hpp>
|
||||
|
||||
#include <ostream>
|
||||
#include <istream>
|
||||
#include <cmath>
|
||||
#include <math.h> // fmodl
|
||||
|
||||
#ifndef BOOST_MATH_STD_REAL_CONCEPT_HPP
|
||||
#define BOOST_MATH_STD_REAL_CONCEPT_HPP
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace concepts
|
||||
{
|
||||
|
||||
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(BOOST_HAS_LONG_LONG) || defined(__DECCXX) || defined(__SUNPRO_CC)
|
||||
std_real_concept(unsigned long long c) : m_value(static_cast<long double>(c)){}
|
||||
std_real_concept(long long c) : m_value(static_cast<long double>(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(BOOST_HAS_LONG_LONG) || defined(__DECCXX) || defined(__SUNPRO_CC)
|
||||
std_real_concept& operator=(long long c) { m_value = static_cast<long double>(c); return *this; }
|
||||
std_real_concept& operator=(unsigned long long c) { m_value = static_cast<long double>(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:
|
||||
long double 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:
|
||||
long double 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(); }
|
||||
|
||||
#if 0
|
||||
// Non-member mixed compare:
|
||||
template <class T>
|
||||
inline bool operator == (const T& a, const std_real_concept& b)
|
||||
{
|
||||
return a == b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator != (const T& a, const std_real_concept& b)
|
||||
{
|
||||
return a != b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator < (const T& a, const std_real_concept& b)
|
||||
{
|
||||
return a < b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator > (const T& a, const std_real_concept& b)
|
||||
{
|
||||
return a > b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator <= (const T& a, const std_real_concept& b)
|
||||
{
|
||||
return a <= b.value();
|
||||
}
|
||||
template <class T>
|
||||
inline bool operator >= (const T& a, const std_real_concept& b)
|
||||
{
|
||||
return a >= b.value();
|
||||
}
|
||||
#endif // Non-member mixed compare:
|
||||
|
||||
} // 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)
|
||||
{
|
||||
long double ip;
|
||||
long double 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{
|
||||
|
||||
// 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)
|
||||
{
|
||||
long double v;
|
||||
is >> v;
|
||||
a = v;
|
||||
return is;
|
||||
}
|
||||
|
||||
} // namespace concepts
|
||||
|
||||
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::std_real_concept>(concepts::std_real_concept r)
|
||||
{
|
||||
return static_cast<unsigned int>(r.value());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int real_cast<int, concepts::std_real_concept>(concepts::std_real_concept r)
|
||||
{
|
||||
return static_cast<int>(r.value());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline long real_cast<long, concepts::std_real_concept>(concepts::std_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::std_real_concept>(concepts::std_real_concept r)
|
||||
{
|
||||
return static_cast<float>(r.value());
|
||||
}
|
||||
template <>
|
||||
inline double real_cast<double, concepts::std_real_concept>(concepts::std_real_concept r)
|
||||
{
|
||||
return static_cast<double>(r.value());
|
||||
}
|
||||
template <>
|
||||
inline long double real_cast<long double, concepts::std_real_concept>(concepts::std_real_concept r)
|
||||
{
|
||||
return r.value();
|
||||
}
|
||||
|
||||
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<long double>();
|
||||
}
|
||||
|
||||
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<long double>();
|
||||
}
|
||||
|
||||
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<long double>();
|
||||
}
|
||||
|
||||
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<long double>();
|
||||
}
|
||||
|
||||
template <>
|
||||
inline concepts::std_real_concept epsilon<concepts::std_real_concept>(BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(concepts::std_real_concept))
|
||||
{
|
||||
return tools::epsilon<long double>();
|
||||
}
|
||||
|
||||
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 long double,
|
||||
// unless std::numeric_limits<T>::is_specialized to provide digits.
|
||||
return digits<long double>();
|
||||
}
|
||||
|
||||
} // namespace tools
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_STD_REAL_CONCEPT_HPP
|
||||
|
||||
|
||||
75
include/boost/math/constants/constants.hpp
Normal file
75
include/boost/math/constants/constants.hpp
Normal 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
|
||||
42
include/boost/math/distributions.hpp
Normal file
42
include/boost/math/distributions.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright John Maddock 2006, 2007.
|
||||
// Copyright Paul A. Bristow 2006, 2007.
|
||||
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// This file includes *all* the distributions.
|
||||
// this may be useful if many are used
|
||||
// - to avoid including each distribution individually.
|
||||
|
||||
#ifndef BOOST_MATH_DISTRIBUTIONS_HPP
|
||||
#define BOOST_MATH_DISTRIBUTIONS_HPP
|
||||
|
||||
#include <boost/math/distributions/bernoulli.hpp>
|
||||
#include <boost/math/distributions/beta.hpp>
|
||||
#include <boost/math/distributions/binomial.hpp>
|
||||
#include <boost/math/distributions/cauchy.hpp>
|
||||
#include <boost/math/distributions/chi_squared.hpp>
|
||||
#include <boost/math/distributions/complement.hpp>
|
||||
#include <boost/math/distributions/exponential.hpp>
|
||||
#include <boost/math/distributions/extreme_value.hpp>
|
||||
#include <boost/math/distributions/fisher_f.hpp>
|
||||
#include <boost/math/distributions/gamma.hpp>
|
||||
#include <boost/math/distributions/lognormal.hpp>
|
||||
#include <boost/math/distributions/negative_binomial.hpp>
|
||||
#include <boost/math/distributions/normal.hpp>
|
||||
#include <boost/math/distributions/pareto.hpp>
|
||||
#include <boost/math/distributions/poisson.hpp>
|
||||
#include <boost/math/distributions/rayleigh.hpp>
|
||||
#include <boost/math/distributions/students_t.hpp>
|
||||
#include <boost/math/distributions/triangular.hpp>
|
||||
#include <boost/math/distributions/uniform.hpp>
|
||||
#include <boost/math/distributions/weibull.hpp>
|
||||
// find location and shape for appropriate distributions,
|
||||
// normal, cauchy, lognormal, symmetric triangular
|
||||
// Disabled for now, these are still work in progress.
|
||||
//#include <boost/math/distributions/find_scale.hpp>
|
||||
//#include <boost/math/distributions/find_location.hpp>
|
||||
|
||||
#endif // BOOST_MATH_DISTRIBUTIONS_HPP
|
||||
|
||||
325
include/boost/math/distributions/bernoulli.hpp
Normal file
325
include/boost/math/distributions/bernoulli.hpp
Normal 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
|
||||
|
||||
|
||||
|
||||
544
include/boost/math/distributions/beta.hpp
Normal file
544
include/boost/math/distributions/beta.hpp
Normal 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
|
||||
|
||||
|
||||
724
include/boost/math/distributions/binomial.hpp
Normal file
724
include/boost/math/distributions/binomial.hpp
Normal 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
|
||||
|
||||
|
||||
347
include/boost/math/distributions/cauchy.hpp
Normal file
347
include/boost/math/distributions/cauchy.hpp
Normal 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 <cmath>
|
||||
|
||||
#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
|
||||
326
include/boost/math/distributions/chi_squared.hpp
Normal file
326
include/boost/math/distributions/chi_squared.hpp
Normal file
@@ -0,0 +1,326 @@
|
||||
// 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_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%>&)";
|
||||
if(df <= 2)
|
||||
return policies::raise_domain_error<RealType>(
|
||||
function,
|
||||
"The 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
|
||||
195
include/boost/math/distributions/complement.hpp
Normal file
195
include/boost/math/distributions/complement.hpp
Normal 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
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
// 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.
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_DISTRIBUTIONS_COMMON_ERROR_HANDLING_HPP
|
||||
163
include/boost/math/distributions/detail/derived_accessors.hpp
Normal file
163
include/boost/math/distributions/detail/derived_accessors.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
259
include/boost/math/distributions/exponential.hpp
Normal file
259
include/boost/math/distributions/exponential.hpp
Normal file
@@ -0,0 +1,259 @@
|
||||
// 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 <cmath>
|
||||
|
||||
#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;
|
||||
return std::pair<RealType, RealType>(0, max_value<RealType>());
|
||||
}
|
||||
|
||||
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
|
||||
260
include/boost/math/distributions/extreme_value.hpp
Normal file
260
include/boost/math/distributions/extreme_value.hpp
Normal 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 <cmath>
|
||||
|
||||
//
|
||||
// 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
|
||||
144
include/boost/math/distributions/find_location.hpp
Normal file
144
include/boost/math/distributions/find_location.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
// 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>
|
||||
// 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
|
||||
|
||||
209
include/boost/math/distributions/find_scale.hpp
Normal file
209
include/boost/math/distributions/find_scale.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
// 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>
|
||||
// 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
|
||||
385
include/boost/math/distributions/fisher_f.hpp
Normal file
385
include/boost/math/distributions/fisher_f.hpp
Normal 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
|
||||
94
include/boost/math/distributions/fwd.hpp
Normal file
94
include/boost/math/distributions/fwd.hpp
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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 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;\
|
||||
|
||||
#endif // BOOST_MATH_DISTRIBUTIONS_FWD_HPP
|
||||
348
include/boost/math/distributions/gamma.hpp
Normal file
348
include/boost/math/distributions/gamma.hpp
Normal file
@@ -0,0 +1,348 @@
|
||||
// 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;
|
||||
return std::pair<RealType, RealType>(0, 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
|
||||
|
||||
|
||||
310
include/boost/math/distributions/lognormal.hpp
Normal file
310
include/boost/math/distributions/lognormal.hpp
Normal 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
|
||||
|
||||
|
||||
588
include/boost/math/distributions/negative_binomial.hpp
Normal file
588
include/boost/math/distributions/negative_binomial.hpp
Normal 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
|
||||
308
include/boost/math/distributions/normal.hpp
Normal file
308
include/boost/math/distributions/normal.hpp
Normal 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.
|
||||
}
|
||||
// Theis 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
|
||||
|
||||
|
||||
443
include/boost/math/distributions/pareto.hpp
Normal file
443
include/boost/math/distributions/pareto.hpp
Normal 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
|
||||
|
||||
|
||||
602
include/boost/math/distributions/poisson.hpp
Normal file
602
include/boost/math/distributions/poisson.hpp
Normal file
@@ -0,0 +1,602 @@
|
||||
// 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 Siméon-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/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);
|
||||
}
|
||||
using boost::math::unchecked_factorial;
|
||||
RealType floork = floor(k);
|
||||
if ((floork == k) // integral
|
||||
&& k < max_factorial<RealType>::value)
|
||||
{ // k is small enough (for float 34, double 170 ...) to use factorial(k).
|
||||
return exp(-mean) * pow(mean, k) /
|
||||
unchecked_factorial<RealType>(tools::real_cast<unsigned int>(floork));
|
||||
}
|
||||
else
|
||||
{ // Need to use log(factorial(k)) = lgamma(k+1)
|
||||
// (e ^ -mean * mean ^ k) / k!
|
||||
// == exp(log(e ^ -mean) + log (mean ^ k) - lgamma(k+1))
|
||||
// exp( -mean + log(mean) * k - lgamma(k+1))
|
||||
return exp(-mean + log(mean) * k - boost::math::lgamma(k+1, Policy()));
|
||||
// return gamma_p_derivative(k+1, mean); // equivalent & also passes tests.
|
||||
}
|
||||
} // 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
|
||||
|
||||
|
||||
|
||||
293
include/boost/math/distributions/rayleigh.hpp
Normal file
293
include/boost/math/distributions/rayleigh.hpp
Normal 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 <cmath>
|
||||
|
||||
#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
|
||||
374
include/boost/math/distributions/students_t.hpp
Normal file
374
include/boost/math/distributions/students_t.hpp
Normal 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
|
||||
521
include/boost/math/distributions/triangular.hpp
Normal file
521
include/boost/math/distributions/triangular.hpp
Normal file
@@ -0,0 +1,521 @@
|
||||
// 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)
|
||||
&& check_triangular_mode(function, mode, result, pol)
|
||||
&& check_triangular_upper(function, upper, result, pol)
|
||||
&& (lower < upper) // lower == upper NOT useful.
|
||||
)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{ // upper and lower have each 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;
|
||||
}
|
||||
} // 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
|
||||
|
||||
|
||||
|
||||
375
include/boost/math/distributions/uniform.hpp
Normal file
375
include/boost/math/distributions/uniform.hpp
Normal file
@@ -0,0 +1,375 @@
|
||||
// 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)
|
||||
&& check_uniform_upper(function, upper, result, pol)
|
||||
&& (lower < upper)) // If lower == upper then 1 / (upper-lower) = 1/0 = +infinity!
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{ // 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;
|
||||
}
|
||||
} // 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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
382
include/boost/math/distributions/weibull.hpp
Normal file
382
include/boost/math/distributions/weibull.hpp
Normal file
@@ -0,0 +1,382 @@
|
||||
// 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;
|
||||
return std::pair<RealType, RealType>(0, max_value<RealType>());
|
||||
}
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
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
|
||||
|
||||
|
||||
518
include/boost/math/policies/error_handling.hpp
Normal file
518
include/boost/math/policies/error_handling.hpp
Normal file
@@ -0,0 +1,518 @@
|
||||
// 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 <cmath>
|
||||
#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){}
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
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";
|
||||
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";
|
||||
if(message == 0)
|
||||
message = "Cause unknown";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // 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());
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
|
||||
843
include/boost/math/policies/policy.hpp
Normal file
843
include/boost/math/policies/policy.hpp
Normal file
@@ -0,0 +1,843 @@
|
||||
// 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_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_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__)
|
||||
#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_<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_<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(detail::is_##name##_tester<T>::test(inst)) == 1);\
|
||||
};\
|
||||
}\
|
||||
template <class T> struct is_##name : public boost::mpl::bool_<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(detail::is_##name##_tester<T>::test(inst)) == 1);\
|
||||
};\
|
||||
}\
|
||||
template <class T> struct is_##name : public boost::mpl::bool_<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)
|
||||
|
||||
//
|
||||
// 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;
|
||||
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;
|
||||
#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;
|
||||
#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;
|
||||
//
|
||||
// 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,
|
||||
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();
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
|
||||
|
||||
51
include/boost/math/special_functions.hpp
Normal file
51
include/boost/math/special_functions.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright John Maddock 2006, 2007.
|
||||
// Copyright Paul A. Bristow 2006, 2007.
|
||||
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// This file includes *all* the special functions.
|
||||
// this may be useful if many are used
|
||||
// - to avoid including each function individually.
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_HPP
|
||||
#define BOOST_MATH_SPECIAL_FUNCTIONS_HPP
|
||||
|
||||
#include <boost/math/special_functions/acosh.hpp>
|
||||
#include <boost/math/special_functions/asinh.hpp>
|
||||
#include <boost/math/special_functions/atanh.hpp>
|
||||
#include <boost/math/special_functions/bessel.hpp>
|
||||
#include <boost/math/special_functions/beta.hpp>
|
||||
#include <boost/math/special_functions/binomial.hpp>
|
||||
#include <boost/math/special_functions/cbrt.hpp>
|
||||
#include <boost/math/special_functions/cos_pi.hpp>
|
||||
#include <boost/math/special_functions/digamma.hpp>
|
||||
#include <boost/math/special_functions/ellint_1.hpp>
|
||||
#include <boost/math/special_functions/ellint_2.hpp>
|
||||
#include <boost/math/special_functions/ellint_3.hpp>
|
||||
#include <boost/math/special_functions/ellint_rc.hpp>
|
||||
#include <boost/math/special_functions/ellint_rd.hpp>
|
||||
#include <boost/math/special_functions/ellint_rf.hpp>
|
||||
#include <boost/math/special_functions/ellint_rj.hpp>
|
||||
#include <boost/math/special_functions/erf.hpp>
|
||||
#include <boost/math/special_functions/expm1.hpp>
|
||||
#include <boost/math/special_functions/factorials.hpp>
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
#include <boost/math/special_functions/gamma.hpp>
|
||||
#include <boost/math/special_functions/hermite.hpp>
|
||||
#include <boost/math/special_functions/hypot.hpp>
|
||||
#include <boost/math/special_functions/laguerre.hpp>
|
||||
#include <boost/math/special_functions/lanczos.hpp>
|
||||
#include <boost/math/special_functions/legendre.hpp>
|
||||
#include <boost/math/special_functions/log1p.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/special_functions/powm1.hpp>
|
||||
#include <boost/math/special_functions/sign.hpp>
|
||||
#include <boost/math/special_functions/sin_pi.hpp>
|
||||
#include <boost/math/special_functions/sinc.hpp>
|
||||
#include <boost/math/special_functions/sinhc.hpp>
|
||||
#include <boost/math/special_functions/spherical_harmonic.hpp>
|
||||
#include <boost/math/special_functions/sqrt1pm1.hpp>
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_HPP
|
||||
@@ -12,13 +12,10 @@
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
// This is the inverse of the hyperbolic cosine function.
|
||||
|
||||
@@ -26,6 +23,8 @@ namespace 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:
|
||||
@@ -37,39 +36,25 @@ namespace boost
|
||||
using ::std::numeric_limits;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
// This is the main fare
|
||||
|
||||
template<typename T>
|
||||
inline T acosh(const T x)
|
||||
template<typename T, typename Policy>
|
||||
inline T acosh_imp(const T x, const Policy& pol)
|
||||
{
|
||||
using ::std::abs;
|
||||
using ::std::sqrt;
|
||||
using ::std::log;
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
|
||||
T const one = static_cast<T>(1);
|
||||
T const two = static_cast<T>(2);
|
||||
|
||||
static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
|
||||
static T const taylor_2_bound = sqrt(tools::epsilon<T>());
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
static T const upper_taylor_2_bound = one/taylor_2_bound;
|
||||
|
||||
if (x < one)
|
||||
if(x < one)
|
||||
{
|
||||
if (numeric_limits<T>::has_quiet_NaN)
|
||||
{
|
||||
return(numeric_limits<T>::quiet_NaN());
|
||||
}
|
||||
else
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
|
||||
::std::domain_error bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
return policies::raise_domain_error<T>(
|
||||
"boost::math::acosh<%1%>(%1%)",
|
||||
"acosh requires x >= 1, but got x = %1%.", x, pol);
|
||||
}
|
||||
else if (x >= taylor_n_bound)
|
||||
{
|
||||
@@ -101,98 +86,27 @@ namespace boost
|
||||
return(sqrt(static_cast<T>(2))*result);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// These are implementation details (for main fare see below)
|
||||
|
||||
namespace detail
|
||||
}
|
||||
|
||||
template<typename T, typename Policy>
|
||||
inline typename tools::promote_args<T>::type acosh(const T x, const Policy& pol)
|
||||
{
|
||||
template <
|
||||
typename T,
|
||||
bool QuietNanSupported
|
||||
>
|
||||
struct acosh_helper2_t
|
||||
{
|
||||
static T get_NaN()
|
||||
{
|
||||
return(::std::numeric_limits<T>::quiet_NaN());
|
||||
}
|
||||
}; // boost::detail::acosh_helper2_t
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct acosh_helper2_t<T, false>
|
||||
{
|
||||
static T get_NaN()
|
||||
{
|
||||
::std::string error_reporting("Argument to acosh is greater than or equal to +1!");
|
||||
::std::domain_error bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
}; // boost::detail::acosh_helper2_t
|
||||
|
||||
} // boost::detail
|
||||
|
||||
|
||||
// This is the main fare
|
||||
|
||||
template<typename T>
|
||||
inline T acosh(const T x)
|
||||
{
|
||||
using ::std::abs;
|
||||
using ::std::sqrt;
|
||||
using ::std::log;
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
typedef detail::acosh_helper2_t<T, std::numeric_limits<T>::has_quiet_NaN> helper2_type;
|
||||
|
||||
|
||||
T const one = static_cast<T>(1);
|
||||
T const two = static_cast<T>(2);
|
||||
|
||||
static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
static T const upper_taylor_2_bound = one/taylor_2_bound;
|
||||
|
||||
if (x < one)
|
||||
{
|
||||
return(helper2_type::get_NaN());
|
||||
}
|
||||
else if (x >= taylor_n_bound)
|
||||
{
|
||||
if (x > upper_taylor_2_bound)
|
||||
{
|
||||
// approximation by laurent series in 1/x at 0+ order from -1 to 0
|
||||
return( log( x*two) );
|
||||
}
|
||||
else
|
||||
{
|
||||
return( log( x + sqrt(x*x-one) ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
T y = sqrt(x-one);
|
||||
|
||||
// approximation by taylor series in y at 0 up to order 2
|
||||
T result = y;
|
||||
|
||||
if (y >= taylor_2_bound)
|
||||
{
|
||||
T y3 = y*y*y;
|
||||
|
||||
// approximation by taylor series in y at 0 up to order 4
|
||||
result -= y3/static_cast<T>(12);
|
||||
}
|
||||
|
||||
return(sqrt(static_cast<T>(2))*result);
|
||||
}
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::acosh_imp(
|
||||
static_cast<result_type>(x), pol);
|
||||
}
|
||||
#endif /* defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) */
|
||||
template<typename T>
|
||||
inline typename tools::promote_args<T>::type acosh(const T x)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::acosh_imp(
|
||||
static_cast<result_type>(x), policies::policy<>());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BOOST_ACOSH_HPP */
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,13 +12,9 @@
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
// This is the inverse of the hyperbolic sine function.
|
||||
|
||||
@@ -26,6 +22,7 @@ namespace 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:
|
||||
@@ -38,19 +35,16 @@ namespace boost
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
inline T asinh(const T x)
|
||||
inline T asinh_imp(const T x)
|
||||
{
|
||||
using ::std::abs;
|
||||
using ::std::sqrt;
|
||||
using ::std::log;
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
|
||||
T const one = static_cast<T>(1);
|
||||
T const two = static_cast<T>(2);
|
||||
|
||||
static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
|
||||
static T const taylor_2_bound = sqrt(tools::epsilon<T>());
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
static T const upper_taylor_2_bound = one/taylor_2_bound;
|
||||
static T const upper_taylor_n_bound = one/taylor_n_bound;
|
||||
@@ -95,6 +89,23 @@ namespace boost
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline typename tools::promote_args<T>::type asinh(const T x)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::asinh_imp(
|
||||
static_cast<result_type>(x));
|
||||
}
|
||||
template<typename T, typename Policy>
|
||||
inline typename tools::promote_args<T>::type asinh(const T x, const Policy&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::asinh_imp(
|
||||
static_cast<result_type>(x));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,13 +12,10 @@
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
// This is the inverse of the hyperbolic tangent function.
|
||||
|
||||
@@ -26,6 +23,8 @@ namespace 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:
|
||||
@@ -37,11 +36,10 @@ namespace boost
|
||||
using ::std::numeric_limits;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION)
|
||||
// This is the main fare
|
||||
|
||||
template<typename T>
|
||||
inline T atanh(const T x)
|
||||
template<typename T, typename Policy>
|
||||
inline T atanh_imp(const T x, const Policy& pol)
|
||||
{
|
||||
using ::std::abs;
|
||||
using ::std::sqrt;
|
||||
@@ -52,64 +50,32 @@ namespace boost
|
||||
T const one = static_cast<T>(1);
|
||||
T const two = static_cast<T>(2);
|
||||
|
||||
static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
|
||||
static T const taylor_2_bound = sqrt(tools::epsilon<T>());
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
|
||||
static const char* function = "boost::math::atanh<%1%>(%1%)";
|
||||
|
||||
if (x < -one)
|
||||
{
|
||||
if (numeric_limits<T>::has_quiet_NaN)
|
||||
{
|
||||
return(numeric_limits<T>::quiet_NaN());
|
||||
}
|
||||
else
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
|
||||
::std::domain_error bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"atanh requires x >= -1, but got x = %1%.", x, pol);
|
||||
}
|
||||
else if (x < -one+numeric_limits<T>::epsilon())
|
||||
else if (x < -one + tools::epsilon<T>())
|
||||
{
|
||||
if (numeric_limits<T>::has_infinity)
|
||||
{
|
||||
return(-numeric_limits<T>::infinity());
|
||||
}
|
||||
else
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is -1 (result: -Infinity)!");
|
||||
::std::out_of_range bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
// -Infinity:
|
||||
return -policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
else if (x > +one-numeric_limits<T>::epsilon())
|
||||
else if (x > one - tools::epsilon<T>())
|
||||
{
|
||||
if (numeric_limits<T>::has_infinity)
|
||||
{
|
||||
return(+numeric_limits<T>::infinity());
|
||||
}
|
||||
else
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is +1 (result: +Infinity)!");
|
||||
::std::out_of_range bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
// Infinity:
|
||||
return -policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
else if (x > +one)
|
||||
{
|
||||
if (numeric_limits<T>::has_quiet_NaN)
|
||||
{
|
||||
return(numeric_limits<T>::quiet_NaN());
|
||||
}
|
||||
else
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
|
||||
::std::domain_error bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"atanh requires x <= 1, but got x = %1%.", x, pol);
|
||||
}
|
||||
else if (abs(x) >= taylor_n_bound)
|
||||
{
|
||||
@@ -131,137 +97,26 @@ namespace boost
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// These are implementation details (for main fare see below)
|
||||
|
||||
namespace detail
|
||||
}
|
||||
|
||||
template<typename T, typename Policy>
|
||||
inline typename tools::promote_args<T>::type atanh(const T x, const Policy& pol)
|
||||
{
|
||||
template <
|
||||
typename T,
|
||||
bool InfinitySupported
|
||||
>
|
||||
struct atanh_helper1_t
|
||||
{
|
||||
static T get_pos_infinity()
|
||||
{
|
||||
return(+::std::numeric_limits<T>::infinity());
|
||||
}
|
||||
|
||||
static T get_neg_infinity()
|
||||
{
|
||||
return(-::std::numeric_limits<T>::infinity());
|
||||
}
|
||||
}; // boost::math::detail::atanh_helper1_t
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct atanh_helper1_t<T, false>
|
||||
{
|
||||
static T get_pos_infinity()
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is +1 (result: +Infinity)!");
|
||||
::std::out_of_range bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
|
||||
static T get_neg_infinity()
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is -1 (result: -Infinity)!");
|
||||
::std::out_of_range bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
}; // boost::math::detail::atanh_helper1_t
|
||||
|
||||
|
||||
template <
|
||||
typename T,
|
||||
bool QuietNanSupported
|
||||
>
|
||||
struct atanh_helper2_t
|
||||
{
|
||||
static T get_NaN()
|
||||
{
|
||||
return(::std::numeric_limits<T>::quiet_NaN());
|
||||
}
|
||||
}; // boost::detail::atanh_helper2_t
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct atanh_helper2_t<T, false>
|
||||
{
|
||||
static T get_NaN()
|
||||
{
|
||||
::std::string error_reporting("Argument to atanh is strictly greater than +1 or strictly smaller than -1!");
|
||||
::std::domain_error bad_argument(error_reporting);
|
||||
|
||||
throw(bad_argument);
|
||||
}
|
||||
}; // boost::detail::atanh_helper2_t
|
||||
} // boost::detail
|
||||
|
||||
|
||||
// This is the main fare
|
||||
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::atanh_imp(
|
||||
static_cast<result_type>(x), pol);
|
||||
}
|
||||
template<typename T>
|
||||
inline T atanh(const T x)
|
||||
inline typename tools::promote_args<T>::type atanh(const T x)
|
||||
{
|
||||
using ::std::abs;
|
||||
using ::std::sqrt;
|
||||
using ::std::log;
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
typedef detail::atanh_helper1_t<T, ::std::numeric_limits<T>::has_infinity> helper1_type;
|
||||
typedef detail::atanh_helper2_t<T, ::std::numeric_limits<T>::has_quiet_NaN> helper2_type;
|
||||
|
||||
|
||||
T const one = static_cast<T>(1);
|
||||
T const two = static_cast<T>(2);
|
||||
|
||||
static T const taylor_2_bound = sqrt(numeric_limits<T>::epsilon());
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
|
||||
if (x < -one)
|
||||
{
|
||||
return(helper2_type::get_NaN());
|
||||
}
|
||||
else if (x < -one+numeric_limits<T>::epsilon())
|
||||
{
|
||||
return(helper1_type::get_neg_infinity());
|
||||
}
|
||||
else if (x > +one-numeric_limits<T>::epsilon())
|
||||
{
|
||||
return(helper1_type::get_pos_infinity());
|
||||
}
|
||||
else if (x > +one)
|
||||
{
|
||||
return(helper2_type::get_NaN());
|
||||
}
|
||||
else if (abs(x) >= taylor_n_bound)
|
||||
{
|
||||
return(log( (one + x) / (one - x) ) / two);
|
||||
}
|
||||
else
|
||||
{
|
||||
// approximation by taylor series in x at 0 up to order 2
|
||||
T result = x;
|
||||
|
||||
if (abs(x) >= taylor_2_bound)
|
||||
{
|
||||
T x3 = x*x*x;
|
||||
|
||||
// approximation by taylor series in x at 0 up to order 4
|
||||
result += x3/static_cast<T>(3);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::atanh_imp(
|
||||
static_cast<result_type>(x), policies::policy<>());
|
||||
}
|
||||
#endif /* defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) */
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BOOST_ATANH_HPP */
|
||||
|
||||
|
||||
|
||||
484
include/boost/math/special_functions/bessel.hpp
Normal file
484
include/boost/math/special_functions/bessel.hpp
Normal file
@@ -0,0 +1,484 @@
|
||||
// Copyright (c) 2007 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// This header just defines the function entry points, and adds dispatch
|
||||
// to the right implementation method. Most of the implementation details
|
||||
// are in separate headers and copyright Xiaogang Zhang.
|
||||
//
|
||||
#ifndef BOOST_MATH_BESSEL_HPP
|
||||
#define BOOST_MATH_BESSEL_HPP
|
||||
|
||||
#include <boost/math/special_functions/detail/bessel_jy.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_jn.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_yn.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_ik.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_i0.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_i1.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_kn.hpp>
|
||||
#include <boost/math/special_functions/sin_pi.hpp>
|
||||
#include <boost/math/special_functions/cos_pi.hpp>
|
||||
#include <boost/math/special_functions/sinc.hpp>
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class T, class Policy>
|
||||
struct bessel_j_small_z_series_term
|
||||
{
|
||||
typedef T result_type;
|
||||
|
||||
bessel_j_small_z_series_term(T v_, T x)
|
||||
: N(0), v(v_)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
mult = x / 2;
|
||||
term = pow(mult, v) / boost::math::tgamma(v+1, Policy());
|
||||
mult *= -mult;
|
||||
}
|
||||
T operator()()
|
||||
{
|
||||
T r = term;
|
||||
++N;
|
||||
term *= mult / (N * (N + v));
|
||||
return r;
|
||||
}
|
||||
private:
|
||||
unsigned N;
|
||||
T v;
|
||||
T mult;
|
||||
T term;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
struct sph_bessel_j_small_z_series_term
|
||||
{
|
||||
typedef T result_type;
|
||||
|
||||
sph_bessel_j_small_z_series_term(unsigned v_, T x)
|
||||
: N(0), v(v_)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
mult = x / 2;
|
||||
term = pow(mult, T(v)) / boost::math::tgamma(v+1+T(0.5f), Policy());
|
||||
mult *= -mult;
|
||||
}
|
||||
T operator()()
|
||||
{
|
||||
T r = term;
|
||||
++N;
|
||||
term *= mult / (N * T(N + v + 0.5f));
|
||||
return r;
|
||||
}
|
||||
private:
|
||||
unsigned N;
|
||||
unsigned v;
|
||||
T mult;
|
||||
T term;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T bessel_j_small_z_series(T v, T x, const Policy& pol)
|
||||
{
|
||||
bessel_j_small_z_series_term<T, Policy> s(v, x);
|
||||
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
||||
#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(tools::real_cast<int>(v) & 1)
|
||||
r = -r;
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got x = %1%, but we need x >= 0", x, pol);
|
||||
}
|
||||
if(x == 0)
|
||||
return (v == 0) ? 1 : (v > 0) ? 0 :
|
||||
policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got v = %1%, but require v >= 0 or a negative integer: the result would be complex.", v, pol);
|
||||
|
||||
|
||||
if((v >= 0) && ((x < 1) || (v > x * x / 4)))
|
||||
{
|
||||
return bessel_j_small_z_series(v, x, pol);
|
||||
}
|
||||
|
||||
T j, y;
|
||||
bessel_jy(v, x, &j, &y, need_j, pol);
|
||||
return j;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_bessel_j_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names.
|
||||
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
|
||||
if((fabs(v) < 200) && (floor(v) == v))
|
||||
{
|
||||
if(fabs(x) > asymptotic_bessel_j_limit<T>(v, tag_type()))
|
||||
return asymptotic_bessel_j_large_x_2(v, x);
|
||||
else
|
||||
return bessel_jn(tools::real_cast<int>(v), x, pol);
|
||||
}
|
||||
return cyl_bessel_j_imp(v, x, bessel_no_int_tag(), pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_bessel_j_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
|
||||
if(fabs(x) > asymptotic_bessel_j_limit<T>(abs(v), tag_type()))
|
||||
{
|
||||
T r = asymptotic_bessel_j_large_x_2(static_cast<T>(abs(v)), x);
|
||||
if((v < 0) && (v & 1))
|
||||
r = -r;
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return bessel_jn(v, x, pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T sph_bessel_j_imp(unsigned n, T x, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
if(x < 0)
|
||||
return policies::raise_domain_error<T>(
|
||||
"boost::math::sph_bessel_j<%1%>(%1%,%1%)",
|
||||
"Got x = %1%, but function requires x > 0.", x, pol);
|
||||
//
|
||||
// Special case, n == 0 resolves down to the sinus cardinal of x:
|
||||
//
|
||||
if(n == 0)
|
||||
return boost::math::sinc_pi(x, pol);
|
||||
//
|
||||
// When x is small we may end up with 0/0, use series evaluation
|
||||
// instead, especially as it converges rapidly:
|
||||
//
|
||||
if(x < 1)
|
||||
return sph_bessel_j_small_z_series(n, x, pol);
|
||||
//
|
||||
// Default case is just a naive evaluation of the definition:
|
||||
//
|
||||
return sqrt(constants::pi<T>() / (2 * x))
|
||||
* cyl_bessel_j_imp(T(n)+T(0.5f), x, bessel_no_int_tag(), pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T cyl_bessel_i_imp(T v, T x, const Policy& pol)
|
||||
{
|
||||
//
|
||||
// This handles all the bessel I functions, note that we don't optimise
|
||||
// for integer v, other than the v = 0 or 1 special cases, as Millers
|
||||
// algorithm is at least as inefficient as the general case (the general
|
||||
// case has better error handling too).
|
||||
//
|
||||
BOOST_MATH_STD_USING
|
||||
if(x < 0)
|
||||
{
|
||||
// better have integer v:
|
||||
if(floor(v) == v)
|
||||
{
|
||||
T r = cyl_bessel_i_imp(v, -x, pol);
|
||||
if(tools::real_cast<int>(v) & 1)
|
||||
r = -r;
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return policies::raise_domain_error<T>(
|
||||
"boost::math::cyl_bessel_i<%1%>(%1%,%1%)",
|
||||
"Got x = %1%, but we need x >= 0", x, pol);
|
||||
}
|
||||
if(x == 0)
|
||||
{
|
||||
return (v == 0) ? 1 : 0;
|
||||
}
|
||||
if(v == 0.5f)
|
||||
{
|
||||
// common special case, note try and avoid overflow in exp(x):
|
||||
T e = exp(x / 2);
|
||||
return e * (e / sqrt(2 * x * constants::pi<T>()));
|
||||
}
|
||||
if(policies::digits<T, Policy>() <= 64)
|
||||
{
|
||||
if(v == 0)
|
||||
{
|
||||
return bessel_i0(x);
|
||||
}
|
||||
if(v == 1)
|
||||
{
|
||||
return bessel_i1(x);
|
||||
}
|
||||
}
|
||||
T I, K;
|
||||
bessel_ik(v, x, &I, &K, need_i, pol);
|
||||
return I;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_bessel_k_imp(T v, T x, const bessel_no_int_tag& /* t */, const Policy& pol)
|
||||
{
|
||||
static const char* function = "boost::math::cyl_bessel_k<%1%>(%1%,%1%)";
|
||||
BOOST_MATH_STD_USING
|
||||
if(x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got x = %1%, but we need x > 0", x, pol);
|
||||
}
|
||||
if(x == 0)
|
||||
{
|
||||
return (v == 0) ? policies::raise_overflow_error<T>(function, 0, pol)
|
||||
: policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got x = %1%, but we need x > 0", x, pol);
|
||||
}
|
||||
T I, K;
|
||||
bessel_ik(v, x, &I, &K, need_k, pol);
|
||||
return K;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_bessel_k_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
if((floor(v) == v))
|
||||
{
|
||||
return bessel_kn(tools::real_cast<int>(v), x, pol);
|
||||
}
|
||||
return cyl_bessel_k_imp(v, x, bessel_no_int_tag(), pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_bessel_k_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
|
||||
{
|
||||
return bessel_kn(v, x, pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_neumann_imp(T v, T x, const bessel_no_int_tag&, const Policy& pol)
|
||||
{
|
||||
static const char* function = "boost::math::cyl_neumann<%1%>(%1%,%1%)";
|
||||
if(x <= 0)
|
||||
{
|
||||
return (v == 0) && (x == 0) ?
|
||||
policies::raise_overflow_error<T>(function, 0, pol)
|
||||
: policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got x = %1%, but result is complex for x <= 0", x, pol);
|
||||
}
|
||||
T j, y;
|
||||
bessel_jy(v, x, &j, &y, need_y, pol);
|
||||
//
|
||||
// Post evaluation check for internal overflow during evaluation,
|
||||
// can occur when x is small and v is large, in which case the result
|
||||
// is -INF:
|
||||
//
|
||||
if(!(boost::math::isfinite)(y))
|
||||
return -policies::raise_overflow_error<T>(function, 0, pol);
|
||||
return y;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_neumann_imp(T v, T x, const bessel_maybe_int_tag&, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
|
||||
if(floor(v) == v)
|
||||
{
|
||||
if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
|
||||
{
|
||||
T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
|
||||
if((v < 0) && (tools::real_cast<int>(v) & 1))
|
||||
r = -r;
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return bessel_yn(tools::real_cast<int>(v), x, pol);
|
||||
}
|
||||
return cyl_neumann_imp<T>(v, x, bessel_no_int_tag(), pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T cyl_neumann_imp(int v, T x, const bessel_int_tag&, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
|
||||
if((fabs(x) > asymptotic_bessel_y_limit<T>(tag_type())) && (fabs(x) > 5 * abs(v)))
|
||||
{
|
||||
T r = asymptotic_bessel_y_large_x_2(static_cast<T>(abs(v)), x);
|
||||
if((v < 0) && (v & 1))
|
||||
r = -r;
|
||||
return r;
|
||||
}
|
||||
else
|
||||
return bessel_yn(tools::real_cast<int>(v), x, pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T sph_neumann_imp(unsigned v, T x, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
static const char* function = "boost::math::sph_neumann<%1%>(%1%,%1%)";
|
||||
//
|
||||
// Nothing much to do here but check for errors, and
|
||||
// evaluate the function's definition directly:
|
||||
//
|
||||
if(x < 0)
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got x = %1%, but function requires x > 0.", x, pol);
|
||||
|
||||
if(x < 2 * tools::min_value<T>())
|
||||
return -policies::raise_overflow_error<T>(function, 0, pol);
|
||||
|
||||
T result = cyl_neumann_imp(T(v)+0.5f, x, bessel_no_int_tag(), pol);
|
||||
T tx = sqrt(constants::pi<T>() / (2 * x));
|
||||
|
||||
if((tx > 1) && (tools::max_value<T>() / tx < result))
|
||||
return -policies::raise_overflow_error<T>(function, 0, pol);
|
||||
|
||||
return result * tx;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_j(T1 v, T2 x, const Policy& pol)
|
||||
{
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
|
||||
typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_j_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_bessel_j<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_j(T1 v, T2 x)
|
||||
{
|
||||
return cyl_bessel_j(v, x, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename detail::bessel_traits<T, T, Policy>::result_type sph_bessel(unsigned v, T x, const Policy& pol)
|
||||
{
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename detail::bessel_traits<T, T, Policy>::result_type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_bessel_j_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::sph_bessel<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_bessel(unsigned v, T x)
|
||||
{
|
||||
return sph_bessel(v, x, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_i(T1 v, T2 x, const Policy& pol)
|
||||
{
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_i_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::cyl_bessel_i<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_i(T1 v, T2 x)
|
||||
{
|
||||
return cyl_bessel_i(v, x, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_k(T1 v, T2 x, const Policy& pol)
|
||||
{
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
|
||||
typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_bessel_k_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_bessel_k<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_k(T1 v, T2 x)
|
||||
{
|
||||
return cyl_bessel_k(v, x, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_neumann(T1 v, T2 x, const Policy& pol)
|
||||
{
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename detail::bessel_traits<T1, T2, Policy>::result_type result_type;
|
||||
typedef typename detail::bessel_traits<T1, T2, Policy>::optimisation_tag tag_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::cyl_neumann_imp<value_type>(v, static_cast<value_type>(x), tag_type(), pol), "boost::math::cyl_neumann<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_neumann(T1 v, T2 x)
|
||||
{
|
||||
return cyl_neumann(v, x, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename detail::bessel_traits<T, T, Policy>::result_type sph_neumann(unsigned v, T x, const Policy& pol)
|
||||
{
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename detail::bessel_traits<T, T, Policy>::result_type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::sph_neumann_imp<value_type>(v, static_cast<value_type>(x), pol), "boost::math::sph_neumann<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_neumann(unsigned v, T x)
|
||||
{
|
||||
return sph_neumann(v, x, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_HPP
|
||||
1350
include/boost/math/special_functions/beta.hpp
Normal file
1350
include/boost/math/special_functions/beta.hpp
Normal file
File diff suppressed because it is too large
Load Diff
75
include/boost/math/special_functions/binomial.hpp
Normal file
75
include/boost/math/special_functions/binomial.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SF_BINOMIAL_HPP
|
||||
#define BOOST_MATH_SF_BINOMIAL_HPP
|
||||
|
||||
#include <boost/math/special_functions/factorials.hpp>
|
||||
#include <boost/math/special_functions/beta.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
template <class T, class Policy>
|
||||
T binomial_coefficient(unsigned n, unsigned k, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
static const char* function = "boost::math::binomial_coefficient<%1%>(unsigned, unsigned)";
|
||||
if(k > n)
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"The binomial coefficient is undefined for k > n, but got k = %1%.",
|
||||
k, pol);
|
||||
T result;
|
||||
if((k == 0) || (k == n))
|
||||
return 1;
|
||||
if((k == 1) || (k == n-1))
|
||||
return n;
|
||||
|
||||
if(n <= max_factorial<T>::value)
|
||||
{
|
||||
// Use fast table lookup:
|
||||
result = unchecked_factorial<T>(n);
|
||||
result /= unchecked_factorial<T>(n-k);
|
||||
result /= unchecked_factorial<T>(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the beta function:
|
||||
if(k < n - k)
|
||||
result = k * beta(static_cast<T>(k), static_cast<T>(n-k+1), pol);
|
||||
else
|
||||
result = (n - k) * beta(static_cast<T>(k+1), static_cast<T>(n-k), pol);
|
||||
if(result == 0)
|
||||
return policies::raise_overflow_error<T>(function, 0, pol);
|
||||
result = 1 / result;
|
||||
}
|
||||
// convert to nearest integer:
|
||||
return ceil(result - 0.5f);
|
||||
}
|
||||
//
|
||||
// Type float can only store the first 35 factorials, in order to
|
||||
// increase the chance that we can use a table driven implementation
|
||||
// we'll promote to double:
|
||||
//
|
||||
template <>
|
||||
inline float binomial_coefficient<float, policies::policy<> >(unsigned n, unsigned k, const policies::policy<>& pol)
|
||||
{
|
||||
return policies::checked_narrowing_cast<float, policies::policy<> >(binomial_coefficient<double>(n, k, pol), "boost::math::binomial_coefficient<%1%>(unsigned,unsigned)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T binomial_coefficient(unsigned n, unsigned k)
|
||||
{
|
||||
return binomial_coefficient<T>(n, k, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_MATH_SF_BINOMIAL_HPP
|
||||
|
||||
|
||||
72
include/boost/math/special_functions/cbrt.hpp
Normal file
72
include/boost/math/special_functions/cbrt.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SF_CBRT_HPP
|
||||
#define BOOST_MATH_SF_CBRT_HPP
|
||||
|
||||
#include <boost/math/tools/roots.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class T>
|
||||
struct cbrt_functor
|
||||
{
|
||||
cbrt_functor(T const& target) : a(target){}
|
||||
std::tr1::tuple<T, T, T> operator()(T const& z)
|
||||
{
|
||||
T sqr = z * z;
|
||||
return std::tr1::make_tuple(sqr * z - a, 3 * sqr, 6 * z);
|
||||
}
|
||||
private:
|
||||
T a;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
T cbrt_imp(T z, const Policy&)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
int i_exp, sign(1);
|
||||
if(z < 0)
|
||||
{
|
||||
z = -z;
|
||||
sign = -sign;
|
||||
}
|
||||
if(z == 0)
|
||||
return 0;
|
||||
|
||||
frexp(z, &i_exp);
|
||||
T min = static_cast<T>(ldexp(0.5, i_exp/3));
|
||||
T max = static_cast<T>(ldexp(2.0, i_exp/3));
|
||||
T guess = static_cast<T>(ldexp(1.0, i_exp/3));
|
||||
int digits = (policies::digits<T, Policy>()) / 2;
|
||||
return sign * tools::halley_iterate(detail::cbrt_functor<T>(z), guess, min, max, digits);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type cbrt(T z, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::cbrt_imp(result_type(z), pol);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type cbrt(T z)
|
||||
{
|
||||
return cbrt(z, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SF_CBRT_HPP
|
||||
|
||||
|
||||
|
||||
64
include/boost/math/special_functions/cos_pi.hpp
Normal file
64
include/boost/math/special_functions/cos_pi.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2007 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_COS_PI_HPP
|
||||
#define BOOST_MATH_COS_PI_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/real_cast.hpp>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
template <class T>
|
||||
T cos_pi_imp(T x)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
// cos of pi*x:
|
||||
bool invert = false;
|
||||
if(x < 0.5)
|
||||
return cos(constants::pi<T>() * x);
|
||||
if(x < 1)
|
||||
{
|
||||
x = -x;
|
||||
}
|
||||
|
||||
T rem = floor(x);
|
||||
if(tools::real_cast<int>(rem) & 1)
|
||||
invert = !invert;
|
||||
rem = x - rem;
|
||||
if(rem > 0.5f)
|
||||
{
|
||||
rem = 1 - rem;
|
||||
invert = !invert;
|
||||
}
|
||||
if(rem == 0.5f)
|
||||
return 0;
|
||||
|
||||
rem = cos(constants::pi<T>() * rem);
|
||||
return invert ? -rem : rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type cos_pi(T x, const Policy&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return boost::math::detail::cos_pi_imp<result_type>(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type cos_pi(T x)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return boost::math::detail::cos_pi_imp<result_type>(x);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
#endif
|
||||
96
include/boost/math/special_functions/detail/bessel_i0.hpp
Normal file
96
include/boost/math/special_functions/detail/bessel_i0.hpp
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_I0_HPP
|
||||
#define BOOST_MATH_BESSEL_I0_HPP
|
||||
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Modified Bessel function of the first kind of order zero
|
||||
// minimax rational approximations on intervals, see
|
||||
// Blair and Edwards, Chalk River Report AECL-4928, 1974
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T>
|
||||
T bessel_i0(T x)
|
||||
{
|
||||
static const T P1[] = {
|
||||
static_cast<T>(-2.2335582639474375249e+15L),
|
||||
static_cast<T>(-5.5050369673018427753e+14L),
|
||||
static_cast<T>(-3.2940087627407749166e+13L),
|
||||
static_cast<T>(-8.4925101247114157499e+11L),
|
||||
static_cast<T>(-1.1912746104985237192e+10L),
|
||||
static_cast<T>(-1.0313066708737980747e+08L),
|
||||
static_cast<T>(-5.9545626019847898221e+05L),
|
||||
static_cast<T>(-2.4125195876041896775e+03L),
|
||||
static_cast<T>(-7.0935347449210549190e+00L),
|
||||
static_cast<T>(-1.5453977791786851041e-02L),
|
||||
static_cast<T>(-2.5172644670688975051e-05L),
|
||||
static_cast<T>(-3.0517226450451067446e-08L),
|
||||
static_cast<T>(-2.6843448573468483278e-11L),
|
||||
static_cast<T>(-1.5982226675653184646e-14L),
|
||||
static_cast<T>(-5.2487866627945699800e-18L),
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(-2.2335582639474375245e+15L),
|
||||
static_cast<T>(7.8858692566751002988e+12L),
|
||||
static_cast<T>(-1.2207067397808979846e+10L),
|
||||
static_cast<T>(1.0377081058062166144e+07L),
|
||||
static_cast<T>(-4.8527560179962773045e+03L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(-2.2210262233306573296e-04L),
|
||||
static_cast<T>(1.3067392038106924055e-02L),
|
||||
static_cast<T>(-4.4700805721174453923e-01L),
|
||||
static_cast<T>(5.5674518371240761397e+00L),
|
||||
static_cast<T>(-2.3517945679239481621e+01L),
|
||||
static_cast<T>(3.1611322818701131207e+01L),
|
||||
static_cast<T>(-9.6090021968656180000e+00L),
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(-5.5194330231005480228e-04L),
|
||||
static_cast<T>(3.2547697594819615062e-02L),
|
||||
static_cast<T>(-1.1151759188741312645e+00L),
|
||||
static_cast<T>(1.3982595353892851542e+01L),
|
||||
static_cast<T>(-6.0228002066743340583e+01L),
|
||||
static_cast<T>(8.5539563258012929600e+01L),
|
||||
static_cast<T>(-3.1446690275135491500e+01L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
T value, factor, r;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
x = -x; // even function
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
return static_cast<T>(1);
|
||||
}
|
||||
if (x <= 15) // x in (0, 15]
|
||||
{
|
||||
T y = x * x;
|
||||
value = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
|
||||
}
|
||||
else // x in (15, \infty)
|
||||
{
|
||||
T y = 1 / x - T(1) / 15;
|
||||
r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
|
||||
factor = exp(x) / sqrt(x);
|
||||
value = factor * r;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_I0_HPP
|
||||
99
include/boost/math/special_functions/detail/bessel_i1.hpp
Normal file
99
include/boost/math/special_functions/detail/bessel_i1.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_I1_HPP
|
||||
#define BOOST_MATH_BESSEL_I1_HPP
|
||||
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Modified Bessel function of the first kind of order one
|
||||
// minimax rational approximations on intervals, see
|
||||
// Blair and Edwards, Chalk River Report AECL-4928, 1974
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T>
|
||||
T bessel_i1(T x)
|
||||
{
|
||||
static const T P1[] = {
|
||||
static_cast<T>(-1.4577180278143463643e+15L),
|
||||
static_cast<T>(-1.7732037840791591320e+14L),
|
||||
static_cast<T>(-6.9876779648010090070e+12L),
|
||||
static_cast<T>(-1.3357437682275493024e+11L),
|
||||
static_cast<T>(-1.4828267606612366099e+09L),
|
||||
static_cast<T>(-1.0588550724769347106e+07L),
|
||||
static_cast<T>(-5.1894091982308017540e+04L),
|
||||
static_cast<T>(-1.8225946631657315931e+02L),
|
||||
static_cast<T>(-4.7207090827310162436e-01L),
|
||||
static_cast<T>(-9.1746443287817501309e-04L),
|
||||
static_cast<T>(-1.3466829827635152875e-06L),
|
||||
static_cast<T>(-1.4831904935994647675e-09L),
|
||||
static_cast<T>(-1.1928788903603238754e-12L),
|
||||
static_cast<T>(-6.5245515583151902910e-16L),
|
||||
static_cast<T>(-1.9705291802535139930e-19L),
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(-2.9154360556286927285e+15L),
|
||||
static_cast<T>(9.7887501377547640438e+12L),
|
||||
static_cast<T>(-1.4386907088588283434e+10L),
|
||||
static_cast<T>(1.1594225856856884006e+07L),
|
||||
static_cast<T>(-5.1326864679904189920e+03L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(1.4582087408985668208e-05L),
|
||||
static_cast<T>(-8.9359825138577646443e-04L),
|
||||
static_cast<T>(2.9204895411257790122e-02L),
|
||||
static_cast<T>(-3.4198728018058047439e-01L),
|
||||
static_cast<T>(1.3960118277609544334e+00L),
|
||||
static_cast<T>(-1.9746376087200685843e+00L),
|
||||
static_cast<T>(8.5591872901933459000e-01L),
|
||||
static_cast<T>(-6.0437159056137599999e-02L),
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(3.7510433111922824643e-05L),
|
||||
static_cast<T>(-2.2835624489492512649e-03L),
|
||||
static_cast<T>(7.4212010813186530069e-02L),
|
||||
static_cast<T>(-8.5017476463217924408e-01L),
|
||||
static_cast<T>(3.2593714889036996297e+00L),
|
||||
static_cast<T>(-3.8806586721556593450e+00L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
T value, factor, r, w;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
w = abs(x);
|
||||
if (x == 0)
|
||||
{
|
||||
return static_cast<T>(0);
|
||||
}
|
||||
if (w <= 15) // w in (0, 15]
|
||||
{
|
||||
T y = x * x;
|
||||
r = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
|
||||
factor = w;
|
||||
value = factor * r;
|
||||
}
|
||||
else // w in (15, \infty)
|
||||
{
|
||||
T y = 1 / w - T(1) / 15;
|
||||
r = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
|
||||
factor = exp(w) / sqrt(w);
|
||||
value = factor * r;
|
||||
}
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
value *= -value; // odd function
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_I1_HPP
|
||||
331
include/boost/math/special_functions/detail/bessel_ik.hpp
Normal file
331
include/boost/math/special_functions/detail/bessel_ik.hpp
Normal file
@@ -0,0 +1,331 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_IK_HPP
|
||||
#define BOOST_MATH_BESSEL_IK_HPP
|
||||
|
||||
#include <boost/math/special_functions/gamma.hpp>
|
||||
#include <boost/math/special_functions/sin_pi.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
|
||||
// Modified Bessel functions of the first and second kind of fractional order
|
||||
|
||||
namespace boost { namespace math {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Calculate K(v, x) and K(v+1, x) by method analogous to
|
||||
// Temme, Journal of Computational Physics, vol 21, 343 (1976)
|
||||
template <typename T, typename Policy>
|
||||
int temme_ik(T v, T x, T* K, T* K1, const Policy& pol)
|
||||
{
|
||||
T f, h, p, q, coef, sum, sum1, tolerance;
|
||||
T a, b, c, d, sigma, gamma1, gamma2;
|
||||
unsigned long k;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
using namespace boost::math::constants;
|
||||
|
||||
|
||||
// |x| <= 2, Temme series converge rapidly
|
||||
// |x| > 2, the larger the |x|, the slower the convergence
|
||||
BOOST_ASSERT(abs(x) <= 2);
|
||||
BOOST_ASSERT(abs(v) <= 0.5f);
|
||||
|
||||
T gp = 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 = tools::real_cast<unsigned>(v + 0.5f);
|
||||
u = v - n; // -1/2 <= u < 1/2
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(n);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(u);
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
*I = *K = policies::raise_domain_error<T>(function,
|
||||
"Got x = %1% but real argument x must be non-negative, complex number result not supported.", x, pol);
|
||||
return 1;
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
Iv = (v == 0) ? static_cast<T>(1) : static_cast<T>(0);
|
||||
if(kind & need_k)
|
||||
{
|
||||
Kv = policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
else
|
||||
{
|
||||
Kv = std::numeric_limits<T>::quiet_NaN(); // any value will do
|
||||
}
|
||||
|
||||
if(reflect && (kind & need_i))
|
||||
{
|
||||
T z = (u + n % 2);
|
||||
Iv = 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
|
||||
147
include/boost/math/special_functions/detail/bessel_j0.hpp
Normal file
147
include/boost/math/special_functions/detail/bessel_j0.hpp
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_J0_HPP
|
||||
#define BOOST_MATH_BESSEL_J0_HPP
|
||||
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Bessel function of the first kind of order zero
|
||||
// x <= 8, minimax rational approximations on root-bracketing intervals
|
||||
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T>
|
||||
T bessel_j0(T x)
|
||||
{
|
||||
static const T P1[] = {
|
||||
static_cast<T>(-4.1298668500990866786e+11L),
|
||||
static_cast<T>(2.7282507878605942706e+10L),
|
||||
static_cast<T>(-6.2140700423540120665e+08L),
|
||||
static_cast<T>(6.6302997904833794242e+06L),
|
||||
static_cast<T>(-3.6629814655107086448e+04L),
|
||||
static_cast<T>(1.0344222815443188943e+02L),
|
||||
static_cast<T>(-1.2117036164593528341e-01L)
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(2.3883787996332290397e+12L),
|
||||
static_cast<T>(2.6328198300859648632e+10L),
|
||||
static_cast<T>(1.3985097372263433271e+08L),
|
||||
static_cast<T>(4.5612696224219938200e+05L),
|
||||
static_cast<T>(9.3614022392337710626e+02L),
|
||||
static_cast<T>(1.0L),
|
||||
static_cast<T>(0.0L)
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(-1.8319397969392084011e+03L),
|
||||
static_cast<T>(-1.2254078161378989535e+04L),
|
||||
static_cast<T>(-7.2879702464464618998e+03L),
|
||||
static_cast<T>(1.0341910641583726701e+04L),
|
||||
static_cast<T>(1.1725046279757103576e+04L),
|
||||
static_cast<T>(4.4176707025325087628e+03L),
|
||||
static_cast<T>(7.4321196680624245801e+02L),
|
||||
static_cast<T>(4.8591703355916499363e+01L)
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(-3.5783478026152301072e+05L),
|
||||
static_cast<T>(2.4599102262586308984e+05L),
|
||||
static_cast<T>(-8.4055062591169562211e+04L),
|
||||
static_cast<T>(1.8680990008359188352e+04L),
|
||||
static_cast<T>(-2.9458766545509337327e+03L),
|
||||
static_cast<T>(3.3307310774649071172e+02L),
|
||||
static_cast<T>(-2.5258076240801555057e+01L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T PC[] = {
|
||||
static_cast<T>(2.2779090197304684302e+04L),
|
||||
static_cast<T>(4.1345386639580765797e+04L),
|
||||
static_cast<T>(2.1170523380864944322e+04L),
|
||||
static_cast<T>(3.4806486443249270347e+03L),
|
||||
static_cast<T>(1.5376201909008354296e+02L),
|
||||
static_cast<T>(8.8961548424210455236e-01L)
|
||||
};
|
||||
static const T QC[] = {
|
||||
static_cast<T>(2.2779090197304684318e+04L),
|
||||
static_cast<T>(4.1370412495510416640e+04L),
|
||||
static_cast<T>(2.1215350561880115730e+04L),
|
||||
static_cast<T>(3.5028735138235608207e+03L),
|
||||
static_cast<T>(1.5711159858080893649e+02L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T PS[] = {
|
||||
static_cast<T>(-8.9226600200800094098e+01L),
|
||||
static_cast<T>(-1.8591953644342993800e+02L),
|
||||
static_cast<T>(-1.1183429920482737611e+02L),
|
||||
static_cast<T>(-2.2300261666214198472e+01L),
|
||||
static_cast<T>(-1.2441026745835638459e+00L),
|
||||
static_cast<T>(-8.8033303048680751817e-03L)
|
||||
};
|
||||
static const T QS[] = {
|
||||
static_cast<T>(5.7105024128512061905e+03L),
|
||||
static_cast<T>(1.1951131543434613647e+04L),
|
||||
static_cast<T>(7.2642780169211018836e+03L),
|
||||
static_cast<T>(1.4887231232283756582e+03L),
|
||||
static_cast<T>(9.0593769594993125859e+01L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T x1 = static_cast<T>(2.4048255576957727686e+00L),
|
||||
x2 = static_cast<T>(5.5200781102863106496e+00L),
|
||||
x11 = static_cast<T>(6.160e+02L),
|
||||
x12 = static_cast<T>(-1.42444230422723137837e-03L),
|
||||
x21 = static_cast<T>(1.4130e+03L),
|
||||
x22 = static_cast<T>(5.46860286310649596604e-04L);
|
||||
|
||||
T value, factor, r, rc, rs;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
using namespace boost::math::constants;
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
x = -x; // even function
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
return static_cast<T>(1);
|
||||
}
|
||||
if (x <= 4) // x in (0, 4]
|
||||
{
|
||||
T y = x * x;
|
||||
BOOST_ASSERT(sizeof(P1) == sizeof(Q1));
|
||||
r = evaluate_rational(P1, Q1, y);
|
||||
factor = (x + x1) * ((x - x11/256) - x12);
|
||||
value = factor * r;
|
||||
}
|
||||
else if (x <= 8.0) // x in (4, 8]
|
||||
{
|
||||
T y = 1 - (x * x)/64;
|
||||
BOOST_ASSERT(sizeof(P2) == sizeof(Q2));
|
||||
r = evaluate_rational(P2, Q2, y);
|
||||
factor = (x + x2) * ((x - x21/256) - x22);
|
||||
value = factor * r;
|
||||
}
|
||||
else // x in (8, \infty)
|
||||
{
|
||||
T y = 8 / x;
|
||||
T y2 = y * y;
|
||||
T z = x - 0.25f * pi<T>();
|
||||
BOOST_ASSERT(sizeof(PC) == sizeof(QC));
|
||||
BOOST_ASSERT(sizeof(PS) == sizeof(QS));
|
||||
rc = evaluate_rational(PC, QC, y2);
|
||||
rs = evaluate_rational(PS, QS, y2);
|
||||
factor = sqrt(2 / (x * pi<T>()));
|
||||
value = factor * (rc * cos(z) - y * rs * sin(z));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_J0_HPP
|
||||
152
include/boost/math/special_functions/detail/bessel_j1.hpp
Normal file
152
include/boost/math/special_functions/detail/bessel_j1.hpp
Normal 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_J1_HPP
|
||||
#define BOOST_MATH_BESSEL_J1_HPP
|
||||
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Bessel function of the first kind of order one
|
||||
// x <= 8, minimax rational approximations on root-bracketing intervals
|
||||
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
|
||||
|
||||
namespace boost { namespace math{ namespace detail{
|
||||
|
||||
template <typename T>
|
||||
T bessel_j1(T x)
|
||||
{
|
||||
static const T P1[] = {
|
||||
static_cast<T>(-1.4258509801366645672e+11L),
|
||||
static_cast<T>(6.6781041261492395835e+09L),
|
||||
static_cast<T>(-1.1548696764841276794e+08L),
|
||||
static_cast<T>(9.8062904098958257677e+05L),
|
||||
static_cast<T>(-4.4615792982775076130e+03L),
|
||||
static_cast<T>(1.0650724020080236441e+01L),
|
||||
static_cast<T>(-1.0767857011487300348e-02L)
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(4.1868604460820175290e+12L),
|
||||
static_cast<T>(4.2091902282580133541e+10L),
|
||||
static_cast<T>(2.0228375140097033958e+08L),
|
||||
static_cast<T>(5.9117614494174794095e+05L),
|
||||
static_cast<T>(1.0742272239517380498e+03L),
|
||||
static_cast<T>(1.0L),
|
||||
static_cast<T>(0.0L)
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(-1.7527881995806511112e+16L),
|
||||
static_cast<T>(1.6608531731299018674e+15L),
|
||||
static_cast<T>(-3.6658018905416665164e+13L),
|
||||
static_cast<T>(3.5580665670910619166e+11L),
|
||||
static_cast<T>(-1.8113931269860667829e+09L),
|
||||
static_cast<T>(5.0793266148011179143e+06L),
|
||||
static_cast<T>(-7.5023342220781607561e+03L),
|
||||
static_cast<T>(4.6179191852758252278e+00L)
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(1.7253905888447681194e+18L),
|
||||
static_cast<T>(1.7128800897135812012e+16L),
|
||||
static_cast<T>(8.4899346165481429307e+13L),
|
||||
static_cast<T>(2.7622777286244082666e+11L),
|
||||
static_cast<T>(6.4872502899596389593e+08L),
|
||||
static_cast<T>(1.1267125065029138050e+06L),
|
||||
static_cast<T>(1.3886978985861357615e+03L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T PC[] = {
|
||||
static_cast<T>(-4.4357578167941278571e+06L),
|
||||
static_cast<T>(-9.9422465050776411957e+06L),
|
||||
static_cast<T>(-6.6033732483649391093e+06L),
|
||||
static_cast<T>(-1.5235293511811373833e+06L),
|
||||
static_cast<T>(-1.0982405543459346727e+05L),
|
||||
static_cast<T>(-1.6116166443246101165e+03L),
|
||||
static_cast<T>(0.0L)
|
||||
};
|
||||
static const T QC[] = {
|
||||
static_cast<T>(-4.4357578167941278568e+06L),
|
||||
static_cast<T>(-9.9341243899345856590e+06L),
|
||||
static_cast<T>(-6.5853394797230870728e+06L),
|
||||
static_cast<T>(-1.5118095066341608816e+06L),
|
||||
static_cast<T>(-1.0726385991103820119e+05L),
|
||||
static_cast<T>(-1.4550094401904961825e+03L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T PS[] = {
|
||||
static_cast<T>(3.3220913409857223519e+04L),
|
||||
static_cast<T>(8.5145160675335701966e+04L),
|
||||
static_cast<T>(6.6178836581270835179e+04L),
|
||||
static_cast<T>(1.8494262873223866797e+04L),
|
||||
static_cast<T>(1.7063754290207680021e+03L),
|
||||
static_cast<T>(3.5265133846636032186e+01L),
|
||||
static_cast<T>(0.0L)
|
||||
};
|
||||
static const T QS[] = {
|
||||
static_cast<T>(7.0871281941028743574e+05L),
|
||||
static_cast<T>(1.8194580422439972989e+06L),
|
||||
static_cast<T>(1.4194606696037208929e+06L),
|
||||
static_cast<T>(4.0029443582266975117e+05L),
|
||||
static_cast<T>(3.7890229745772202641e+04L),
|
||||
static_cast<T>(8.6383677696049909675e+02L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T x1 = static_cast<T>(3.8317059702075123156e+00L),
|
||||
x2 = static_cast<T>(7.0155866698156187535e+00L),
|
||||
x11 = static_cast<T>(9.810e+02L),
|
||||
x12 = static_cast<T>(-3.2527979248768438556e-04L),
|
||||
x21 = static_cast<T>(1.7960e+03L),
|
||||
x22 = static_cast<T>(-3.8330184381246462950e-05L);
|
||||
|
||||
T value, factor, r, rc, rs, w;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
using namespace boost::math::constants;
|
||||
|
||||
w = abs(x);
|
||||
if (x == 0)
|
||||
{
|
||||
return static_cast<T>(0);
|
||||
}
|
||||
if (w <= 4) // w in (0, 4]
|
||||
{
|
||||
T y = x * x;
|
||||
BOOST_ASSERT(sizeof(P1) == sizeof(Q1));
|
||||
r = evaluate_rational(P1, Q1, y);
|
||||
factor = w * (w + x1) * ((w - x11/256) - x12);
|
||||
value = factor * r;
|
||||
}
|
||||
else if (w <= 8) // w in (4, 8]
|
||||
{
|
||||
T y = x * x;
|
||||
BOOST_ASSERT(sizeof(P2) == sizeof(Q2));
|
||||
r = evaluate_rational(P2, Q2, y);
|
||||
factor = w * (w + x2) * ((w - x21/256) - x22);
|
||||
value = factor * r;
|
||||
}
|
||||
else // w in (8, \infty)
|
||||
{
|
||||
T y = 8 / w;
|
||||
T y2 = y * y;
|
||||
T z = w - 0.75f * pi<T>();
|
||||
BOOST_ASSERT(sizeof(PC) == sizeof(QC));
|
||||
BOOST_ASSERT(sizeof(PS) == sizeof(QS));
|
||||
rc = evaluate_rational(PC, QC, y2);
|
||||
rs = evaluate_rational(PS, QS, y2);
|
||||
factor = sqrt(2 / (w * pi<T>()));
|
||||
value = factor * (rc * cos(z) - y * rs * sin(z));
|
||||
}
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
value *= -1; // odd function
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_J1_HPP
|
||||
86
include/boost/math/special_functions/detail/bessel_jn.hpp
Normal file
86
include/boost/math/special_functions/detail/bessel_jn.hpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_JN_HPP
|
||||
#define BOOST_MATH_BESSEL_JN_HPP
|
||||
|
||||
#include <boost/math/special_functions/detail/bessel_j0.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_j1.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_jy.hpp>
|
||||
|
||||
// Bessel function of the first kind of integer order
|
||||
// J_n(z) is the minimal solution
|
||||
// n < abs(z), forward recurrence stable and usable
|
||||
// n >= abs(z), forward recurrence unstable, use Miller's algorithm
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T bessel_jn(int n, T x, const Policy& pol)
|
||||
{
|
||||
T value(0), factor, current, prev, next;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
return bessel_j0(x);
|
||||
}
|
||||
if (n == 1)
|
||||
{
|
||||
return bessel_j1(x);
|
||||
}
|
||||
if (n < 0)
|
||||
{
|
||||
factor = (n & 0x1) ? -1 : 1; // J_{-n}(z) = (-1)^n J_n(z)
|
||||
n = -n;
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = 1;
|
||||
}
|
||||
|
||||
if (x == 0) // n >= 2
|
||||
{
|
||||
return static_cast<T>(0);
|
||||
}
|
||||
|
||||
if (n < abs(x)) // forward recurrence
|
||||
{
|
||||
prev = bessel_j0(x);
|
||||
current = bessel_j1(x);
|
||||
for (int k = 1; k < n; k++)
|
||||
{
|
||||
value = 2 * k * current / x - prev;
|
||||
prev = current;
|
||||
current = value;
|
||||
}
|
||||
}
|
||||
else // backward recurrence
|
||||
{
|
||||
T fn; int s; // fn = J_(n+1) / J_n
|
||||
// |x| <= n, fast convergence for continued fraction CF1
|
||||
boost::math::detail::CF1_jy(static_cast<T>(n), x, &fn, &s, pol);
|
||||
// tiny initial value to prevent overflow
|
||||
T init = sqrt(tools::min_value<T>());
|
||||
prev = fn * init;
|
||||
current = init;
|
||||
for (int k = n; k > 0; k--)
|
||||
{
|
||||
next = 2 * k * current / x - prev;
|
||||
prev = current;
|
||||
current = next;
|
||||
}
|
||||
T ratio = init / current; // scaling ratio
|
||||
value = bessel_j0(x) * ratio; // normalization
|
||||
}
|
||||
value *= factor;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_JN_HPP
|
||||
361
include/boost/math/special_functions/detail/bessel_jy.hpp
Normal file
361
include/boost/math/special_functions/detail/bessel_jy.hpp
Normal file
@@ -0,0 +1,361 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_JY_HPP
|
||||
#define BOOST_MATH_BESSEL_JY_HPP
|
||||
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/special_functions/gamma.hpp>
|
||||
#include <boost/math/special_functions/sign.hpp>
|
||||
#include <boost/math/special_functions/hypot.hpp>
|
||||
#include <boost/math/special_functions/sin_pi.hpp>
|
||||
#include <boost/math/special_functions/cos_pi.hpp>
|
||||
#include <boost/math/special_functions/detail/simple_complex.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_jy_asym.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/type_traits/is_floating_point.hpp>
|
||||
#include <complex>
|
||||
|
||||
// Bessel functions of the first and second kind of fractional order
|
||||
|
||||
namespace boost { namespace math {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Calculate Y(v, x) and Y(v+1, x) by Temme's method, see
|
||||
// Temme, Journal of Computational Physics, vol 21, 343 (1976)
|
||||
template <typename T, typename Policy>
|
||||
int temme_jy(T v, T x, T* Y, T* Y1, const Policy& pol)
|
||||
{
|
||||
T g, h, p, q, f, coef, sum, sum1, tolerance;
|
||||
T a, d, e, sigma;
|
||||
unsigned long k;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
using namespace boost::math::constants;
|
||||
|
||||
BOOST_ASSERT(fabs(v) <= 0.5f); // precondition for using this routine
|
||||
|
||||
T gp = 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 = real_cast<unsigned>(v + 0.5L);
|
||||
u = v - n; // -1/2 <= u < 1/2
|
||||
|
||||
if (x == 0)
|
||||
{
|
||||
*J = *Y = policies::raise_overflow_error<T>(
|
||||
function, 0, pol);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// x is positive until reflection
|
||||
W = T(2) / (x * pi<T>()); // Wronskian
|
||||
if (x <= 2) // x in (0, 2]
|
||||
{
|
||||
if(temme_jy(u, x, &Yu, &Yu1, pol)) // Temme series
|
||||
{
|
||||
// domain error:
|
||||
*J = *Y = Yu;
|
||||
return 1;
|
||||
}
|
||||
prev = Yu;
|
||||
current = Yu1;
|
||||
for (k = 1; k <= n; k++) // forward recurrence for Y
|
||||
{
|
||||
next = 2 * (u + k) * current / x - prev;
|
||||
prev = current;
|
||||
current = next;
|
||||
}
|
||||
Yv = prev;
|
||||
Yv1 = current;
|
||||
if(kind&need_j)
|
||||
{
|
||||
CF1_jy(v, x, &fv, &s, pol); // continued fraction CF1_jy
|
||||
Jv = W / (Yv * fv - Yv1); // Wronskian relation
|
||||
}
|
||||
else
|
||||
Jv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
|
||||
}
|
||||
else // x in (2, \infty)
|
||||
{
|
||||
// Get Y(u, x):
|
||||
// define tag type that will dispatch to right limits:
|
||||
typedef typename bessel_asymptotic_tag<T, Policy>::type tag_type;
|
||||
|
||||
T lim;
|
||||
switch(kind)
|
||||
{
|
||||
case need_j:
|
||||
lim = asymptotic_bessel_j_limit<T>(v, tag_type());
|
||||
break;
|
||||
case need_y:
|
||||
lim = asymptotic_bessel_y_limit<T>(tag_type());
|
||||
break;
|
||||
default:
|
||||
lim = (std::max)(
|
||||
asymptotic_bessel_j_limit<T>(v, tag_type()),
|
||||
asymptotic_bessel_y_limit<T>(tag_type()));
|
||||
break;
|
||||
}
|
||||
if(x > lim)
|
||||
{
|
||||
if(kind&need_y)
|
||||
{
|
||||
Yu = asymptotic_bessel_y_large_x_2(u, x);
|
||||
Yu1 = asymptotic_bessel_y_large_x_2(u + 1, x);
|
||||
}
|
||||
else
|
||||
Yu = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
|
||||
if(kind&need_j)
|
||||
{
|
||||
Jv = asymptotic_bessel_j_large_x_2(v, x);
|
||||
}
|
||||
else
|
||||
Jv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
|
||||
}
|
||||
else
|
||||
{
|
||||
CF1_jy(v, x, &fv, &s, pol);
|
||||
// tiny initial value to prevent overflow
|
||||
T init = sqrt(tools::min_value<T>());
|
||||
prev = fv * s * init;
|
||||
current = s * init;
|
||||
for (k = n; k > 0; k--) // backward recurrence for J
|
||||
{
|
||||
next = 2 * (u + k) * current / x - prev;
|
||||
prev = current;
|
||||
current = next;
|
||||
}
|
||||
T ratio = (s * init) / current; // scaling ratio
|
||||
// can also call CF1_jy() to get fu, not much difference in precision
|
||||
fu = prev / current;
|
||||
CF2_jy(u, x, &p, &q, pol); // continued fraction CF2_jy
|
||||
T t = u / x - fu; // t = J'/J
|
||||
gamma = (p - t) / q;
|
||||
Ju = sign(current) * sqrt(W / (q + gamma * (p - t)));
|
||||
|
||||
Jv = Ju * ratio; // normalization
|
||||
|
||||
Yu = gamma * Ju;
|
||||
Yu1 = Yu * (u/x - p - q/gamma);
|
||||
}
|
||||
if(kind&need_y)
|
||||
{
|
||||
// compute Y:
|
||||
prev = Yu;
|
||||
current = Yu1;
|
||||
for (k = 1; k <= n; k++) // forward recurrence for Y
|
||||
{
|
||||
next = 2 * (u + k) * current / x - prev;
|
||||
prev = current;
|
||||
current = next;
|
||||
}
|
||||
Yv = prev;
|
||||
}
|
||||
else
|
||||
Yv = std::numeric_limits<T>::quiet_NaN(); // any value will do, we're not using it.
|
||||
}
|
||||
|
||||
if (reflect)
|
||||
{
|
||||
T z = (u + n % 2);
|
||||
*J = 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
|
||||
297
include/boost/math/special_functions/detail/bessel_jy_asym.hpp
Normal file
297
include/boost/math/special_functions/detail/bessel_jy_asym.hpp
Normal file
@@ -0,0 +1,297 @@
|
||||
// Copyright (c) 2007 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
//
|
||||
// This is a partial header, do not include on it's own!!!
|
||||
//
|
||||
// Contains asymptotic expansions for Bessel J(v,x) and Y(v,x)
|
||||
// functions, as x -> INF.
|
||||
//
|
||||
#ifndef BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
|
||||
#define BOOST_MATH_SF_DETAIL_BESSEL_JY_ASYM_HPP
|
||||
|
||||
#include <boost/math/special_functions/factorials.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_large_x_P(T v, T x)
|
||||
{
|
||||
// A&S 9.2.9
|
||||
T s = 1;
|
||||
T mu = 4 * v * v;
|
||||
T ez2 = 8 * x;
|
||||
ez2 *= ez2;
|
||||
s -= (mu-1) * (mu-9) / (2 * ez2);
|
||||
s += (mu-1) * (mu-9) * (mu-25) * (mu - 49) / (24 * ez2 * ez2);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_large_x_Q(T v, T x)
|
||||
{
|
||||
// A&S 9.2.10
|
||||
T s = 0;
|
||||
T mu = 4 * v * v;
|
||||
T ez = 8*x;
|
||||
s += (mu-1) / ez;
|
||||
s -= (mu-1) * (mu-9) * (mu-25) / (6 * ez*ez*ez);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_large_x(T v, T x)
|
||||
{
|
||||
//
|
||||
// See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
|
||||
//
|
||||
// Also A&S 9.2.5
|
||||
//
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
|
||||
return sqrt(2 / (constants::pi<T>() * x))
|
||||
* (asymptotic_bessel_j_large_x_P(v, x) * cos(chi)
|
||||
- asymptotic_bessel_j_large_x_Q(v, x) * sin(chi));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_y_large_x(T v, T x)
|
||||
{
|
||||
//
|
||||
// See http://functions.wolfram.com/BesselAiryStruveFunctions/BesselJ/06/02/02/0001/
|
||||
//
|
||||
// Also A&S 9.2.5
|
||||
//
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
T chi = fabs(x) - constants::pi<T>() * (2 * v + 1) / 4;
|
||||
return sqrt(2 / (constants::pi<T>() * x))
|
||||
* (asymptotic_bessel_j_large_x_P(v, x) * sin(chi)
|
||||
- asymptotic_bessel_j_large_x_Q(v, x) * cos(chi));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_amplitude(T v, T x)
|
||||
{
|
||||
// Calculate the amplitude of J(v, x) and Y(v, x) for large
|
||||
// x: see A&S 9.2.28.
|
||||
BOOST_MATH_STD_USING
|
||||
T s = 1;
|
||||
T mu = 4 * v * v;
|
||||
T txq = 2 * x;
|
||||
txq *= txq;
|
||||
|
||||
s += (mu - 1) / (2 * txq);
|
||||
s += 3 * (mu - 1) * (mu - 9) / (txq * txq * 8);
|
||||
s += 15 * (mu - 1) * (mu - 9) * (mu - 25) / (txq * txq * txq * 8 * 6);
|
||||
|
||||
return sqrt(s * 2 / (constants::pi<T>() * x));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T asymptotic_bessel_phase_mx(T v, T x)
|
||||
{
|
||||
//
|
||||
// Calculate the phase of J(v, x) and Y(v, x) for large x.
|
||||
// See A&S 9.2.29.
|
||||
// Note that the result returned is the phase less x.
|
||||
//
|
||||
T mu = 4 * v * v;
|
||||
T denom = 4 * x;
|
||||
T denom_mult = denom * denom;
|
||||
|
||||
T s = -constants::pi<T>() * (v / 2 + 0.25f);
|
||||
s += (mu - 1) / (2 * denom);
|
||||
denom *= denom_mult;
|
||||
s += (mu - 1) * (mu - 25) / (6 * denom);
|
||||
denom *= denom_mult;
|
||||
s += (mu - 1) * (mu * mu - 114 * mu + 1073) / (5 * denom);
|
||||
denom *= denom_mult;
|
||||
s += (mu - 1) * (5 * mu * mu * mu - 1535 * mu * mu + 54703 * mu - 375733) / (14 * denom);
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_y_large_x_2(T v, T x)
|
||||
{
|
||||
// See A&S 9.2.19.
|
||||
BOOST_MATH_STD_USING
|
||||
// Get the phase and amplitude:
|
||||
T ampl = asymptotic_bessel_amplitude(v, x);
|
||||
T phase = asymptotic_bessel_phase_mx(v, x);
|
||||
//
|
||||
// Calculate the sine of the phase, using:
|
||||
// sin(x+p) = sin(x)cos(p) + cos(x)sin(p)
|
||||
//
|
||||
T sin_phase = sin(phase) * cos(x) + cos(phase) * sin(x);
|
||||
return sin_phase * ampl;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_large_x_2(T v, T x)
|
||||
{
|
||||
// See A&S 9.2.19.
|
||||
BOOST_MATH_STD_USING
|
||||
// Get the phase and amplitude:
|
||||
T ampl = asymptotic_bessel_amplitude(v, x);
|
||||
T phase = asymptotic_bessel_phase_mx(v, x);
|
||||
//
|
||||
// Calculate the sine of the phase, using:
|
||||
// cos(x+p) = cos(x)cos(p) - sin(x)sin(p)
|
||||
//
|
||||
T sin_phase = cos(phase) * cos(x) - sin(phase) * sin(x);
|
||||
return sin_phase * ampl;
|
||||
}
|
||||
|
||||
//
|
||||
// Various limits for the J and Y asymptotics
|
||||
// (the asympotic expansions are safe to use if
|
||||
// x is less than the limit given).
|
||||
// We assume that if we don't use these expansions then the
|
||||
// error will likely be >100eps, so the limits given are chosen
|
||||
// to lead to < 100eps truncation error.
|
||||
//
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_y_limit(const mpl::int_<0>&)
|
||||
{
|
||||
// default case:
|
||||
BOOST_MATH_STD_USING
|
||||
return 2.25 / pow(100 * tools::epsilon<T>() / T(0.001f), T(0.2f));
|
||||
}
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_y_limit(const mpl::int_<53>&)
|
||||
{
|
||||
// double case:
|
||||
return 304 /*780*/;
|
||||
}
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_y_limit(const mpl::int_<64>&)
|
||||
{
|
||||
// 80-bit extended-double case:
|
||||
return 1552 /*3500*/;
|
||||
}
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_y_limit(const mpl::int_<113>&)
|
||||
{
|
||||
// 128-bit long double case:
|
||||
return 1245243 /*3128000*/;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
struct bessel_asymptotic_tag
|
||||
{
|
||||
typedef typename policies::precision<T, Policy>::type precision_type;
|
||||
typedef typename mpl::if_<
|
||||
mpl::or_<
|
||||
mpl::equal_to<precision_type, mpl::int_<0> >,
|
||||
mpl::greater<precision_type, mpl::int_<113> > >,
|
||||
mpl::int_<0>,
|
||||
typename mpl::if_<
|
||||
mpl::greater<precision_type, mpl::int_<64> >,
|
||||
mpl::int_<113>,
|
||||
typename mpl::if_<
|
||||
mpl::greater<precision_type, mpl::int_<53> >,
|
||||
mpl::int_<64>,
|
||||
mpl::int_<53>
|
||||
>::type
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<0>&)
|
||||
{
|
||||
// default case:
|
||||
BOOST_MATH_STD_USING
|
||||
T v2 = (std::max)(T(3), v * v);
|
||||
return v2 / pow(100 * tools::epsilon<T>() / T(2e-5f), T(0.17f));
|
||||
}
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<53>&)
|
||||
{
|
||||
// double case:
|
||||
T v2 = (std::max)(T(3), v * v);
|
||||
return v2 * 33 /*73*/;
|
||||
}
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<64>&)
|
||||
{
|
||||
// 80-bit extended-double case:
|
||||
T v2 = (std::max)(T(3), v * v);
|
||||
return v2 * 121 /*266*/;
|
||||
}
|
||||
template <class T>
|
||||
inline T asymptotic_bessel_j_limit(const T& v, const mpl::int_<113>&)
|
||||
{
|
||||
// 128-bit long double case:
|
||||
T v2 = (std::max)(T(3), v * v);
|
||||
return v2 * 39154 /*85700*/;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
void temme_asyptotic_y_small_x(T v, T x, T* Y, T* Y1, const Policy& pol)
|
||||
{
|
||||
T c = 1;
|
||||
T p = (v / 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
|
||||
116
include/boost/math/special_functions/detail/bessel_k0.hpp
Normal file
116
include/boost/math/special_functions/detail/bessel_k0.hpp
Normal file
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_K0_HPP
|
||||
#define BOOST_MATH_BESSEL_K0_HPP
|
||||
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Modified Bessel function of the second kind of order zero
|
||||
// minimax rational approximations on intervals, see
|
||||
// Russon and Blair, Chalk River Report AECL-3461, 1969
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T bessel_k0(T x, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_INSTRUMENT_CODE(x);
|
||||
|
||||
static const T P1[] = {
|
||||
static_cast<T>(2.4708152720399552679e+03L),
|
||||
static_cast<T>(5.9169059852270512312e+03L),
|
||||
static_cast<T>(4.6850901201934832188e+02L),
|
||||
static_cast<T>(1.1999463724910714109e+01L),
|
||||
static_cast<T>(1.3166052564989571850e-01L),
|
||||
static_cast<T>(5.8599221412826100000e-04L)
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(2.1312714303849120380e+04L),
|
||||
static_cast<T>(-2.4994418972832303646e+02L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(-1.6128136304458193998e+06L),
|
||||
static_cast<T>(-3.7333769444840079748e+05L),
|
||||
static_cast<T>(-1.7984434409411765813e+04L),
|
||||
static_cast<T>(-2.9501657892958843865e+02L),
|
||||
static_cast<T>(-1.6414452837299064100e+00L)
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(-1.6128136304458193998e+06L),
|
||||
static_cast<T>(2.9865713163054025489e+04L),
|
||||
static_cast<T>(-2.5064972445877992730e+02L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T P3[] = {
|
||||
static_cast<T>(1.1600249425076035558e+02L),
|
||||
static_cast<T>(2.3444738764199315021e+03L),
|
||||
static_cast<T>(1.8321525870183537725e+04L),
|
||||
static_cast<T>(7.1557062783764037541e+04L),
|
||||
static_cast<T>(1.5097646353289914539e+05L),
|
||||
static_cast<T>(1.7398867902565686251e+05L),
|
||||
static_cast<T>(1.0577068948034021957e+05L),
|
||||
static_cast<T>(3.1075408980684392399e+04L),
|
||||
static_cast<T>(3.6832589957340267940e+03L),
|
||||
static_cast<T>(1.1394980557384778174e+02L)
|
||||
};
|
||||
static const T Q3[] = {
|
||||
static_cast<T>(9.2556599177304839811e+01L),
|
||||
static_cast<T>(1.8821890840982713696e+03L),
|
||||
static_cast<T>(1.4847228371802360957e+04L),
|
||||
static_cast<T>(5.8824616785857027752e+04L),
|
||||
static_cast<T>(1.2689839587977598727e+05L),
|
||||
static_cast<T>(1.5144644673520157801e+05L),
|
||||
static_cast<T>(9.7418829762268075784e+04L),
|
||||
static_cast<T>(3.1474655750295278825e+04L),
|
||||
static_cast<T>(4.4329628889746408858e+03L),
|
||||
static_cast<T>(2.0013443064949242491e+02L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
T value, factor, r, r1, r2;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::bessel_k0<%1%>(%1%,%1%)";
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got x = %1%, but argument x must be non-negative, complex number result not supported", x, pol);
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
return policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
if (x <= 1) // x in (0, 1]
|
||||
{
|
||||
T y = x * x;
|
||||
r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
|
||||
r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
|
||||
factor = log(x);
|
||||
value = r1 - factor * r2;
|
||||
}
|
||||
else // x in (1, \infty)
|
||||
{
|
||||
T y = 1 / x;
|
||||
r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
|
||||
factor = exp(-x) / sqrt(x);
|
||||
value = factor * r;
|
||||
BOOST_MATH_INSTRUMENT_CODE("y = " << y);
|
||||
BOOST_MATH_INSTRUMENT_CODE("r = " << r);
|
||||
BOOST_MATH_INSTRUMENT_CODE("factor = " << factor);
|
||||
BOOST_MATH_INSTRUMENT_CODE("value = " << value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_K0_HPP
|
||||
112
include/boost/math/special_functions/detail/bessel_k1.hpp
Normal file
112
include/boost/math/special_functions/detail/bessel_k1.hpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_K1_HPP
|
||||
#define BOOST_MATH_BESSEL_K1_HPP
|
||||
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Modified Bessel function of the second kind of order one
|
||||
// minimax rational approximations on intervals, see
|
||||
// Russon and Blair, Chalk River Report AECL-3461, 1969
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T bessel_k1(T x, const Policy& pol)
|
||||
{
|
||||
static const T P1[] = {
|
||||
static_cast<T>(-2.2149374878243304548e+06L),
|
||||
static_cast<T>(7.1938920065420586101e+05L),
|
||||
static_cast<T>(1.7733324035147015630e+05L),
|
||||
static_cast<T>(7.1885382604084798576e+03L),
|
||||
static_cast<T>(9.9991373567429309922e+01L),
|
||||
static_cast<T>(4.8127070456878442310e-01L)
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(-2.2149374878243304548e+06L),
|
||||
static_cast<T>(3.7264298672067697862e+04L),
|
||||
static_cast<T>(-2.8143915754538725829e+02L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(0.0L),
|
||||
static_cast<T>(-1.3531161492785421328e+06L),
|
||||
static_cast<T>(-1.4758069205414222471e+05L),
|
||||
static_cast<T>(-4.5051623763436087023e+03L),
|
||||
static_cast<T>(-5.3103913335180275253e+01L),
|
||||
static_cast<T>(-2.2795590826955002390e-01L)
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(-2.7062322985570842656e+06L),
|
||||
static_cast<T>(4.3117653211351080007e+04L),
|
||||
static_cast<T>(-3.0507151578787595807e+02L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
static const T P3[] = {
|
||||
static_cast<T>(2.2196792496874548962e+00L),
|
||||
static_cast<T>(4.4137176114230414036e+01L),
|
||||
static_cast<T>(3.4122953486801312910e+02L),
|
||||
static_cast<T>(1.3319486433183221990e+03L),
|
||||
static_cast<T>(2.8590657697910288226e+03L),
|
||||
static_cast<T>(3.4540675585544584407e+03L),
|
||||
static_cast<T>(2.3123742209168871550e+03L),
|
||||
static_cast<T>(8.1094256146537402173e+02L),
|
||||
static_cast<T>(1.3182609918569941308e+02L),
|
||||
static_cast<T>(7.5584584631176030810e+00L),
|
||||
static_cast<T>(6.4257745859173138767e-02L)
|
||||
};
|
||||
static const T Q3[] = {
|
||||
static_cast<T>(1.7710478032601086579e+00L),
|
||||
static_cast<T>(3.4552228452758912848e+01L),
|
||||
static_cast<T>(2.5951223655579051357e+02L),
|
||||
static_cast<T>(9.6929165726802648634e+02L),
|
||||
static_cast<T>(1.9448440788918006154e+03L),
|
||||
static_cast<T>(2.1181000487171943810e+03L),
|
||||
static_cast<T>(1.2082692316002348638e+03L),
|
||||
static_cast<T>(3.3031020088765390854e+02L),
|
||||
static_cast<T>(3.6001069306861518855e+01L),
|
||||
static_cast<T>(1.0L)
|
||||
};
|
||||
T value, factor, r, r1, r2;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::bessel_k1<%1%>(%1%,%1%)";
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol);
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
return policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
if (x <= 1) // x in (0, 1]
|
||||
{
|
||||
T y = x * x;
|
||||
r1 = evaluate_polynomial(P1, y) / evaluate_polynomial(Q1, y);
|
||||
r2 = evaluate_polynomial(P2, y) / evaluate_polynomial(Q2, y);
|
||||
factor = log(x);
|
||||
value = (r1 + factor * r2) / x;
|
||||
}
|
||||
else // x in (1, \infty)
|
||||
{
|
||||
T y = 1 / x;
|
||||
r = evaluate_polynomial(P3, y) / evaluate_polynomial(Q3, y);
|
||||
factor = exp(-x) / sqrt(x);
|
||||
value = factor * r;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_K1_HPP
|
||||
69
include/boost/math/special_functions/detail/bessel_kn.hpp
Normal file
69
include/boost/math/special_functions/detail/bessel_kn.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_KN_HPP
|
||||
#define BOOST_MATH_BESSEL_KN_HPP
|
||||
|
||||
#include <boost/math/special_functions/detail/bessel_k0.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_k1.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
// Modified Bessel function of the second kind of integer order
|
||||
// K_n(z) is the dominant solution, forward recurrence always OK (though unstable)
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T bessel_kn(int n, T x, const Policy& pol)
|
||||
{
|
||||
T value, current, prev;
|
||||
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::bessel_kn<%1%>(%1%,%1%)";
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got x = %1%, but argument x must be non-negative, complex number result not supported.", x, pol);
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
return policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
n = -n; // K_{-n}(z) = K_n(z)
|
||||
}
|
||||
if (n == 0)
|
||||
{
|
||||
value = bessel_k0(x, pol);
|
||||
}
|
||||
else if (n == 1)
|
||||
{
|
||||
value = bessel_k1(x, pol);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = bessel_k0(x, pol);
|
||||
current = bessel_k1(x, pol);
|
||||
int k = 1;
|
||||
BOOST_ASSERT(k < n);
|
||||
do
|
||||
{
|
||||
value = 2 * k * current / x + prev;
|
||||
prev = current;
|
||||
current = value;
|
||||
++k;
|
||||
}
|
||||
while(k < n);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_KN_HPP
|
||||
177
include/boost/math/special_functions/detail/bessel_y0.hpp
Normal file
177
include/boost/math/special_functions/detail/bessel_y0.hpp
Normal file
@@ -0,0 +1,177 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_Y0_HPP
|
||||
#define BOOST_MATH_BESSEL_Y0_HPP
|
||||
|
||||
#include <boost/math/special_functions/detail/bessel_j0.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Bessel function of the second kind of order zero
|
||||
// x <= 8, minimax rational approximations on root-bracketing intervals
|
||||
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T bessel_y0(T x, const Policy& pol)
|
||||
{
|
||||
static const T P1[] = {
|
||||
static_cast<T>(1.0723538782003176831e+11L),
|
||||
static_cast<T>(-8.3716255451260504098e+09L),
|
||||
static_cast<T>(2.0422274357376619816e+08L),
|
||||
static_cast<T>(-2.1287548474401797963e+06L),
|
||||
static_cast<T>(1.0102532948020907590e+04L),
|
||||
static_cast<T>(-1.8402381979244993524e+01L),
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(5.8873865738997033405e+11L),
|
||||
static_cast<T>(8.1617187777290363573e+09L),
|
||||
static_cast<T>(5.5662956624278251596e+07L),
|
||||
static_cast<T>(2.3889393209447253406e+05L),
|
||||
static_cast<T>(6.6475986689240190091e+02L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(-2.2213976967566192242e+13L),
|
||||
static_cast<T>(-5.5107435206722644429e+11L),
|
||||
static_cast<T>(4.3600098638603061642e+10L),
|
||||
static_cast<T>(-6.9590439394619619534e+08L),
|
||||
static_cast<T>(4.6905288611678631510e+06L),
|
||||
static_cast<T>(-1.4566865832663635920e+04L),
|
||||
static_cast<T>(1.7427031242901594547e+01L),
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(4.3386146580707264428e+14L),
|
||||
static_cast<T>(5.4266824419412347550e+12L),
|
||||
static_cast<T>(3.4015103849971240096e+10L),
|
||||
static_cast<T>(1.3960202770986831075e+08L),
|
||||
static_cast<T>(4.0669982352539552018e+05L),
|
||||
static_cast<T>(8.3030857612070288823e+02L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T P3[] = {
|
||||
static_cast<T>(-8.0728726905150210443e+15L),
|
||||
static_cast<T>(6.7016641869173237784e+14L),
|
||||
static_cast<T>(-1.2829912364088687306e+11L),
|
||||
static_cast<T>(-1.9363051266772083678e+11L),
|
||||
static_cast<T>(2.1958827170518100757e+09L),
|
||||
static_cast<T>(-1.0085539923498211426e+07L),
|
||||
static_cast<T>(2.1363534169313901632e+04L),
|
||||
static_cast<T>(-1.7439661319197499338e+01L),
|
||||
};
|
||||
static const T Q3[] = {
|
||||
static_cast<T>(3.4563724628846457519e+17L),
|
||||
static_cast<T>(3.9272425569640309819e+15L),
|
||||
static_cast<T>(2.2598377924042897629e+13L),
|
||||
static_cast<T>(8.6926121104209825246e+10L),
|
||||
static_cast<T>(2.4727219475672302327e+08L),
|
||||
static_cast<T>(5.3924739209768057030e+05L),
|
||||
static_cast<T>(8.7903362168128450017e+02L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T PC[] = {
|
||||
static_cast<T>(2.2779090197304684302e+04L),
|
||||
static_cast<T>(4.1345386639580765797e+04L),
|
||||
static_cast<T>(2.1170523380864944322e+04L),
|
||||
static_cast<T>(3.4806486443249270347e+03L),
|
||||
static_cast<T>(1.5376201909008354296e+02L),
|
||||
static_cast<T>(8.8961548424210455236e-01L),
|
||||
};
|
||||
static const T QC[] = {
|
||||
static_cast<T>(2.2779090197304684318e+04L),
|
||||
static_cast<T>(4.1370412495510416640e+04L),
|
||||
static_cast<T>(2.1215350561880115730e+04L),
|
||||
static_cast<T>(3.5028735138235608207e+03L),
|
||||
static_cast<T>(1.5711159858080893649e+02L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T PS[] = {
|
||||
static_cast<T>(-8.9226600200800094098e+01L),
|
||||
static_cast<T>(-1.8591953644342993800e+02L),
|
||||
static_cast<T>(-1.1183429920482737611e+02L),
|
||||
static_cast<T>(-2.2300261666214198472e+01L),
|
||||
static_cast<T>(-1.2441026745835638459e+00L),
|
||||
static_cast<T>(-8.8033303048680751817e-03L),
|
||||
};
|
||||
static const T QS[] = {
|
||||
static_cast<T>(5.7105024128512061905e+03L),
|
||||
static_cast<T>(1.1951131543434613647e+04L),
|
||||
static_cast<T>(7.2642780169211018836e+03L),
|
||||
static_cast<T>(1.4887231232283756582e+03L),
|
||||
static_cast<T>(9.0593769594993125859e+01L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T x1 = static_cast<T>(8.9357696627916752158e-01L),
|
||||
x2 = static_cast<T>(3.9576784193148578684e+00L),
|
||||
x3 = static_cast<T>(7.0860510603017726976e+00L),
|
||||
x11 = static_cast<T>(2.280e+02L),
|
||||
x12 = static_cast<T>(2.9519662791675215849e-03L),
|
||||
x21 = static_cast<T>(1.0130e+03L),
|
||||
x22 = static_cast<T>(6.4716931485786837568e-04L),
|
||||
x31 = static_cast<T>(1.8140e+03L),
|
||||
x32 = static_cast<T>(1.1356030177269762362e-04L)
|
||||
;
|
||||
T value, factor, r, rc, rs;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
using namespace boost::math::constants;
|
||||
|
||||
static const char* function = "boost::math::bessel_y0<%1%>(%1%,%1%)";
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got x = %1% but x must be non-negative, complex result not supported.", x, pol);
|
||||
}
|
||||
if (x == 0)
|
||||
{
|
||||
return -policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
if (x <= 3) // x in (0, 3]
|
||||
{
|
||||
T y = x * x;
|
||||
T z = 2 * log(x/x1) * bessel_j0(x) / pi<T>();
|
||||
r = evaluate_rational(P1, Q1, y);
|
||||
factor = (x + x1) * ((x - x11/256) - x12);
|
||||
value = z + factor * r;
|
||||
}
|
||||
else if (x <= 5.5f) // x in (3, 5.5]
|
||||
{
|
||||
T y = x * x;
|
||||
T z = 2 * log(x/x2) * bessel_j0(x) / pi<T>();
|
||||
r = evaluate_rational(P2, Q2, y);
|
||||
factor = (x + x2) * ((x - x21/256) - x22);
|
||||
value = z + factor * r;
|
||||
}
|
||||
else if (x <= 8) // x in (5.5, 8]
|
||||
{
|
||||
T y = x * x;
|
||||
T z = 2 * log(x/x3) * bessel_j0(x) / pi<T>();
|
||||
r = evaluate_rational(P3, Q3, y);
|
||||
factor = (x + x3) * ((x - x31/256) - x32);
|
||||
value = z + factor * r;
|
||||
}
|
||||
else // x in (8, \infty)
|
||||
{
|
||||
T y = 8 / x;
|
||||
T y2 = y * y;
|
||||
T z = x - 0.25f * pi<T>();
|
||||
rc = evaluate_rational(PC, QC, y2);
|
||||
rs = evaluate_rational(PS, QS, y2);
|
||||
factor = sqrt(2 / (x * pi<T>()));
|
||||
value = factor * (rc * sin(z) + y * rs * cos(z));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_Y0_HPP
|
||||
150
include/boost/math/special_functions/detail/bessel_y1.hpp
Normal file
150
include/boost/math/special_functions/detail/bessel_y1.hpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_Y1_HPP
|
||||
#define BOOST_MATH_BESSEL_Y1_HPP
|
||||
|
||||
#include <boost/math/special_functions/detail/bessel_j1.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
// Bessel function of the second kind of order one
|
||||
// x <= 8, minimax rational approximations on root-bracketing intervals
|
||||
// x > 8, Hankel asymptotic expansion in Hart, Computer Approximations, 1968
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T bessel_y1(T x, const Policy& pol)
|
||||
{
|
||||
static const T P1[] = {
|
||||
static_cast<T>(4.0535726612579544093e+13L),
|
||||
static_cast<T>(5.4708611716525426053e+12L),
|
||||
static_cast<T>(-3.7595974497819597599e+11L),
|
||||
static_cast<T>(7.2144548214502560419e+09L),
|
||||
static_cast<T>(-5.9157479997408395984e+07L),
|
||||
static_cast<T>(2.2157953222280260820e+05L),
|
||||
static_cast<T>(-3.1714424660046133456e+02L),
|
||||
};
|
||||
static const T Q1[] = {
|
||||
static_cast<T>(3.0737873921079286084e+14L),
|
||||
static_cast<T>(4.1272286200406461981e+12L),
|
||||
static_cast<T>(2.7800352738690585613e+10L),
|
||||
static_cast<T>(1.2250435122182963220e+08L),
|
||||
static_cast<T>(3.8136470753052572164e+05L),
|
||||
static_cast<T>(8.2079908168393867438e+02L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T P2[] = {
|
||||
static_cast<T>(1.1514276357909013326e+19L),
|
||||
static_cast<T>(-5.6808094574724204577e+18L),
|
||||
static_cast<T>(-2.3638408497043134724e+16L),
|
||||
static_cast<T>(4.0686275289804744814e+15L),
|
||||
static_cast<T>(-5.9530713129741981618e+13L),
|
||||
static_cast<T>(3.7453673962438488783e+11L),
|
||||
static_cast<T>(-1.1957961912070617006e+09L),
|
||||
static_cast<T>(1.9153806858264202986e+06L),
|
||||
static_cast<T>(-1.2337180442012953128e+03L),
|
||||
};
|
||||
static const T Q2[] = {
|
||||
static_cast<T>(5.3321844313316185697e+20L),
|
||||
static_cast<T>(5.6968198822857178911e+18L),
|
||||
static_cast<T>(3.0837179548112881950e+16L),
|
||||
static_cast<T>(1.1187010065856971027e+14L),
|
||||
static_cast<T>(3.0221766852960403645e+11L),
|
||||
static_cast<T>(6.3550318087088919566e+08L),
|
||||
static_cast<T>(1.0453748201934079734e+06L),
|
||||
static_cast<T>(1.2855164849321609336e+03L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T PC[] = {
|
||||
static_cast<T>(-4.4357578167941278571e+06L),
|
||||
static_cast<T>(-9.9422465050776411957e+06L),
|
||||
static_cast<T>(-6.6033732483649391093e+06L),
|
||||
static_cast<T>(-1.5235293511811373833e+06L),
|
||||
static_cast<T>(-1.0982405543459346727e+05L),
|
||||
static_cast<T>(-1.6116166443246101165e+03L),
|
||||
static_cast<T>(0.0L),
|
||||
};
|
||||
static const T QC[] = {
|
||||
static_cast<T>(-4.4357578167941278568e+06L),
|
||||
static_cast<T>(-9.9341243899345856590e+06L),
|
||||
static_cast<T>(-6.5853394797230870728e+06L),
|
||||
static_cast<T>(-1.5118095066341608816e+06L),
|
||||
static_cast<T>(-1.0726385991103820119e+05L),
|
||||
static_cast<T>(-1.4550094401904961825e+03L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T PS[] = {
|
||||
static_cast<T>(3.3220913409857223519e+04L),
|
||||
static_cast<T>(8.5145160675335701966e+04L),
|
||||
static_cast<T>(6.6178836581270835179e+04L),
|
||||
static_cast<T>(1.8494262873223866797e+04L),
|
||||
static_cast<T>(1.7063754290207680021e+03L),
|
||||
static_cast<T>(3.5265133846636032186e+01L),
|
||||
static_cast<T>(0.0L),
|
||||
};
|
||||
static const T QS[] = {
|
||||
static_cast<T>(7.0871281941028743574e+05L),
|
||||
static_cast<T>(1.8194580422439972989e+06L),
|
||||
static_cast<T>(1.4194606696037208929e+06L),
|
||||
static_cast<T>(4.0029443582266975117e+05L),
|
||||
static_cast<T>(3.7890229745772202641e+04L),
|
||||
static_cast<T>(8.6383677696049909675e+02L),
|
||||
static_cast<T>(1.0L),
|
||||
};
|
||||
static const T x1 = static_cast<T>(2.1971413260310170351e+00L),
|
||||
x2 = static_cast<T>(5.4296810407941351328e+00L),
|
||||
x11 = static_cast<T>(5.620e+02L),
|
||||
x12 = static_cast<T>(1.8288260310170351490e-03L),
|
||||
x21 = static_cast<T>(1.3900e+03L),
|
||||
x22 = static_cast<T>(-6.4592058648672279948e-06L)
|
||||
;
|
||||
T value, factor, r, rc, rs;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
using namespace boost::math::constants;
|
||||
|
||||
if (x <= 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>("bost::math::bessel_y1<%1%>(%1%,%1%)",
|
||||
"Got x == %1%, but x must be > 0, complex result not supported.", x, pol);
|
||||
}
|
||||
if (x <= 4) // x in (0, 4]
|
||||
{
|
||||
T y = x * x;
|
||||
T z = 2 * log(x/x1) * bessel_j1(x) / pi<T>();
|
||||
r = evaluate_rational(P1, Q1, y);
|
||||
factor = (x + x1) * ((x - x11/256) - x12) / x;
|
||||
value = z + factor * r;
|
||||
}
|
||||
else if (x <= 8) // x in (4, 8]
|
||||
{
|
||||
T y = x * x;
|
||||
T z = 2 * log(x/x2) * bessel_j1(x) / pi<T>();
|
||||
r = evaluate_rational(P2, Q2, y);
|
||||
factor = (x + x2) * ((x - x21/256) - x22) / x;
|
||||
value = z + factor * r;
|
||||
}
|
||||
else // x in (8, \infty)
|
||||
{
|
||||
T y = 8 / x;
|
||||
T y2 = y * y;
|
||||
T z = x - 0.75f * pi<T>();
|
||||
rc = evaluate_rational(PC, QC, y2);
|
||||
rs = evaluate_rational(PS, QS, y2);
|
||||
factor = sqrt(2 / (x * pi<T>()));
|
||||
value = factor * (rc * sin(z) + y * rs * cos(z));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_Y1_HPP
|
||||
79
include/boost/math/special_functions/detail/bessel_yn.hpp
Normal file
79
include/boost/math/special_functions/detail/bessel_yn.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_BESSEL_YN_HPP
|
||||
#define BOOST_MATH_BESSEL_YN_HPP
|
||||
|
||||
#include <boost/math/special_functions/detail/bessel_y0.hpp>
|
||||
#include <boost/math/special_functions/detail/bessel_y1.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
// Bessel function of the second kind of integer order
|
||||
// Y_n(z) is the dominant solution, forward recurrence always OK (though unstable)
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T bessel_yn(int n, T x, const Policy& pol)
|
||||
{
|
||||
T value, factor, current, prev;
|
||||
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::bessel_yn<%1%>(%1%,%1%)";
|
||||
|
||||
if ((x == 0) && (n == 0))
|
||||
{
|
||||
return -policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
if (x <= 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got x = %1%, but x must be > 0, complex result not supported.", x, pol);
|
||||
}
|
||||
|
||||
//
|
||||
// Reflection comes first:
|
||||
//
|
||||
if (n < 0)
|
||||
{
|
||||
factor = (n & 0x1) ? -1 : 1; // Y_{-n}(z) = (-1)^n Y_n(z)
|
||||
n = -n;
|
||||
}
|
||||
else
|
||||
{
|
||||
factor = 1;
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
{
|
||||
value = bessel_y0(x, pol);
|
||||
}
|
||||
else if (n == 1)
|
||||
{
|
||||
value = factor * bessel_y1(x, pol);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = bessel_y0(x, pol);
|
||||
current = bessel_y1(x, pol);
|
||||
int k = 1;
|
||||
BOOST_ASSERT(k < n);
|
||||
do
|
||||
{
|
||||
value = 2 * k * current / x - prev;
|
||||
prev = current;
|
||||
current = value;
|
||||
++k;
|
||||
}
|
||||
while(k < n);
|
||||
value *= factor;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_BESSEL_YN_HPP
|
||||
464
include/boost/math/special_functions/detail/erf_inv.hpp
Normal file
464
include/boost/math/special_functions/detail/erf_inv.hpp
Normal file
@@ -0,0 +1,464 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SF_ERF_INV_HPP
|
||||
#define BOOST_MATH_SF_ERF_INV_HPP
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace detail{
|
||||
//
|
||||
// The inverse erf and erfc functions share a common implementation,
|
||||
// this version is for 80-bit long double's and smaller:
|
||||
//
|
||||
template <class T, class Policy>
|
||||
T erf_inv_imp(const T& p, const T& q, const Policy&, const boost::mpl::int_<64>*)
|
||||
{
|
||||
BOOST_MATH_STD_USING // for ADL of std names.
|
||||
|
||||
T result = 0;
|
||||
|
||||
if(p <= 0.5)
|
||||
{
|
||||
//
|
||||
// Evaluate inverse erf using the rational approximation:
|
||||
//
|
||||
// x = p(p+10)(Y+R(p))
|
||||
//
|
||||
// Where Y is a constant, and R(p) is optimised for a low
|
||||
// absolute error compared to |Y|.
|
||||
//
|
||||
// double: Max error found: 2.001849e-18
|
||||
// long double: Max error found: 1.017064e-20
|
||||
// Maximum Deviation Found (actual error term at infinite precision) 8.030e-21
|
||||
//
|
||||
static const float Y = 0.0891314744949340820313f;
|
||||
static const T P[] = {
|
||||
-0.000508781949658280665617L,
|
||||
-0.00836874819741736770379L,
|
||||
0.0334806625409744615033L,
|
||||
-0.0126926147662974029034L,
|
||||
-0.0365637971411762664006L,
|
||||
0.0219878681111168899165L,
|
||||
0.00822687874676915743155L,
|
||||
-0.00538772965071242932965L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1,
|
||||
-0.970005043303290640362L,
|
||||
-1.56574558234175846809L,
|
||||
1.56221558398423026363L,
|
||||
0.662328840472002992063L,
|
||||
-0.71228902341542847553L,
|
||||
-0.0527396382340099713954L,
|
||||
0.0795283687341571680018L,
|
||||
-0.00233393759374190016776L,
|
||||
0.000886216390456424707504L
|
||||
};
|
||||
T g = p * (p + 10);
|
||||
T r = tools::evaluate_polynomial(P, p) / tools::evaluate_polynomial(Q, p);
|
||||
result = g * Y + g * r;
|
||||
}
|
||||
else if(q >= 0.25)
|
||||
{
|
||||
//
|
||||
// Rational approximation for 0.5 > q >= 0.25
|
||||
//
|
||||
// x = sqrt(-2*log(q)) / (Y + R(q))
|
||||
//
|
||||
// Where Y is a constant, and R(q) is optimised for a low
|
||||
// absolute error compared to Y.
|
||||
//
|
||||
// double : Max error found: 7.403372e-17
|
||||
// long double : Max error found: 6.084616e-20
|
||||
// Maximum Deviation Found (error term) 4.811e-20
|
||||
//
|
||||
static const float Y = 2.249481201171875f;
|
||||
static const T P[] = {
|
||||
-0.202433508355938759655L,
|
||||
0.105264680699391713268L,
|
||||
8.37050328343119927838L,
|
||||
17.6447298408374015486L,
|
||||
-18.8510648058714251895L,
|
||||
-44.6382324441786960818L,
|
||||
17.445385985570866523L,
|
||||
21.1294655448340526258L,
|
||||
-3.67192254707729348546L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1L,
|
||||
6.24264124854247537712L,
|
||||
3.9713437953343869095L,
|
||||
-28.6608180499800029974L,
|
||||
-20.1432634680485188801L,
|
||||
48.5609213108739935468L,
|
||||
10.8268667355460159008L,
|
||||
-22.6436933413139721736L,
|
||||
1.72114765761200282724L
|
||||
};
|
||||
T g = sqrt(-2 * log(q));
|
||||
T xs = q - 0.25;
|
||||
T r = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
|
||||
result = g / (Y + r);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// For q < 0.25 we have a series of rational approximations all
|
||||
// of the general form:
|
||||
//
|
||||
// let: x = sqrt(-log(q))
|
||||
//
|
||||
// Then the result is given by:
|
||||
//
|
||||
// x(Y+R(x-B))
|
||||
//
|
||||
// where Y is a constant, B is the lowest value of x for which
|
||||
// the approximation is valid, and R(x-B) is optimised for a low
|
||||
// absolute error compared to Y.
|
||||
//
|
||||
// Note that almost all code will really go through the first
|
||||
// or maybe second approximation. After than we're dealing with very
|
||||
// small input values indeed: 80 and 128 bit long double's go all the
|
||||
// way down to ~ 1e-5000 so the "tail" is rather long...
|
||||
//
|
||||
T x = sqrt(-log(q));
|
||||
if(x < 3)
|
||||
{
|
||||
// Max error found: 1.089051e-20
|
||||
static const float Y = 0.807220458984375f;
|
||||
static const T P[] = {
|
||||
-0.131102781679951906451L,
|
||||
-0.163794047193317060787L,
|
||||
0.117030156341995252019L,
|
||||
0.387079738972604337464L,
|
||||
0.337785538912035898924L,
|
||||
0.142869534408157156766L,
|
||||
0.0290157910005329060432L,
|
||||
0.00214558995388805277169L,
|
||||
-0.679465575181126350155e-6L,
|
||||
0.285225331782217055858e-7L,
|
||||
-0.681149956853776992068e-9L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1,
|
||||
3.46625407242567245975L,
|
||||
5.38168345707006855425L,
|
||||
4.77846592945843778382L,
|
||||
2.59301921623620271374L,
|
||||
0.848854343457902036425L,
|
||||
0.152264338295331783612L,
|
||||
0.01105924229346489121L
|
||||
};
|
||||
T xs = x - 1.125;
|
||||
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
|
||||
result = Y * x + R * x;
|
||||
}
|
||||
else if(x < 6)
|
||||
{
|
||||
// Max error found: 8.389174e-21
|
||||
static const float Y = 0.93995571136474609375f;
|
||||
static const T P[] = {
|
||||
-0.0350353787183177984712L,
|
||||
-0.00222426529213447927281L,
|
||||
0.0185573306514231072324L,
|
||||
0.00950804701325919603619L,
|
||||
0.00187123492819559223345L,
|
||||
0.000157544617424960554631L,
|
||||
0.460469890584317994083e-5L,
|
||||
-0.230404776911882601748e-9L,
|
||||
0.266339227425782031962e-11L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1L,
|
||||
1.3653349817554063097L,
|
||||
0.762059164553623404043L,
|
||||
0.220091105764131249824L,
|
||||
0.0341589143670947727934L,
|
||||
0.00263861676657015992959L,
|
||||
0.764675292302794483503e-4L
|
||||
};
|
||||
T xs = x - 3;
|
||||
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
|
||||
result = Y * x + R * x;
|
||||
}
|
||||
else if(x < 18)
|
||||
{
|
||||
// Max error found: 1.481312e-19
|
||||
static const float Y = 0.98362827301025390625f;
|
||||
static const T P[] = {
|
||||
-0.0167431005076633737133L,
|
||||
-0.00112951438745580278863L,
|
||||
0.00105628862152492910091L,
|
||||
0.000209386317487588078668L,
|
||||
0.149624783758342370182e-4L,
|
||||
0.449696789927706453732e-6L,
|
||||
0.462596163522878599135e-8L,
|
||||
-0.281128735628831791805e-13L,
|
||||
0.99055709973310326855e-16L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1L,
|
||||
0.591429344886417493481L,
|
||||
0.138151865749083321638L,
|
||||
0.0160746087093676504695L,
|
||||
0.000964011807005165528527L,
|
||||
0.275335474764726041141e-4L,
|
||||
0.282243172016108031869e-6L
|
||||
};
|
||||
T xs = x - 6;
|
||||
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
|
||||
result = Y * x + R * x;
|
||||
}
|
||||
else if(x < 44)
|
||||
{
|
||||
// Max error found: 5.697761e-20
|
||||
static const float Y = 0.99714565277099609375f;
|
||||
static const T P[] = {
|
||||
-0.0024978212791898131227L,
|
||||
-0.779190719229053954292e-5L,
|
||||
0.254723037413027451751e-4L,
|
||||
0.162397777342510920873e-5L,
|
||||
0.396341011304801168516e-7L,
|
||||
0.411632831190944208473e-9L,
|
||||
0.145596286718675035587e-11L,
|
||||
-0.116765012397184275695e-17L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1L,
|
||||
0.207123112214422517181L,
|
||||
0.0169410838120975906478L,
|
||||
0.000690538265622684595676L,
|
||||
0.145007359818232637924e-4L,
|
||||
0.144437756628144157666e-6L,
|
||||
0.509761276599778486139e-9L
|
||||
};
|
||||
T xs = x - 18;
|
||||
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
|
||||
result = Y * x + R * x;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Max error found: 1.279746e-20
|
||||
static const float Y = 0.99941349029541015625f;
|
||||
static const T P[] = {
|
||||
-0.000539042911019078575891L,
|
||||
-0.28398759004727721098e-6L,
|
||||
0.899465114892291446442e-6L,
|
||||
0.229345859265920864296e-7L,
|
||||
0.225561444863500149219e-9L,
|
||||
0.947846627503022684216e-12L,
|
||||
0.135880130108924861008e-14L,
|
||||
-0.348890393399948882918e-21L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1L,
|
||||
0.0845746234001899436914L,
|
||||
0.00282092984726264681981L,
|
||||
0.468292921940894236786e-4L,
|
||||
0.399968812193862100054e-6L,
|
||||
0.161809290887904476097e-8L,
|
||||
0.231558608310259605225e-11L
|
||||
};
|
||||
T xs = x - 44;
|
||||
T R = tools::evaluate_polynomial(P, xs) / tools::evaluate_polynomial(Q, xs);
|
||||
result = Y * x + R * x;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
struct erf_roots
|
||||
{
|
||||
std::tr1::tuple<T,T,T> operator()(const T& guess)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
T derivative = sign * (2 / sqrt(constants::pi<T>())) * exp(-(guess * guess));
|
||||
T derivative2 = -2 * guess * derivative;
|
||||
return std::tr1::make_tuple(((sign > 0) ? boost::math::erf(guess, Policy()) : boost::math::erfc(guess, Policy())) - target, derivative, derivative2);
|
||||
}
|
||||
erf_roots(T z, int s) : target(z), sign(s) {}
|
||||
private:
|
||||
T target;
|
||||
int sign;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
T erf_inv_imp(const T& p, const T& q, const Policy& pol, const boost::mpl::int_<0>*)
|
||||
{
|
||||
//
|
||||
// Generic version, get a guess that's accurate to 64-bits (10^-19)
|
||||
//
|
||||
T guess = erf_inv_imp(p, q, pol, static_cast<mpl::int_<64> const*>(0));
|
||||
T result;
|
||||
//
|
||||
// If T has more bit's than 64 in it's mantissa then we need to iterate,
|
||||
// otherwise we can just return the result:
|
||||
//
|
||||
if(policies::digits<T, Policy>() > 64)
|
||||
{
|
||||
if(p <= 0.5)
|
||||
{
|
||||
result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(p, 1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = tools::halley_iterate(detail::erf_roots<typename remove_cv<T>::type, Policy>(q, -1), guess, static_cast<T>(0), tools::max_value<T>(), (policies::digits<T, Policy>() * 2) / 3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = guess;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type erfc_inv(T z, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
//
|
||||
// Begin by testing for domain errors, and other special cases:
|
||||
//
|
||||
static const char* function = "boost::math::erfc_inv<%1%>(%1%, %1%)";
|
||||
if((z < 0) || (z > 2))
|
||||
policies::raise_domain_error<result_type>(function, "Argument outside range [0,2] in inverse erfc function (got p=%1%).", z, pol);
|
||||
if(z == 0)
|
||||
return policies::raise_overflow_error<result_type>(function, 0, pol);
|
||||
if(z == 2)
|
||||
return -policies::raise_overflow_error<result_type>(function, 0, pol);
|
||||
//
|
||||
// Normalise the input, so it's in the range [0,1], we will
|
||||
// negate the result if z is outside that range. This is a simple
|
||||
// application of the erfc reflection formula: erfc(-z) = 2 - erfc(z)
|
||||
//
|
||||
result_type p, q, s;
|
||||
if(z > 1)
|
||||
{
|
||||
q = 2 - z;
|
||||
p = 1 - q;
|
||||
s = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = 1 - z;
|
||||
q = z;
|
||||
s = 1;
|
||||
}
|
||||
//
|
||||
// A bit of meta-programming to figure out which implementation
|
||||
// to use, based on the number of bits in the mantissa of T:
|
||||
//
|
||||
typedef typename policies::precision<result_type, Policy>::type precision_type;
|
||||
typedef typename mpl::if_<
|
||||
mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >,
|
||||
mpl::int_<0>,
|
||||
mpl::int_<64>
|
||||
>::type tag_type;
|
||||
//
|
||||
// Likewise use internal promotion, so we evaluate at a higher
|
||||
// precision internally if it's appropriate:
|
||||
//
|
||||
typedef typename policies::evaluation<result_type, Policy>::type eval_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
//
|
||||
// And get the result, negating where required:
|
||||
//
|
||||
return s * policies::checked_narrowing_cast<result_type, forwarding_policy>(
|
||||
detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type erf_inv(T z, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
//
|
||||
// Begin by testing for domain errors, and other special cases:
|
||||
//
|
||||
static const char* function = "boost::math::erf_inv<%1%>(%1%, %1%)";
|
||||
if((z < -1) || (z > 1))
|
||||
policies::raise_domain_error<result_type>(function, "Argument outside range [-1, 1] in inverse erf function (got p=%1%).", z, pol);
|
||||
if(z == 1)
|
||||
return policies::raise_overflow_error<result_type>(function, 0, pol);
|
||||
if(z == -1)
|
||||
return -policies::raise_overflow_error<result_type>(function, 0, pol);
|
||||
if(z == 0)
|
||||
return 0;
|
||||
//
|
||||
// Normalise the input, so it's in the range [0,1], we will
|
||||
// negate the result if z is outside that range. This is a simple
|
||||
// application of the erf reflection formula: erf(-z) = -erf(z)
|
||||
//
|
||||
result_type p, q, s;
|
||||
if(z < 0)
|
||||
{
|
||||
p = -z;
|
||||
q = 1 - p;
|
||||
s = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
p = z;
|
||||
q = 1 - z;
|
||||
s = 1;
|
||||
}
|
||||
//
|
||||
// A bit of meta-programming to figure out which implementation
|
||||
// to use, based on the number of bits in the mantissa of T:
|
||||
//
|
||||
typedef typename policies::precision<result_type, Policy>::type precision_type;
|
||||
typedef typename mpl::if_<
|
||||
mpl::or_<mpl::less_equal<precision_type, mpl::int_<0> >, mpl::greater<precision_type, mpl::int_<64> > >,
|
||||
mpl::int_<0>,
|
||||
mpl::int_<64>
|
||||
>::type tag_type;
|
||||
//
|
||||
// Likewise use internal promotion, so we evaluate at a higher
|
||||
// precision internally if it's appropriate:
|
||||
//
|
||||
typedef typename policies::evaluation<result_type, Policy>::type eval_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
//
|
||||
// Likewise use internal promotion, so we evaluate at a higher
|
||||
// precision internally if it's appropriate:
|
||||
//
|
||||
typedef typename policies::evaluation<result_type, Policy>::type eval_type;
|
||||
//
|
||||
// And get the result, negating where required:
|
||||
//
|
||||
return s * policies::checked_narrowing_cast<result_type, forwarding_policy>(
|
||||
detail::erf_inv_imp(static_cast<eval_type>(p), static_cast<eval_type>(q), forwarding_policy(), static_cast<tag_type const*>(0)), function);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type erfc_inv(T z)
|
||||
{
|
||||
return erfc_inv(z, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type erf_inv(T z)
|
||||
{
|
||||
return erf_inv(z, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SF_ERF_INV_HPP
|
||||
228
include/boost/math/special_functions/detail/gamma_inva.hpp
Normal file
228
include/boost/math/special_functions/detail/gamma_inva.hpp
Normal file
@@ -0,0 +1,228 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
//
|
||||
// This is not a complete header file, it is included by gamma.hpp
|
||||
// after it has defined it's definitions. This inverts the incomplete
|
||||
// gamma functions P and Q on the first parameter "a" using a generic
|
||||
// root finding algorithm (TOMS Algorithm 748).
|
||||
//
|
||||
|
||||
#ifndef BOOST_MATH_SP_DETAIL_GAMMA_INVA
|
||||
#define BOOST_MATH_SP_DETAIL_GAMMA_INVA
|
||||
|
||||
#include <boost/math/tools/toms748_solve.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
template <class T, class Policy>
|
||||
struct gamma_inva_t
|
||||
{
|
||||
gamma_inva_t(T z_, T p_, bool invert_) : z(z_), p(p_), invert(invert_) {}
|
||||
T operator()(T a)
|
||||
{
|
||||
return invert ? p - boost::math::gamma_q(a, z, Policy()) : boost::math::gamma_p(a, z, Policy()) - p;
|
||||
}
|
||||
private:
|
||||
T z, p;
|
||||
bool invert;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
T inverse_poisson_cornish_fisher(T lambda, T p, T q, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
// mean:
|
||||
T m = lambda;
|
||||
// standard deviation:
|
||||
T sigma = sqrt(lambda);
|
||||
// skewness
|
||||
T sk = 1 / sigma;
|
||||
// kurtosis:
|
||||
// T k = 1/lambda;
|
||||
// Get the inverse of a std normal distribution:
|
||||
T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
|
||||
// Set the sign:
|
||||
if(p < 0.5)
|
||||
x = -x;
|
||||
T x2 = x * x;
|
||||
// w is correction term due to skewness
|
||||
T w = x + sk * (x2 - 1) / 6;
|
||||
/*
|
||||
// Add on correction due to kurtosis.
|
||||
// Disabled for now, seems to make things worse?
|
||||
//
|
||||
if(lambda >= 10)
|
||||
w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
|
||||
*/
|
||||
w = m + sigma * w;
|
||||
return w > tools::min_value<T>() ? w : tools::min_value<T>();
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T gamma_inva_imp(const T& z, const T& p, const T& q, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // for ADL of std lib math functions
|
||||
//
|
||||
// Special cases first:
|
||||
//
|
||||
if(p == 0)
|
||||
{
|
||||
return tools::max_value<T>();
|
||||
}
|
||||
if(q == 0)
|
||||
{
|
||||
return tools::min_value<T>();
|
||||
}
|
||||
//
|
||||
// Function object, this is the functor whose root
|
||||
// we have to solve:
|
||||
//
|
||||
gamma_inva_t<T, Policy> f(z, (p < q) ? p : q, (p < q) ? false : true);
|
||||
//
|
||||
// Tolerance: full precision.
|
||||
//
|
||||
tools::eps_tolerance<T> tol(policies::digits<T, Policy>());
|
||||
//
|
||||
// Now figure out a starting guess for what a may be,
|
||||
// we'll start out with a value that'll put p or q
|
||||
// right bang in the middle of their range, the functions
|
||||
// are quite sensitive so we should need too many steps
|
||||
// to bracket the root from there:
|
||||
//
|
||||
T guess;
|
||||
T factor = 8;
|
||||
if(z >= 1)
|
||||
{
|
||||
//
|
||||
// We can use the relationship between the incomplete
|
||||
// gamma function and the poisson distribution to
|
||||
// calculate an approximate inverse, for large z
|
||||
// this is actually pretty accurate, but it fails badly
|
||||
// when z is very small. Also set our step-factor according
|
||||
// to how accurate we think the result is likely to be:
|
||||
//
|
||||
guess = 1 + inverse_poisson_cornish_fisher(z, q, p, pol);
|
||||
if(z > 5)
|
||||
{
|
||||
if(z > 1000)
|
||||
factor = 1.01f;
|
||||
else if(z > 50)
|
||||
factor = 1.1f;
|
||||
else if(guess > 10)
|
||||
factor = 1.25f;
|
||||
else
|
||||
factor = 2;
|
||||
if(guess < 1.1)
|
||||
factor = 8;
|
||||
}
|
||||
}
|
||||
else if(z > 0.5)
|
||||
{
|
||||
guess = z * 1.2f;
|
||||
}
|
||||
else
|
||||
{
|
||||
guess = -0.4f / log(z);
|
||||
}
|
||||
//
|
||||
// Max iterations permitted:
|
||||
//
|
||||
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
||||
//
|
||||
// Use our generic derivative-free root finding procedure.
|
||||
// We could use Newton steps here, taking the PDF of the
|
||||
// Poisson distribution as our derivative, but that's
|
||||
// even worse performance-wise than the generic method :-(
|
||||
//
|
||||
std::pair<T, T> r = bracket_and_solve_root(f, guess, factor, false, tol, max_iter, pol);
|
||||
if(max_iter >= policies::get_max_root_iterations<Policy>())
|
||||
policies::raise_evaluation_error<T>("boost::math::gamma_p_inva<%1%>(%1%, %1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol);
|
||||
return (r.first + r.second) / 2;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class 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
|
||||
|
||||
|
||||
319
include/boost/math/special_functions/detail/ibeta_inv_ab.hpp
Normal file
319
include/boost/math/special_functions/detail/ibeta_inv_ab.hpp
Normal file
@@ -0,0 +1,319 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
//
|
||||
// This is not a complete header file, it is included by beta.hpp
|
||||
// after it has defined it's definitions. This inverts the incomplete
|
||||
// beta functions ibeta and ibetac on the first parameters "a"
|
||||
// and "b" using a generic root finding algorithm (TOMS Algorithm 748).
|
||||
//
|
||||
|
||||
#ifndef BOOST_MATH_SP_DETAIL_BETA_INV_AB
|
||||
#define BOOST_MATH_SP_DETAIL_BETA_INV_AB
|
||||
|
||||
#include <boost/math/tools/toms748_solve.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
template <class T, class Policy>
|
||||
struct beta_inv_ab_t
|
||||
{
|
||||
beta_inv_ab_t(T b_, T z_, T p_, bool invert_, bool swap_ab_) : b(b_), z(z_), p(p_), invert(invert_), swap_ab(swap_ab_) {}
|
||||
T operator()(T a)
|
||||
{
|
||||
return invert ?
|
||||
p - boost::math::ibetac(swap_ab ? b : a, swap_ab ? a : b, z, Policy())
|
||||
: boost::math::ibeta(swap_ab ? b : a, swap_ab ? a : b, z, Policy()) - p;
|
||||
}
|
||||
private:
|
||||
T b, z, p;
|
||||
bool invert, swap_ab;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
T inverse_negative_binomial_cornish_fisher(T n, T sf, T sfc, T p, T q, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
// mean:
|
||||
T m = n * (sfc) / sf;
|
||||
T t = sqrt(n * (sfc));
|
||||
// standard deviation:
|
||||
T sigma = t / sf;
|
||||
// skewness
|
||||
T sk = (1 + sfc) / t;
|
||||
// kurtosis:
|
||||
T k = (6 - sf * (5+sfc)) / (n * (sfc));
|
||||
// Get the inverse of a std normal distribution:
|
||||
T x = boost::math::erfc_inv(p > q ? 2 * q : 2 * p, pol) * constants::root_two<T>();
|
||||
// Set the sign:
|
||||
if(p < 0.5)
|
||||
x = -x;
|
||||
T x2 = x * x;
|
||||
// w is correction term due to skewness
|
||||
T w = x + sk * (x2 - 1) / 6;
|
||||
//
|
||||
// Add on correction due to kurtosis.
|
||||
//
|
||||
if(n >= 10)
|
||||
w += k * x * (x2 - 3) / 24 + sk * sk * x * (2 * x2 - 5) / -36;
|
||||
|
||||
w = m + sigma * w;
|
||||
if(w < tools::min_value<T>())
|
||||
return tools::min_value<T>();
|
||||
return w;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T ibeta_inv_ab_imp(const T& b, const T& z, const T& p, const T& q, bool swap_ab, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // for ADL of std lib math functions
|
||||
//
|
||||
// Special cases first:
|
||||
//
|
||||
BOOST_MATH_INSTRUMENT_CODE("b = " << b << " z = " << z << " p = " << p << " q = " << " swap = " << swap_ab);
|
||||
if(p == 0)
|
||||
{
|
||||
return swap_ab ? tools::min_value<T>() : tools::max_value<T>();
|
||||
}
|
||||
if(q == 0)
|
||||
{
|
||||
return swap_ab ? tools::max_value<T>() : tools::min_value<T>();
|
||||
}
|
||||
//
|
||||
// Function object, this is the functor whose root
|
||||
// we have to solve:
|
||||
//
|
||||
beta_inv_ab_t<T, Policy> f(b, z, (p < q) ? p : q, (p < q) ? false : true, swap_ab);
|
||||
//
|
||||
// Tolerance: full precision.
|
||||
//
|
||||
tools::eps_tolerance<T> tol(policies::digits<T, Policy>());
|
||||
//
|
||||
// Now figure out a starting guess for what a may be,
|
||||
// we'll start out with a value that'll put p or q
|
||||
// right bang in the middle of their range, the functions
|
||||
// are quite sensitive so we should need too many steps
|
||||
// to bracket the root from there:
|
||||
//
|
||||
T guess = 0;
|
||||
T factor = 5;
|
||||
//
|
||||
// Convert variables to parameters of a negative binomial distribution:
|
||||
//
|
||||
T n = b;
|
||||
T sf = swap_ab ? z : 1-z;
|
||||
T sfc = swap_ab ? 1-z : z;
|
||||
T u = swap_ab ? p : q;
|
||||
T v = swap_ab ? q : p;
|
||||
if(u <= pow(sf, n))
|
||||
{
|
||||
//
|
||||
// Result is less than 1, negative binomial approximation
|
||||
// is useless....
|
||||
//
|
||||
if((p < q) != swap_ab)
|
||||
{
|
||||
guess = (std::min)(b * 2, T(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
guess = (std::min)(b / 2, T(1));
|
||||
}
|
||||
}
|
||||
if(n * n * n * u * sf > 0.005)
|
||||
guess = 1 + inverse_negative_binomial_cornish_fisher(n, sf, sfc, u, v, pol);
|
||||
|
||||
if(guess < 10)
|
||||
{
|
||||
//
|
||||
// Negative binomial approximation not accurate in this area:
|
||||
//
|
||||
if((p < q) != swap_ab)
|
||||
{
|
||||
guess = (std::min)(b * 2, T(10));
|
||||
}
|
||||
else
|
||||
{
|
||||
guess = (std::min)(b / 2, T(10));
|
||||
}
|
||||
}
|
||||
else
|
||||
factor = (v < sqrt(tools::epsilon<T>())) ? 2 : (guess < 20 ? 1.2f : 1.1f);
|
||||
BOOST_MATH_INSTRUMENT_CODE("guess = " << guess);
|
||||
//
|
||||
// Max iterations permitted:
|
||||
//
|
||||
boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
||||
std::pair<T, T> r = bracket_and_solve_root(f, guess, factor, swap_ab ? true : false, tol, max_iter, pol);
|
||||
if(max_iter >= policies::get_max_root_iterations<Policy>())
|
||||
policies::raise_evaluation_error<T>("boost::math::ibeta_invab_imp<%1%>(%1%,%1%,%1%)", "Unable to locate the root within a reasonable number of iterations, closest approximation so far was %1%", r.first, pol);
|
||||
return (r.first + r.second) / 2;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class 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
|
||||
|
||||
|
||||
934
include/boost/math/special_functions/detail/ibeta_inverse.hpp
Normal file
934
include/boost/math/special_functions/detail/ibeta_inverse.hpp
Normal file
@@ -0,0 +1,934 @@
|
||||
// Copyright John Maddock 2006.
|
||||
// Copyright Paul A. Bristow 2007
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
|
||||
#define BOOST_MATH_SPECIAL_FUNCTIONS_IBETA_INVERSE_HPP
|
||||
|
||||
#include <boost/math/special_functions/beta.hpp>
|
||||
#include <boost/math/special_functions/erf.hpp>
|
||||
#include <boost/math/tools/roots.hpp>
|
||||
#include <boost/math/special_functions/detail/t_distribution_inv.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
//
|
||||
// Helper object used by root finding
|
||||
// code to convert eta to x.
|
||||
//
|
||||
template <class T>
|
||||
struct temme_root_finder
|
||||
{
|
||||
temme_root_finder(const T t_, const T a_) : t(t_), a(a_) {}
|
||||
|
||||
std::tr1::tuple<T, T> operator()(T x)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
|
||||
T y = 1 - x;
|
||||
if(y == 0)
|
||||
{
|
||||
T big = tools::max_value<T>() / 4;
|
||||
return std::tr1::make_tuple(-big, -big);
|
||||
}
|
||||
if(x == 0)
|
||||
{
|
||||
T big = tools::max_value<T>() / 4;
|
||||
return std::tr1::make_tuple(-big, big);
|
||||
}
|
||||
T f = log(x) + a * log(y) + t;
|
||||
T f1 = (1 / x) - (a / (y));
|
||||
return std::tr1::make_tuple(f, f1);
|
||||
}
|
||||
private:
|
||||
T t, a;
|
||||
};
|
||||
//
|
||||
// See:
|
||||
// "Asymptotic Inversion of the Incomplete Beta Function"
|
||||
// N.M. Temme
|
||||
// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
|
||||
// Section 2.
|
||||
//
|
||||
template <class T, class Policy>
|
||||
T temme_method_1_ibeta_inverse(T a, T b, T z, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
|
||||
const T r2 = sqrt(T(2));
|
||||
//
|
||||
// get the first approximation for eta from the inverse
|
||||
// error function (Eq: 2.9 and 2.10).
|
||||
//
|
||||
T eta0 = boost::math::erfc_inv(2 * z, pol);
|
||||
eta0 /= -sqrt(a / 2);
|
||||
|
||||
T terms[4] = { eta0 };
|
||||
T workspace[7];
|
||||
//
|
||||
// calculate powers:
|
||||
//
|
||||
T B = b - a;
|
||||
T B_2 = B * B;
|
||||
T B_3 = B_2 * B;
|
||||
//
|
||||
// Calculate correction terms:
|
||||
//
|
||||
|
||||
// See eq following 2.15:
|
||||
workspace[0] = -B * r2 / 2;
|
||||
workspace[1] = (1 - 2 * B) / 8;
|
||||
workspace[2] = -(B * r2 / 48);
|
||||
workspace[3] = T(-1) / 192;
|
||||
workspace[4] = -B * r2 / 3840;
|
||||
terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
|
||||
// Eq Following 2.17:
|
||||
workspace[0] = B * r2 * (3 * B - 2) / 12;
|
||||
workspace[1] = (20 * B_2 - 12 * B + 1) / 128;
|
||||
workspace[2] = B * r2 * (20 * B - 1) / 960;
|
||||
workspace[3] = (16 * B_2 + 30 * B - 15) / 4608;
|
||||
workspace[4] = B * r2 * (21 * B + 32) / 53760;
|
||||
workspace[5] = (-32 * B_2 + 63) / 368640;
|
||||
workspace[6] = -B * r2 * (120 * B + 17) / 25804480;
|
||||
terms[2] = tools::evaluate_polynomial(workspace, eta0, 7);
|
||||
// Eq Following 2.17:
|
||||
workspace[0] = B * r2 * (-75 * B_2 + 80 * B - 16) / 480;
|
||||
workspace[1] = (-1080 * B_3 + 868 * B_2 - 90 * B - 45) / 9216;
|
||||
workspace[2] = B * r2 * (-1190 * B_2 + 84 * B + 373) / 53760;
|
||||
workspace[3] = (-2240 * B_3 - 2508 * B_2 + 2100 * B - 165) / 368640;
|
||||
terms[3] = tools::evaluate_polynomial(workspace, eta0, 4);
|
||||
//
|
||||
// Bring them together to get a final estimate for eta:
|
||||
//
|
||||
T eta = tools::evaluate_polynomial(terms, 1/a, 4);
|
||||
//
|
||||
// now we need to convert eta to x, by solving the appropriate
|
||||
// quadratic equation:
|
||||
//
|
||||
T eta_2 = eta * eta;
|
||||
T c = -exp(-eta_2 / 2);
|
||||
T x;
|
||||
if(eta_2 == 0)
|
||||
x = 0.5;
|
||||
else
|
||||
x = (1 + eta * sqrt((1 + c) / eta_2)) / 2;
|
||||
|
||||
BOOST_ASSERT(x >= 0);
|
||||
BOOST_ASSERT(x <= 1);
|
||||
BOOST_ASSERT(eta * (x - 0.5) >= 0);
|
||||
#ifdef BOOST_INSTRUMENT
|
||||
std::cout << "Estimating x with Temme method 1: " << x << std::endl;
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
//
|
||||
// See:
|
||||
// "Asymptotic Inversion of the Incomplete Beta Function"
|
||||
// N.M. Temme
|
||||
// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
|
||||
// Section 3.
|
||||
//
|
||||
template <class T, class Policy>
|
||||
T temme_method_2_ibeta_inverse(T /*a*/, T /*b*/, T z, T r, T theta, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
|
||||
//
|
||||
// Get first estimate for eta, see Eq 3.9 and 3.10,
|
||||
// but note there is a typo in Eq 3.10:
|
||||
//
|
||||
T eta0 = boost::math::erfc_inv(2 * z, pol);
|
||||
eta0 /= -sqrt(r / 2);
|
||||
|
||||
T s = sin(theta);
|
||||
T c = cos(theta);
|
||||
//
|
||||
// Now we need to purturb eta0 to get eta, which we do by
|
||||
// evaluating the polynomial in 1/r at the bottom of page 151,
|
||||
// to do this we first need the error terms e1, e2 e3
|
||||
// which we'll fill into the array "terms". Since these
|
||||
// terms are themselves polynomials, we'll need another
|
||||
// array "workspace" to calculate those...
|
||||
//
|
||||
T terms[4] = { eta0 };
|
||||
T workspace[6];
|
||||
//
|
||||
// some powers of sin(theta)cos(theta) that we'll need later:
|
||||
//
|
||||
T sc = s * c;
|
||||
T sc_2 = sc * sc;
|
||||
T sc_3 = sc_2 * sc;
|
||||
T sc_4 = sc_2 * sc_2;
|
||||
T sc_5 = sc_2 * sc_3;
|
||||
T sc_6 = sc_3 * sc_3;
|
||||
T sc_7 = sc_4 * sc_3;
|
||||
//
|
||||
// Calculate e1 and put it in terms[1], see the middle of page 151:
|
||||
//
|
||||
workspace[0] = (2 * s * s - 1) / (3 * s * c);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co1[] = { -1, -5, 5 };
|
||||
workspace[1] = -tools::evaluate_even_polynomial(co1, s, 3) / (36 * sc_2);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co2[] = { 1, 21, -69, 46 };
|
||||
workspace[2] = tools::evaluate_even_polynomial(co2, s, 4) / (1620 * sc_3);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 7, -2, 33, -62, 31 };
|
||||
workspace[3] = -tools::evaluate_even_polynomial(co3, s, 5) / (6480 * sc_4);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 25, -52, -17, 88, -115, 46 };
|
||||
workspace[4] = tools::evaluate_even_polynomial(co4, s, 6) / (90720 * sc_5);
|
||||
terms[1] = tools::evaluate_polynomial(workspace, eta0, 5);
|
||||
//
|
||||
// Now evaluate e2 and put it in terms[2]:
|
||||
//
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co5[] = { 7, 12, -78, 52 };
|
||||
workspace[0] = -tools::evaluate_even_polynomial(co5, s, 4) / (405 * sc_3);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co6[] = { -7, 2, 183, -370, 185 };
|
||||
workspace[1] = tools::evaluate_even_polynomial(co6, s, 5) / (2592 * sc_4);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co7[] = { -533, 776, -1835, 10240, -13525, 5410 };
|
||||
workspace[2] = -tools::evaluate_even_polynomial(co7, s, 6) / (204120 * sc_5);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co8[] = { -1579, 3747, -3372, -15821, 45588, -45213, 15071 };
|
||||
workspace[3] = -tools::evaluate_even_polynomial(co8, s, 7) / (2099520 * sc_6);
|
||||
terms[2] = tools::evaluate_polynomial(workspace, eta0, 4);
|
||||
//
|
||||
// And e3, and put it in terms[3]:
|
||||
//
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co9[] = {449, -1259, -769, 6686, -9260, 3704 };
|
||||
workspace[0] = tools::evaluate_even_polynomial(co9, s, 6) / (102060 * sc_5);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co10[] = { 63149, -151557, 140052, -727469, 2239932, -2251437, 750479 };
|
||||
workspace[1] = -tools::evaluate_even_polynomial(co10, s, 7) / (20995200 * sc_6);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co11[] = { 29233, -78755, 105222, 146879, -1602610, 3195183, -2554139, 729754 };
|
||||
workspace[2] = tools::evaluate_even_polynomial(co11, s, 8) / (36741600 * sc_7);
|
||||
terms[3] = tools::evaluate_polynomial(workspace, eta0, 3);
|
||||
//
|
||||
// Bring the correction terms together to evaluate eta,
|
||||
// this is the last equation on page 151:
|
||||
//
|
||||
T eta = tools::evaluate_polynomial(terms, 1/r, 4);
|
||||
//
|
||||
// Now that we have eta we need to back solve for x,
|
||||
// we seek the value of x that gives eta in Eq 3.2.
|
||||
// The two methods used are described in section 5.
|
||||
//
|
||||
// Begin by defining a few variables we'll need later:
|
||||
//
|
||||
T x;
|
||||
T s_2 = s * s;
|
||||
T c_2 = c * c;
|
||||
T alpha = c / s;
|
||||
alpha *= alpha;
|
||||
T lu = (-(eta * eta) / (2 * s_2) + log(s_2) + c_2 * log(c_2) / s_2);
|
||||
//
|
||||
// Temme doesn't specify what value to switch on here,
|
||||
// but this seems to work pretty well:
|
||||
//
|
||||
if(fabs(eta) < 0.7)
|
||||
{
|
||||
//
|
||||
// Small eta use the expansion Temme gives in the second equation
|
||||
// of section 5, it's a polynomial in eta:
|
||||
//
|
||||
workspace[0] = s * s;
|
||||
workspace[1] = s * c;
|
||||
workspace[2] = (1 - 2 * workspace[0]) / 3;
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co3[] = { 1, -13, 13 };
|
||||
workspace[3] = tools::evaluate_polynomial(co3, workspace[0], 3) / (36 * s * c);
|
||||
static const BOOST_MATH_INT_TABLE_TYPE(T, int) co4[] = { 1, 21, -69, 46 };
|
||||
workspace[4] = tools::evaluate_polynomial(co4, workspace[0], 4) / (270 * workspace[0] * c * c);
|
||||
x = tools::evaluate_polynomial(workspace, eta, 5);
|
||||
#ifdef BOOST_INSTRUMENT
|
||||
std::cout << "Estimating x with Temme method 2 (small eta): " << x << std::endl;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If eta is large we need to solve Eq 3.2 more directly,
|
||||
// begin by getting an initial approximation for x from
|
||||
// the last equation on page 155, this is a polynomial in u:
|
||||
//
|
||||
T u = exp(lu);
|
||||
workspace[0] = u;
|
||||
workspace[1] = alpha;
|
||||
workspace[2] = 0;
|
||||
workspace[3] = 3 * alpha * (3 * alpha + 1) / 6;
|
||||
workspace[4] = 4 * alpha * (4 * alpha + 1) * (4 * alpha + 2) / 24;
|
||||
workspace[5] = 5 * alpha * (5 * alpha + 1) * (5 * alpha + 2) * (5 * alpha + 3) / 120;
|
||||
x = tools::evaluate_polynomial(workspace, u, 6);
|
||||
//
|
||||
// At this point we may or may not have the right answer, Eq-3.2 has
|
||||
// two solutions for x for any given eta, however the mapping in 3.2
|
||||
// is 1:1 with the sign of eta and x-sin^2(theta) being the same.
|
||||
// So we can check if we have the right root of 3.2, and if not
|
||||
// switch x for 1-x. This transformation is motivated by the fact
|
||||
// that the distribution is *almost* symetric so 1-x will be in the right
|
||||
// ball park for the solution:
|
||||
//
|
||||
if((x - s_2) * eta < 0)
|
||||
x = 1 - x;
|
||||
#ifdef BOOST_INSTRUMENT
|
||||
std::cout << "Estimating x with Temme method 2 (large eta): " << x << std::endl;
|
||||
#endif
|
||||
}
|
||||
//
|
||||
// The final step is a few Newton-Raphson iterations to
|
||||
// clean up our approximation for x, this is pretty cheap
|
||||
// in general, and very cheap compared to an incomplete beta
|
||||
// evaluation. The limits set on x come from the observation
|
||||
// that the sign of eta and x-sin^2(theta) are the same.
|
||||
//
|
||||
T lower, upper;
|
||||
if(eta < 0)
|
||||
{
|
||||
lower = 0;
|
||||
upper = s_2;
|
||||
}
|
||||
else
|
||||
{
|
||||
lower = s_2;
|
||||
upper = 1;
|
||||
}
|
||||
//
|
||||
// If our initial approximation is out of bounds then bisect:
|
||||
//
|
||||
if((x < lower) || (x > upper))
|
||||
x = (lower+upper) / 2;
|
||||
//
|
||||
// And iterate:
|
||||
//
|
||||
x = tools::newton_raphson_iterate(
|
||||
temme_root_finder<T>(-lu, alpha), x, lower, upper, policies::digits<T, Policy>() / 2);
|
||||
|
||||
return x;
|
||||
}
|
||||
//
|
||||
// See:
|
||||
// "Asymptotic Inversion of the Incomplete Beta Function"
|
||||
// N.M. Temme
|
||||
// Journal of Computation and Applied Mathematics 41 (1992) 145-157.
|
||||
// Section 4.
|
||||
//
|
||||
template <class T, class Policy>
|
||||
T temme_method_3_ibeta_inverse(T a, T b, T p, T q, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
|
||||
//
|
||||
// Begin by getting an initial approximation for the quantity
|
||||
// eta from the dominant part of the incomplete beta:
|
||||
//
|
||||
T eta0;
|
||||
if(p < q)
|
||||
eta0 = boost::math::gamma_q_inv(b, p, pol);
|
||||
else
|
||||
eta0 = boost::math::gamma_p_inv(b, q, pol);
|
||||
eta0 /= a;
|
||||
//
|
||||
// Define the variables and powers we'll need later on:
|
||||
//
|
||||
T mu = b / a;
|
||||
T w = sqrt(1 + mu);
|
||||
T w_2 = w * w;
|
||||
T w_3 = w_2 * w;
|
||||
T w_4 = w_2 * w_2;
|
||||
T w_5 = w_3 * w_2;
|
||||
T w_6 = w_3 * w_3;
|
||||
T w_7 = w_4 * w_3;
|
||||
T w_8 = w_4 * w_4;
|
||||
T w_9 = w_5 * w_4;
|
||||
T w_10 = w_5 * w_5;
|
||||
T d = eta0 - mu;
|
||||
T d_2 = d * d;
|
||||
T d_3 = d_2 * d;
|
||||
T d_4 = d_2 * d_2;
|
||||
T w1 = w + 1;
|
||||
T w1_2 = w1 * w1;
|
||||
T w1_3 = w1 * w1_2;
|
||||
T w1_4 = w1_2 * w1_2;
|
||||
//
|
||||
// Now we need to compute the purturbation error terms that
|
||||
// convert eta0 to eta, these are all polynomials of polynomials.
|
||||
// Probably these should be re-written to use tabulated data
|
||||
// (see examples above), but it's less of a win in this case as we
|
||||
// need to calculate the individual powers for the denominator terms
|
||||
// anyway, so we might as well use them for the numerator-polynomials
|
||||
// as well....
|
||||
//
|
||||
// Refer to p154-p155 for the details of these expansions:
|
||||
//
|
||||
T e1 = (w + 2) * (w - 1) / (3 * w);
|
||||
e1 += (w_3 + 9 * w_2 + 21 * w + 5) * d / (36 * w_2 * w1);
|
||||
e1 -= (w_4 - 13 * w_3 + 69 * w_2 + 167 * w + 46) * d_2 / (1620 * w1_2 * w_3);
|
||||
e1 -= (7 * w_5 + 21 * w_4 + 70 * w_3 + 26 * w_2 - 93 * w - 31) * d_3 / (6480 * w1_3 * w_4);
|
||||
e1 -= (75 * w_6 + 202 * w_5 + 188 * w_4 - 888 * w_3 - 1345 * w_2 + 118 * w + 138) * d_4 / (272160 * w1_4 * w_5);
|
||||
|
||||
T e2 = (28 * w_4 + 131 * w_3 + 402 * w_2 + 581 * w + 208) * (w - 1) / (1620 * w1 * w_3);
|
||||
e2 -= (35 * w_6 - 154 * w_5 - 623 * w_4 - 1636 * w_3 - 3983 * w_2 - 3514 * w - 925) * d / (12960 * w1_2 * w_4);
|
||||
e2 -= (2132 * w_7 + 7915 * w_6 + 16821 * w_5 + 35066 * w_4 + 87490 * w_3 + 141183 * w_2 + 95993 * w + 21640) * d_2 / (816480 * w_5 * w1_3);
|
||||
e2 -= (11053 * w_8 + 53308 * w_7 + 117010 * w_6 + 163924 * w_5 + 116188 * w_4 - 258428 * w_3 - 677042 * w_2 - 481940 * w - 105497) * d_3 / (14696640 * w1_4 * w_6);
|
||||
|
||||
T e3 = -((3592 * w_7 + 8375 * w_6 - 1323 * w_5 - 29198 * w_4 - 89578 * w_3 - 154413 * w_2 - 116063 * w - 29632) * (w - 1)) / (816480 * w_5 * w1_2);
|
||||
e3 -= (442043 * w_9 + 2054169 * w_8 + 3803094 * w_7 + 3470754 * w_6 + 2141568 * w_5 - 2393568 * w_4 - 19904934 * w_3 - 34714674 * w_2 - 23128299 * w - 5253353) * d / (146966400 * w_6 * w1_3);
|
||||
e3 -= (116932 * w_10 + 819281 * w_9 + 2378172 * w_8 + 4341330 * w_7 + 6806004 * w_6 + 10622748 * w_5 + 18739500 * w_4 + 30651894 * w_3 + 30869976 * w_2 + 15431867 * w + 2919016) * d_2 / (146966400 * w1_4 * w_7);
|
||||
//
|
||||
// Combine eta0 and the error terms to compute eta (Second eqaution p155):
|
||||
//
|
||||
T eta = eta0 + e1 / a + e2 / (a * a) + e3 / (a * a * a);
|
||||
//
|
||||
// Now we need to solve Eq 4.2 to obtain x. For any given value of
|
||||
// eta there are two solutions to this equation, and since the distribtion
|
||||
// may be very skewed, these are not related by x ~ 1-x we used when
|
||||
// implementing section 3 above. However we know that:
|
||||
//
|
||||
// cross < x <= 1 ; iff eta < mu
|
||||
// x == cross ; iff eta == mu
|
||||
// 0 <= x < cross ; iff eta > mu
|
||||
//
|
||||
// Where cross == 1 / (1 + mu)
|
||||
// Many thanks to Prof Temme for clarifying this point.
|
||||
//
|
||||
// Therefore we'll just jump straight into Newton iterations
|
||||
// to solve Eq 4.2 using these bounds, and simple bisection
|
||||
// as the first guess, in practice this converges pretty quickly
|
||||
// and we only need a few digits correct anyway:
|
||||
//
|
||||
if(eta <= 0)
|
||||
eta = tools::min_value<T>();
|
||||
T u = eta - mu * log(eta) + (1 + mu) * log(1 + mu) - mu;
|
||||
T cross = 1 / (1 + mu);
|
||||
T lower = eta < mu ? cross : 0;
|
||||
T upper = eta < mu ? 1 : cross;
|
||||
T x = (lower + upper) / 2;
|
||||
x = tools::newton_raphson_iterate(
|
||||
temme_root_finder<T>(u, mu), x, lower, upper, policies::digits<T, Policy>() / 2);
|
||||
#ifdef BOOST_INSTRUMENT
|
||||
std::cout << "Estimating x with Temme method 3: " << x << std::endl;
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
struct ibeta_roots
|
||||
{
|
||||
ibeta_roots(T _a, T _b, T t, bool inv = false)
|
||||
: a(_a), b(_b), target(t), invert(inv) {}
|
||||
|
||||
std::tr1::tuple<T, T, T> operator()(T x)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
|
||||
T f1;
|
||||
T y = 1 - x;
|
||||
T f = ibeta_imp(a, b, x, Policy(), invert, true, &f1) - target;
|
||||
if(invert)
|
||||
f1 = -f1;
|
||||
if(y == 0)
|
||||
y = tools::min_value<T>() * 64;
|
||||
if(x == 0)
|
||||
x = tools::min_value<T>() * 64;
|
||||
|
||||
T f2 = f1 * (-y * a + (b - 2) * x + 1);
|
||||
if(fabs(f2) < y * x * tools::max_value<T>())
|
||||
f2 /= (y * x);
|
||||
if(invert)
|
||||
f2 = -f2;
|
||||
|
||||
// make sure we don't have a zero derivative:
|
||||
if(f1 == 0)
|
||||
f1 = (invert ? -1 : 1) * tools::min_value<T>() * 64;
|
||||
|
||||
return std::tr1::make_tuple(f, f1, f2);
|
||||
}
|
||||
private:
|
||||
T a, b, target;
|
||||
bool invert;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
T ibeta_inv_imp(T a, T b, T p, T q, const Policy& pol, T* py)
|
||||
{
|
||||
BOOST_MATH_STD_USING // For ADL of math functions.
|
||||
|
||||
//
|
||||
// The flag invert is set to true if we swap a for b and p for q,
|
||||
// in which case the result has to be subtracted from 1:
|
||||
//
|
||||
bool invert = false;
|
||||
//
|
||||
// Depending upon which approximation method we use, we may end up
|
||||
// calculating either x or y initially (where y = 1-x):
|
||||
//
|
||||
T x = 0; // Set to a safe zero to avoid a
|
||||
// MSVC 2005 warning C4701: potentially uninitialized local variable 'x' used
|
||||
// But code inspection appears to ensure that x IS assigned whatever the code path.
|
||||
T y;
|
||||
|
||||
// For some of the methods we can put tighter bounds
|
||||
// on the result than simply [0,1]:
|
||||
//
|
||||
T lower = 0;
|
||||
T upper = 1;
|
||||
//
|
||||
// Student's T with b = 0.5 gets handled as a special case, swap
|
||||
// around if the arguments are in the "wrong" order:
|
||||
//
|
||||
if(a == 0.5f)
|
||||
{
|
||||
std::swap(a, b);
|
||||
std::swap(p, q);
|
||||
invert = !invert;
|
||||
}
|
||||
//
|
||||
// Handle trivial cases first:
|
||||
//
|
||||
if(q == 0)
|
||||
{
|
||||
if(py) *py = 0;
|
||||
return 1;
|
||||
}
|
||||
else if(p == 0)
|
||||
{
|
||||
if(py) *py = 1;
|
||||
return 0;
|
||||
}
|
||||
else if((a == 1) && (b == 1))
|
||||
{
|
||||
if(py) *py = 1 - p;
|
||||
return p;
|
||||
}
|
||||
else if((b == 0.5f) && (a >= 0.5f))
|
||||
{
|
||||
//
|
||||
// We have a Student's T distribution:
|
||||
x = find_ibeta_inv_from_t_dist(a, p, q, &y, pol);
|
||||
}
|
||||
else if(a + b > 5)
|
||||
{
|
||||
//
|
||||
// When a+b is large then we can use one of Prof Temme's
|
||||
// asymptotic expansions, begin by swapping things around
|
||||
// so that p < 0.5, we do this to avoid cancellations errors
|
||||
// when p is large.
|
||||
//
|
||||
if(p > 0.5)
|
||||
{
|
||||
std::swap(a, b);
|
||||
std::swap(p, q);
|
||||
invert = !invert;
|
||||
}
|
||||
T minv = (std::min)(a, b);
|
||||
T maxv = (std::max)(a, b);
|
||||
if((sqrt(minv) > (maxv - minv)) && (minv > 5))
|
||||
{
|
||||
//
|
||||
// When a and b differ by a small amount
|
||||
// the curve is quite symmetrical and we can use an error
|
||||
// function to approximate the inverse. This is the cheapest
|
||||
// of the three Temme expantions, and the calculated value
|
||||
// for x will never be much larger than p, so we don't have
|
||||
// to worry about cancellation as long as p is small.
|
||||
//
|
||||
x = temme_method_1_ibeta_inverse(a, b, p, pol);
|
||||
y = 1 - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
T r = a + b;
|
||||
T theta = asin(sqrt(a / r));
|
||||
T lambda = minv / r;
|
||||
if((lambda >= 0.2) && (lambda <= 0.8) && (lambda >= 10))
|
||||
{
|
||||
//
|
||||
// The second error function case is the next cheapest
|
||||
// to use, it brakes down when the result is likely to be
|
||||
// very small, if a+b is also small, but we can use a
|
||||
// cheaper expansion there in any case. As before x won't
|
||||
// be much larger than p, so as long as p is small we should
|
||||
// be free of cancellation error.
|
||||
//
|
||||
T ppa = pow(p, 1/a);
|
||||
if((ppa < 0.0025) && (a + b < 200))
|
||||
{
|
||||
x = ppa * pow(a * boost::math::beta(a, b, pol), 1/a);
|
||||
}
|
||||
else
|
||||
x = temme_method_2_ibeta_inverse(a, b, p, r, theta, pol);
|
||||
y = 1 - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If we get here then a and b are very different in magnitude
|
||||
// and we need to use the third of Temme's methods which
|
||||
// involves inverting the incomplete gamma. This is much more
|
||||
// expensive than the other methods. We also can only use this
|
||||
// method when a > b, which can lead to cancellation errors
|
||||
// if we really want y (as we will when x is close to 1), so
|
||||
// a different expansion is used in that case.
|
||||
//
|
||||
if(a < b)
|
||||
{
|
||||
std::swap(a, b);
|
||||
std::swap(p, q);
|
||||
invert = !invert;
|
||||
}
|
||||
//
|
||||
// Try and compute the easy way first:
|
||||
//
|
||||
T bet = 0;
|
||||
if(b < 2)
|
||||
bet = boost::math::beta(a, b, pol);
|
||||
if(bet != 0)
|
||||
{
|
||||
y = pow(b * q * bet, 1/b);
|
||||
x = 1 - y;
|
||||
}
|
||||
else
|
||||
y = 1;
|
||||
if(y > 1e-5)
|
||||
{
|
||||
x = temme_method_3_ibeta_inverse(a, b, p, q, pol);
|
||||
y = 1 - x;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if((a < 1) && (b < 1))
|
||||
{
|
||||
//
|
||||
// Both a and b less than 1,
|
||||
// there is a point of inflection at xs:
|
||||
//
|
||||
T xs = (1 - a) / (2 - a - b);
|
||||
//
|
||||
// Now we need to ensure that we start our iteration from the
|
||||
// right side of the inflection point:
|
||||
//
|
||||
T fs = boost::math::ibeta(a, b, xs, pol) - p;
|
||||
if(fabs(fs) / p < tools::epsilon<T>() * 3)
|
||||
{
|
||||
// The result is at the point of inflection, best just return it:
|
||||
*py = invert ? xs : 1 - xs;
|
||||
return invert ? 1-xs : xs;
|
||||
}
|
||||
if(fs < 0)
|
||||
{
|
||||
std::swap(a, b);
|
||||
std::swap(p, q);
|
||||
invert = true;
|
||||
xs = 1 - xs;
|
||||
}
|
||||
T xg = pow(a * p * boost::math::beta(a, b, pol), 1/a);
|
||||
x = xg / (1 + xg);
|
||||
y = 1 / (1 + xg);
|
||||
//
|
||||
// And finally we know that our result is below the inflection
|
||||
// point, so set an upper limit on our search:
|
||||
//
|
||||
if(x > xs)
|
||||
x = xs;
|
||||
upper = xs;
|
||||
}
|
||||
else if((a > 1) && (b > 1))
|
||||
{
|
||||
//
|
||||
// Small a and b, both greater than 1,
|
||||
// there is a point of inflection at xs,
|
||||
// and it's complement is xs2, we must always
|
||||
// start our iteration from the right side of the
|
||||
// point of inflection.
|
||||
//
|
||||
T xs = (a - 1) / (a + b - 2);
|
||||
T xs2 = (b - 1) / (a + b - 2);
|
||||
T ps = boost::math::ibeta(a, b, xs, pol) - p;
|
||||
|
||||
if(ps < 0)
|
||||
{
|
||||
std::swap(a, b);
|
||||
std::swap(p, q);
|
||||
std::swap(xs, xs2);
|
||||
invert = true;
|
||||
}
|
||||
//
|
||||
// Estimate x and y, using expm1 to get a good estimate
|
||||
// for y when it's very small:
|
||||
//
|
||||
T lx = log(p * a * boost::math::beta(a, b, pol)) / a;
|
||||
x = exp(lx);
|
||||
y = x < 0.9 ? 1 - x : -boost::math::expm1(lx, pol);
|
||||
|
||||
if((b < a) && (x < 0.2))
|
||||
{
|
||||
//
|
||||
// Under a limited range of circumstances we can improve
|
||||
// our estimate for x, frankly it's clear if this has much effect!
|
||||
//
|
||||
T ap1 = a - 1;
|
||||
T bm1 = b - 1;
|
||||
T a_2 = a * a;
|
||||
T a_3 = a * a_2;
|
||||
T b_2 = b * b;
|
||||
T terms[5] = { 0, 1 };
|
||||
terms[2] = bm1 / ap1;
|
||||
ap1 *= ap1;
|
||||
terms[3] = bm1 * (3 * a * b + 5 * b + a_2 - a - 4) / (2 * (a + 2) * ap1);
|
||||
ap1 *= (a + 1);
|
||||
terms[4] = bm1 * (33 * a * b_2 + 31 * b_2 + 8 * a_2 * b_2 - 30 * a * b - 47 * b + 11 * a_2 * b + 6 * a_3 * b + 18 + 4 * a - a_3 + a_2 * a_2 - 10 * a_2)
|
||||
/ (3 * (a + 3) * (a + 2) * ap1);
|
||||
x = tools::evaluate_polynomial(terms, x, 5);
|
||||
}
|
||||
//
|
||||
// And finally we know that our result is below the inflection
|
||||
// point, so set an upper limit on our search:
|
||||
//
|
||||
if(x > xs)
|
||||
x = xs;
|
||||
upper = xs;
|
||||
}
|
||||
else /*if((a <= 1) != (b <= 1))*/
|
||||
{
|
||||
//
|
||||
// If all else fails we get here, only one of a and b
|
||||
// is above 1, and a+b is small. Start by swapping
|
||||
// things around so that we have a concave curve with b > a
|
||||
// and no points of inflection in [0,1]. As long as we expect
|
||||
// x to be small then we can use the simple (and cheap) power
|
||||
// term to estimate x, but when we expect x to be large then
|
||||
// this greatly underestimates x and leaves us trying to
|
||||
// iterate "round the corner" which may take almost forever...
|
||||
//
|
||||
// We could use Temme's inverse gamma function case in that case,
|
||||
// this works really rather well (albeit expensively) even though
|
||||
// strictly speaking we're outside it's defined range.
|
||||
//
|
||||
// However it's expensive to compute, and an alternative approach
|
||||
// which models the curve as a distorted quarter circle is much
|
||||
// cheaper to compute, and still keeps the number of iterations
|
||||
// required down to a reasonable level. With thanks to Prof Temme
|
||||
// for this suggestion.
|
||||
//
|
||||
if(b < a)
|
||||
{
|
||||
std::swap(a, b);
|
||||
std::swap(p, q);
|
||||
invert = true;
|
||||
}
|
||||
if(pow(p, 1/a) < 0.5)
|
||||
{
|
||||
x = pow(p * a * boost::math::beta(a, b, pol), 1 / a);
|
||||
if(x == 0)
|
||||
x = boost::math::tools::min_value<T>();
|
||||
y = 1 - x;
|
||||
}
|
||||
else /*if(pow(q, 1/b) < 0.1)*/
|
||||
{
|
||||
// model a distorted quarter circle:
|
||||
y = pow(1 - pow(p, b * boost::math::beta(a, b, pol)), 1/b);
|
||||
if(y == 0)
|
||||
y = boost::math::tools::min_value<T>();
|
||||
x = 1 - y;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Now we have a guess for x (and for y) we can set things up for
|
||||
// iteration. If x > 0.5 it pays to swap things round:
|
||||
//
|
||||
if(x > 0.5)
|
||||
{
|
||||
std::swap(a, b);
|
||||
std::swap(p, q);
|
||||
std::swap(x, y);
|
||||
invert = !invert;
|
||||
T l = 1 - upper;
|
||||
T u = 1 - lower;
|
||||
lower = l;
|
||||
upper = u;
|
||||
}
|
||||
//
|
||||
// lower bound for our search:
|
||||
//
|
||||
// We're not interested in denormalised answers as these tend to
|
||||
// these tend to take up lots of iterations, given that we can't get
|
||||
// accurate derivatives in this area (they tend to be infinite).
|
||||
//
|
||||
if(lower == 0)
|
||||
{
|
||||
if(invert && (py == 0))
|
||||
{
|
||||
//
|
||||
// We're not interested in answers smaller than machine epsilon:
|
||||
//
|
||||
lower = boost::math::tools::epsilon<T>();
|
||||
if(x < lower)
|
||||
x = lower;
|
||||
}
|
||||
else
|
||||
lower = boost::math::tools::min_value<T>();
|
||||
if(x < lower)
|
||||
x = lower;
|
||||
}
|
||||
//
|
||||
// Figure out how many digits to iterate towards:
|
||||
//
|
||||
int digits = boost::math::policies::digits<T, Policy>() / 2;
|
||||
if((x < 1e-50) && ((a < 1) || (b < 1)))
|
||||
{
|
||||
//
|
||||
// If we're in a region where the first derivative is very
|
||||
// large, then we have to take care that the root-finder
|
||||
// doesn't terminate prematurely. We'll bump the precision
|
||||
// up to avoid this, but we have to take care not to set the
|
||||
// precision too high or the last few iterations will just
|
||||
// thrash around and convergence may be slow in this case.
|
||||
// Try 3/4 of machine epsilon:
|
||||
//
|
||||
digits *= 3;
|
||||
digits /= 2;
|
||||
}
|
||||
//
|
||||
// Now iterate, we can use either p or q as the target here
|
||||
// depending on which is smaller:
|
||||
//
|
||||
x = boost::math::tools::halley_iterate(
|
||||
boost::math::detail::ibeta_roots<T, Policy>(a, b, (p < q ? p : q), (p < q ? false : true)), x, lower, upper, digits);
|
||||
//
|
||||
// We don't really want these asserts here, but they are useful for sanity
|
||||
// checking that we have the limits right, uncomment if you suspect bugs *only*.
|
||||
//
|
||||
//BOOST_ASSERT(x != upper);
|
||||
//BOOST_ASSERT((x != lower) || (x == boost::math::tools::min_value<T>()) || (x == boost::math::tools::epsilon<T>()));
|
||||
//
|
||||
// Tidy up, if we "lower" was too high then zero is the best answer we have:
|
||||
//
|
||||
if(x == lower)
|
||||
x = 0;
|
||||
if(py)
|
||||
*py = invert ? x : 1 - x;
|
||||
return invert ? 1-x : x;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class Policy>
|
||||
inline typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol)
|
||||
{
|
||||
static const char* function = "boost::math::ibeta_inv<%1%>(%1%,%1%,%1%)";
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
if(a <= 0)
|
||||
return policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
|
||||
if(b <= 0)
|
||||
return policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
|
||||
if((p < 0) || (p > 1))
|
||||
return policies::raise_domain_error<result_type>(function, "Argument p outside the range [0,1] in the incomplete beta function inverse (got p=%1%).", p, pol);
|
||||
|
||||
value_type rx, ry;
|
||||
|
||||
rx = detail::ibeta_inv_imp(
|
||||
static_cast<value_type>(a),
|
||||
static_cast<value_type>(b),
|
||||
static_cast<value_type>(p),
|
||||
static_cast<value_type>(1 - p),
|
||||
forwarding_policy(), &ry);
|
||||
|
||||
if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
|
||||
return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
inline typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibeta_inv(T1 a, T2 b, T3 p, T4* py)
|
||||
{
|
||||
return ibeta_inv(a, b, p, py, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
ibeta_inv(T1 a, T2 b, T3 p)
|
||||
{
|
||||
return ibeta_inv(a, b, p, static_cast<T1*>(0), policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
ibeta_inv(T1 a, T2 b, T3 p, const Policy& pol)
|
||||
{
|
||||
return ibeta_inv(a, b, p, static_cast<T1*>(0), pol);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class Policy>
|
||||
inline typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol)
|
||||
{
|
||||
static const char* function = "boost::math::ibetac_inv<%1%>(%1%,%1%,%1%)";
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
typedef typename tools::promote_args<T1, T2, T3, T4>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
if(a <= 0)
|
||||
policies::raise_domain_error<result_type>(function, "The argument a to the incomplete beta function inverse must be greater than zero (got a=%1%).", a, pol);
|
||||
if(b <= 0)
|
||||
policies::raise_domain_error<result_type>(function, "The argument b to the incomplete beta function inverse must be greater than zero (got b=%1%).", b, pol);
|
||||
if((q < 0) || (q > 1))
|
||||
policies::raise_domain_error<result_type>(function, "Argument q outside the range [0,1] in the incomplete beta function inverse (got q=%1%).", q, pol);
|
||||
|
||||
value_type rx, ry;
|
||||
|
||||
rx = detail::ibeta_inv_imp(
|
||||
static_cast<value_type>(a),
|
||||
static_cast<value_type>(b),
|
||||
static_cast<value_type>(1 - q),
|
||||
static_cast<value_type>(q),
|
||||
forwarding_policy(), &ry);
|
||||
|
||||
if(py) *py = policies::checked_narrowing_cast<T4, forwarding_policy>(ry, function);
|
||||
return policies::checked_narrowing_cast<result_type, forwarding_policy>(rx, function);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
inline typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibetac_inv(T1 a, T2 b, T3 q, T4* py)
|
||||
{
|
||||
return ibetac_inv(a, b, q, py, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
inline typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac_inv(RT1 a, RT2 b, RT3 q)
|
||||
{
|
||||
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
|
||||
|
||||
|
||||
|
||||
466
include/boost/math/special_functions/detail/igamma_inverse.hpp
Normal file
466
include/boost/math/special_functions/detail/igamma_inverse.hpp
Normal file
@@ -0,0 +1,466 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
|
||||
#define BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
|
||||
|
||||
#include <boost/math/special_functions/gamma.hpp>
|
||||
#include <boost/math/special_functions/sign.hpp>
|
||||
#include <boost/math/tools/roots.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/tr1/tuple.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class T>
|
||||
T find_inverse_s(T p, T q)
|
||||
{
|
||||
//
|
||||
// Computation of the Incomplete Gamma Function Ratios and their Inverse
|
||||
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
||||
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
||||
// December 1986, Pages 377-393.
|
||||
//
|
||||
// See equation 32.
|
||||
//
|
||||
BOOST_MATH_STD_USING
|
||||
T t;
|
||||
if(p < 0.5)
|
||||
{
|
||||
t = sqrt(-2 * log(p));
|
||||
}
|
||||
else
|
||||
{
|
||||
t = sqrt(-2 * log(q));
|
||||
}
|
||||
static const double a[4] = { 3.31125922108741, 11.6616720288968, 4.28342155967104, 0.213623493715853 };
|
||||
static const double b[5] = { 1, 6.61053765625462, 6.40691597760039, 1.27364489782223, 0.3611708101884203e-1 };
|
||||
T s = t - tools::evaluate_polynomial(a, t) / tools::evaluate_polynomial(b, t);
|
||||
if(p < 0.5)
|
||||
s = -s;
|
||||
return s;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T didonato_SN(T a, T x, unsigned N, T tolerance = 0)
|
||||
{
|
||||
//
|
||||
// Computation of the Incomplete Gamma Function Ratios and their Inverse
|
||||
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
||||
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
||||
// December 1986, Pages 377-393.
|
||||
//
|
||||
// See equation 34.
|
||||
//
|
||||
T sum = 1;
|
||||
if(N >= 1)
|
||||
{
|
||||
T partial = x / (a + 1);
|
||||
sum += partial;
|
||||
for(unsigned i = 2; i <= N; ++i)
|
||||
{
|
||||
partial *= x / (a + i);
|
||||
sum += partial;
|
||||
if(partial < tolerance)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T didonato_FN(T p, T a, T x, unsigned N, T tolerance, const Policy& pol)
|
||||
{
|
||||
//
|
||||
// Computation of the Incomplete Gamma Function Ratios and their Inverse
|
||||
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
||||
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
||||
// December 1986, Pages 377-393.
|
||||
//
|
||||
// See equation 34.
|
||||
//
|
||||
BOOST_MATH_STD_USING
|
||||
T u = log(p) + boost::math::lgamma(a + 1, pol);
|
||||
return exp((u + x - log(didonato_SN(a, x, N, tolerance))) / a);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T find_inverse_gamma(T a, T p, T q, const Policy& pol)
|
||||
{
|
||||
//
|
||||
// In order to understand what's going on here, you will
|
||||
// need to refer to:
|
||||
//
|
||||
// Computation of the Incomplete Gamma Function Ratios and their Inverse
|
||||
// ARMIDO R. DIDONATO and ALFRED H. MORRIS, JR.
|
||||
// ACM Transactions on Mathematical Software, Vol. 12, No. 4,
|
||||
// December 1986, Pages 377-393.
|
||||
//
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
T result;
|
||||
|
||||
if(a == 1)
|
||||
result = -log(q);
|
||||
else if(a < 1)
|
||||
{
|
||||
T g = boost::math::tgamma(a, pol);
|
||||
T b = q * g;
|
||||
if((b > 0.6) || ((b >= 0.45) && (a >= 0.3)))
|
||||
{
|
||||
// DiDonato & Morris Eq 21:
|
||||
//
|
||||
// There is a slight variation from DiDonato and Morris here:
|
||||
// the first form given here is unstable when p is close to 1,
|
||||
// making it impossible to compute the inverse of Q(a,x) for small
|
||||
// q. Fortunately the second form works perfectly well in this case.
|
||||
//
|
||||
T u;
|
||||
if((b * q > 1e-8) && (q > 1e-5))
|
||||
{
|
||||
u = pow(p * g * a, 1 / a);
|
||||
}
|
||||
else
|
||||
{
|
||||
u = exp((-q / a) - constants::euler<T>());
|
||||
}
|
||||
result = u / (1 - (u / (a + 1)));
|
||||
}
|
||||
else if((a < 0.3) && (b >= 0.35))
|
||||
{
|
||||
// DiDonato & Morris Eq 22:
|
||||
T t = exp(-constants::euler<T>() - b);
|
||||
T u = t * exp(t);
|
||||
result = t * exp(u);
|
||||
}
|
||||
else if((b > 0.15) || (a >= 0.3))
|
||||
{
|
||||
// DiDonato & Morris Eq 23:
|
||||
T y = -log(b);
|
||||
T u = y - (1 - a) * log(y);
|
||||
result = y - (1 - a) * log(u) - log(1 + (1 - a) / (1 + u));
|
||||
}
|
||||
else if (b > 0.1)
|
||||
{
|
||||
// DiDonato & Morris Eq 24:
|
||||
T y = -log(b);
|
||||
T u = y - (1 - a) * log(y);
|
||||
result = y - (1 - a) * log(u) - log((u * u + 2 * (3 - a) * u + (2 - a) * (3 - a)) / (u * u + (5 - a) * u + 2));
|
||||
}
|
||||
else
|
||||
{
|
||||
// DiDonato & Morris Eq 25:
|
||||
T y = -log(b);
|
||||
T c1 = (a - 1) * log(y);
|
||||
T c1_2 = c1 * c1;
|
||||
T c1_3 = c1_2 * c1;
|
||||
T c1_4 = c1_2 * c1_2;
|
||||
T a_2 = a * a;
|
||||
T a_3 = a_2 * a;
|
||||
|
||||
T c2 = (a - 1) * (1 + c1);
|
||||
T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2);
|
||||
T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6);
|
||||
T c5 = (a - 1) * (-(c1_4 / 4)
|
||||
+ (11 * a - 17) * c1_3 / 6
|
||||
+ (-3 * a_2 + 13 * a -13) * c1_2
|
||||
+ (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2
|
||||
+ (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12);
|
||||
|
||||
T y_2 = y * y;
|
||||
T y_3 = y_2 * y;
|
||||
T y_4 = y_2 * y_2;
|
||||
result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// DiDonato and Morris Eq 31:
|
||||
T s = find_inverse_s(p, q);
|
||||
|
||||
T s_2 = s * s;
|
||||
T s_3 = s_2 * s;
|
||||
T s_4 = s_2 * s_2;
|
||||
T s_5 = s_4 * s;
|
||||
T ra = sqrt(a);
|
||||
|
||||
T w = a + s * ra + (s * s -1) / 3;
|
||||
w += (s_3 - 7 * s) / (36 * ra);
|
||||
w -= (3 * s_4 + 7 * s_2 - 16) / (810 * a);
|
||||
w += (9 * s_5 + 256 * s_3 - 433 * s) / (38880 * a * ra);
|
||||
|
||||
if((a >= 500) && (fabs(1 - w / a) < 1e-6))
|
||||
{
|
||||
result = w;
|
||||
}
|
||||
else if (p > 0.5)
|
||||
{
|
||||
if(w < 3 * a)
|
||||
{
|
||||
result = w;
|
||||
}
|
||||
else
|
||||
{
|
||||
T D = (std::max)(T(2), a * (a - 1));
|
||||
T lg = boost::math::lgamma(a, pol);
|
||||
T lb = log(q) + lg;
|
||||
if(lb < -D * 2.3)
|
||||
{
|
||||
// DiDonato and Morris Eq 25:
|
||||
T y = -lb;
|
||||
T c1 = (a - 1) * log(y);
|
||||
T c1_2 = c1 * c1;
|
||||
T c1_3 = c1_2 * c1;
|
||||
T c1_4 = c1_2 * c1_2;
|
||||
T a_2 = a * a;
|
||||
T a_3 = a_2 * a;
|
||||
|
||||
T c2 = (a - 1) * (1 + c1);
|
||||
T c3 = (a - 1) * (-(c1_2 / 2) + (a - 2) * c1 + (3 * a - 5) / 2);
|
||||
T c4 = (a - 1) * ((c1_3 / 3) - (3 * a - 5) * c1_2 / 2 + (a_2 - 6 * a + 7) * c1 + (11 * a_2 - 46 * a + 47) / 6);
|
||||
T c5 = (a - 1) * (-(c1_4 / 4)
|
||||
+ (11 * a - 17) * c1_3 / 6
|
||||
+ (-3 * a_2 + 13 * a -13) * c1_2
|
||||
+ (2 * a_3 - 25 * a_2 + 72 * a - 61) * c1 / 2
|
||||
+ (25 * a_3 - 195 * a_2 + 477 * a - 379) / 12);
|
||||
|
||||
T y_2 = y * y;
|
||||
T y_3 = y_2 * y;
|
||||
T y_4 = y_2 * y_2;
|
||||
result = y + c1 + (c2 / y) + (c3 / y_2) + (c4 / y_3) + (c5 / y_4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// DiDonato and Morris Eq 33:
|
||||
T u = -lb + (a - 1) * log(w) - log(1 + (1 - a) / (1 + w));
|
||||
result = -lb + (a - 1) * log(u) - log(1 + (1 - a) / (1 + u));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// DiDonato and Morris Eq 35:
|
||||
T z = didonato_FN(p, a, w, 0, T(0), pol);
|
||||
z = didonato_FN(p, a, z, 2, T(0), pol);
|
||||
z = didonato_FN(p, a, z, 2, T(0), pol);
|
||||
z = didonato_FN(p, a, z, 3, T(0), pol);
|
||||
|
||||
if((z <= 0.01 * (a + 1)) || (z > 0.7 * (a + 1)))
|
||||
{
|
||||
result = z;
|
||||
}
|
||||
else
|
||||
{
|
||||
// DiDonato and Morris Eq 36:
|
||||
T zb = didonato_FN(p, a, z, 100, T(1e-4), pol);
|
||||
T u = log(p) + boost::math::lgamma(a + 1, pol);
|
||||
result = zb * (1 - (a * log(zb) - zb - u + log(didonato_SN(a, z, 100, T(1e-4)))) / (a - zb));
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
struct gamma_p_inverse_func
|
||||
{
|
||||
gamma_p_inverse_func(T a_, T p_, bool inv) : a(a_), p(p_), invert(inv)
|
||||
{
|
||||
//
|
||||
// If p is too near 1 then P(x) - p suffers from cancellation
|
||||
// errors causing our root-finding algorithms to "thrash", better
|
||||
// to invert in this case and calculate Q(x) - (1-p) instead.
|
||||
//
|
||||
// Of course if p is *very* close to 1, then the answer we get will
|
||||
// be inaccurate anyway (because there's not enough information in p)
|
||||
// but at least we will converge on the (inaccurate) answer quickly.
|
||||
//
|
||||
if(p > 0.9)
|
||||
{
|
||||
p = 1 - p;
|
||||
invert = !invert;
|
||||
}
|
||||
}
|
||||
|
||||
std::tr1::tuple<T, T, T> operator()(const T& x)const
|
||||
{
|
||||
BOOST_FPU_EXCEPTION_GUARD
|
||||
//
|
||||
// Calculate P(x) - p and the first two derivates, or if the invert
|
||||
// flag is set, then Q(x) - q and it's derivatives.
|
||||
//
|
||||
typedef typename policies::evaluation<T, Policy>::type value_type;
|
||||
typedef typename lanczos::lanczos<T, Policy>::type evaluation_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
BOOST_MATH_STD_USING // For ADL of std functions.
|
||||
|
||||
T f, f1;
|
||||
value_type ft;
|
||||
f = static_cast<T>(boost::math::detail::gamma_incomplete_imp(
|
||||
static_cast<value_type>(a),
|
||||
static_cast<value_type>(x),
|
||||
true, invert,
|
||||
forwarding_policy(), &ft));
|
||||
f1 = static_cast<T>(ft);
|
||||
T f2;
|
||||
T div = (a - x - 1) / x;
|
||||
f2 = f1;
|
||||
if((fabs(div) > 1) && (tools::max_value<T>() / fabs(div) < f2))
|
||||
{
|
||||
// overflow:
|
||||
f2 = -tools::max_value<T>() / 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
f2 *= div;
|
||||
}
|
||||
|
||||
if(invert)
|
||||
{
|
||||
f1 = -f1;
|
||||
f2 = -f2;
|
||||
}
|
||||
|
||||
return std::tr1::make_tuple(f - p, f1, f2);
|
||||
}
|
||||
private:
|
||||
T a, p;
|
||||
bool invert;
|
||||
};
|
||||
|
||||
template <class T, class Policy>
|
||||
T gamma_p_inv_imp(T a, T p, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions.
|
||||
|
||||
static const char* function = "boost::math::gamma_p_inv<%1%>(%1%, %1%)";
|
||||
|
||||
if(a <= 0)
|
||||
policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
|
||||
if((p < 0) || (p > 1))
|
||||
policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got p=%1%).", p, pol);
|
||||
if(p == 1)
|
||||
return tools::max_value<T>();
|
||||
if(p == 0)
|
||||
return 0;
|
||||
T guess = detail::find_inverse_gamma(a, p, 1 - p, pol);
|
||||
T lower = tools::min_value<T>();
|
||||
if(guess <= lower)
|
||||
guess = tools::min_value<T>();
|
||||
//
|
||||
// Work out how many digits to converge to, normally this is
|
||||
// 2/3 of the digits in T, but if the first derivative is very
|
||||
// large convergence is slow, so we'll bump it up to full
|
||||
// precision to prevent premature termination of the root-finding routine.
|
||||
//
|
||||
unsigned digits = (policies::digits<T, Policy>() * 2) / 3;
|
||||
if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
|
||||
digits = policies::digits<T, Policy>() - 2;
|
||||
//
|
||||
// Go ahead and iterate:
|
||||
//
|
||||
guess = tools::halley_iterate(
|
||||
detail::gamma_p_inverse_func<T, Policy>(a, p, false),
|
||||
guess,
|
||||
lower,
|
||||
tools::max_value<T>(),
|
||||
digits);
|
||||
if(guess == lower)
|
||||
guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
|
||||
return guess;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T gamma_q_inv_imp(T a, T q, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions.
|
||||
|
||||
static const char* function = "boost::math::gamma_q_inv<%1%>(%1%, %1%)";
|
||||
|
||||
if(a <= 0)
|
||||
policies::raise_domain_error<T>(function, "Argument a in the incomplete gamma function inverse must be >= 0 (got a=%1%).", a, pol);
|
||||
if((q < 0) || (q > 1))
|
||||
policies::raise_domain_error<T>(function, "Probabilty must be in the range [0,1] in the incomplete gamma function inverse (got q=%1%).", q, pol);
|
||||
if(q == 0)
|
||||
return tools::max_value<T>();
|
||||
if(q == 1)
|
||||
return 0;
|
||||
T guess = detail::find_inverse_gamma(a, 1 - q, q, pol);
|
||||
T lower = tools::min_value<T>();
|
||||
if(guess <= lower)
|
||||
guess = tools::min_value<T>();
|
||||
//
|
||||
// Work out how many digits to converge to, normally this is
|
||||
// 2/3 of the digits in T, but if the first derivative is very
|
||||
// large convergence is slow, so we'll bump it up to full
|
||||
// precision to prevent premature termination of the root-finding routine.
|
||||
//
|
||||
unsigned digits = (policies::digits<T, Policy>() * 2) / 3;
|
||||
if((a < 0.125) && (fabs(gamma_p_derivative(a, guess, pol)) > 1 / sqrt(tools::epsilon<T>())))
|
||||
digits = policies::digits<T, Policy>();
|
||||
//
|
||||
// Go ahead and iterate:
|
||||
//
|
||||
guess = tools::halley_iterate(
|
||||
detail::gamma_p_inverse_func<T, Policy>(a, q, true),
|
||||
guess,
|
||||
lower,
|
||||
tools::max_value<T>(),
|
||||
digits);
|
||||
if(guess == lower)
|
||||
guess = policies::raise_underflow_error<T>(function, "Expected result known to be non-zero, but is smaller than the smallest available number.", pol);
|
||||
return guess;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
gamma_p_inv(T1 a, T2 p, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
return detail::gamma_p_inv_imp(
|
||||
static_cast<result_type>(a),
|
||||
static_cast<result_type>(p), pol);
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
gamma_q_inv(T1 a, T2 p, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
return detail::gamma_q_inv_imp(
|
||||
static_cast<result_type>(a),
|
||||
static_cast<result_type>(p), pol);
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
gamma_p_inv(T1 a, T2 p)
|
||||
{
|
||||
return gamma_p_inv(a, p, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
gamma_q_inv(T1 a, T2 p)
|
||||
{
|
||||
return gamma_q_inv(a, p, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_IGAMMA_INVERSE_HPP
|
||||
|
||||
|
||||
764
include/boost/math/special_functions/detail/igamma_large.hpp
Normal file
764
include/boost/math/special_functions/detail/igamma_large.hpp
Normal file
@@ -0,0 +1,764 @@
|
||||
// Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// This file implements the asymptotic expansions of the incomplete
|
||||
// gamma functions P(a, x) and Q(a, x), used when a is large and
|
||||
// x ~ a.
|
||||
//
|
||||
// The primary reference is:
|
||||
//
|
||||
// "The Asymptotic Expansion of the Incomplete Gamma Functions"
|
||||
// N. M. Temme.
|
||||
// Siam J. Math Anal. Vol 10 No 4, July 1979, p757.
|
||||
//
|
||||
// A different way of evaluating these expansions,
|
||||
// plus a lot of very useful background information is in:
|
||||
//
|
||||
// "A Set of Algorithms For the Incomplete Gamma Functions."
|
||||
// N. M. Temme.
|
||||
// Probability in the Engineering and Informational Sciences,
|
||||
// 8, 1994, 291.
|
||||
//
|
||||
// An alternative implementation is in:
|
||||
//
|
||||
// "Computation of the Incomplete Gamma Function Ratios and their Inverse."
|
||||
// A. R. Didonato and A. H. Morris.
|
||||
// ACM TOMS, Vol 12, No 4, Dec 1986, p377.
|
||||
//
|
||||
// There are various versions of the same code below, each accurate
|
||||
// to a different precision. To understand the code, refer to Didonato
|
||||
// and Morris, from Eq 17 and 18 onwards.
|
||||
//
|
||||
// The coefficients used here are not taken from Didonato and Morris:
|
||||
// the domain over which these expansions are used is slightly different
|
||||
// to theirs, and their constants are not quite accurate enough for
|
||||
// 128-bit long double's. Instead the coefficients were calculated
|
||||
// using the methods described by Temme p762 from Eq 3.8 onwards.
|
||||
// The values obtained agree with those obtained by Didonato and Morris
|
||||
// (at least to the first 30 digits that they provide).
|
||||
// At double precision the degrees of polynomial required for full
|
||||
// machine precision are close to those recomended to Didonato and Morris,
|
||||
// but of course many more terms are needed for larger types.
|
||||
//
|
||||
#ifndef BOOST_MATH_DETAIL_IGAMMA_LARGE
|
||||
#define BOOST_MATH_DETAIL_IGAMMA_LARGE
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
// This version will never be called (at runtime), it's a stub used
|
||||
// when T is unsuitable to be passed to these routines:
|
||||
//
|
||||
template <class T, class Policy>
|
||||
inline T igamma_temme_large(T, T, const Policy& /* pol */, mpl::int_<0> const *)
|
||||
{
|
||||
// stub function, should never actually be called
|
||||
BOOST_ASSERT(0);
|
||||
return 0;
|
||||
}
|
||||
//
|
||||
// This version is accurate for up to 64-bit mantissa's,
|
||||
// (80-bit long double, or 10^-20).
|
||||
//
|
||||
template <class T, class Policy>
|
||||
T igamma_temme_large(T a, T x, const Policy& pol, mpl::int_<64> const *)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions
|
||||
T sigma = (x - a) / a;
|
||||
T phi = -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
|
||||
507
include/boost/math/special_functions/detail/lgamma_small.hpp
Normal file
507
include/boost/math/special_functions/detail/lgamma_small.hpp
Normal file
@@ -0,0 +1,507 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
|
||||
#define BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
//
|
||||
// lgamma for small arguments:
|
||||
//
|
||||
template <class T, class Policy, class L>
|
||||
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<64>&, const Policy& /* l */, const L&)
|
||||
{
|
||||
// This version uses rational approximations for small
|
||||
// values of z accurate enough for 64-bit mantissas
|
||||
// (80-bit long doubles), works well for 53-bit doubles as well.
|
||||
// L is only used to select the Lanczos function.
|
||||
|
||||
BOOST_MATH_STD_USING // for ADL of std names
|
||||
T result = 0;
|
||||
if(z < tools::epsilon<T>())
|
||||
{
|
||||
result = -log(z);
|
||||
}
|
||||
else if((zm1 == 0) || (zm2 == 0))
|
||||
{
|
||||
// nothing to do, result is zero....
|
||||
}
|
||||
else if(z > 2)
|
||||
{
|
||||
//
|
||||
// Begin by performing argument reduction until
|
||||
// z is in [2,3):
|
||||
//
|
||||
if(z >= 3)
|
||||
{
|
||||
do
|
||||
{
|
||||
z -= 1;
|
||||
zm2 -= 1;
|
||||
result += log(z);
|
||||
}while(z >= 3);
|
||||
// Update zm2, we need it below:
|
||||
zm2 = z - 2;
|
||||
}
|
||||
|
||||
//
|
||||
// Use the following form:
|
||||
//
|
||||
// lgamma(z) = (z-2)(z+1)(Y + R(z-2))
|
||||
//
|
||||
// where R(z-2) is a rational approximation optimised for
|
||||
// low absolute error - as long as it's absolute error
|
||||
// is small compared to the constant Y - then any rounding
|
||||
// error in it's computation will get wiped out.
|
||||
//
|
||||
// R(z-2) has the following properties:
|
||||
//
|
||||
// At double: Max error found: 4.231e-18
|
||||
// At long double: Max error found: 1.987e-21
|
||||
// Maximum Deviation Found (approximation error): 5.900e-24
|
||||
//
|
||||
static const T P[] = {
|
||||
static_cast<T>(-0.180355685678449379109e-1L),
|
||||
static_cast<T>(0.25126649619989678683e-1L),
|
||||
static_cast<T>(0.494103151567532234274e-1L),
|
||||
static_cast<T>(0.172491608709613993966e-1L),
|
||||
static_cast<T>(-0.259453563205438108893e-3L),
|
||||
static_cast<T>(-0.541009869215204396339e-3L),
|
||||
static_cast<T>(-0.324588649825948492091e-4L)
|
||||
};
|
||||
static const T Q[] = {
|
||||
static_cast<T>(0.1e1),
|
||||
static_cast<T>(0.196202987197795200688e1L),
|
||||
static_cast<T>(0.148019669424231326694e1L),
|
||||
static_cast<T>(0.541391432071720958364e0L),
|
||||
static_cast<T>(0.988504251128010129477e-1L),
|
||||
static_cast<T>(0.82130967464889339326e-2L),
|
||||
static_cast<T>(0.224936291922115757597e-3L),
|
||||
static_cast<T>(-0.223352763208617092964e-6L)
|
||||
};
|
||||
|
||||
static const float Y = 0.158963680267333984375e0f;
|
||||
|
||||
T r = zm2 * (z + 1);
|
||||
T R = tools::evaluate_polynomial(P, zm2);
|
||||
R /= tools::evaluate_polynomial(Q, zm2);
|
||||
|
||||
result += r * Y + r * R;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If z is less than 1 use recurrance to shift to
|
||||
// z in the interval [1,2]:
|
||||
//
|
||||
if(z < 1)
|
||||
{
|
||||
result += -log(z);
|
||||
zm2 = zm1;
|
||||
zm1 = z;
|
||||
z += 1;
|
||||
}
|
||||
//
|
||||
// Two approximations, on for z in [1,1.5] and
|
||||
// one for z in [1.5,2]:
|
||||
//
|
||||
if(z <= 1.5)
|
||||
{
|
||||
//
|
||||
// Use the following form:
|
||||
//
|
||||
// lgamma(z) = (z-1)(z-2)(Y + R(z-1))
|
||||
//
|
||||
// where R(z-1) is a rational approximation optimised for
|
||||
// low absolute error - as long as it's absolute error
|
||||
// is small compared to the constant Y - then any rounding
|
||||
// error in it's computation will get wiped out.
|
||||
//
|
||||
// R(z-1) has the following properties:
|
||||
//
|
||||
// At double precision: Max error found: 1.230011e-17
|
||||
// At 80-bit long double precision: Max error found: 5.631355e-21
|
||||
// Maximum Deviation Found: 3.139e-021
|
||||
// Expected Error Term: 3.139e-021
|
||||
|
||||
//
|
||||
static const float Y = 0.52815341949462890625f;
|
||||
|
||||
static const T P[] = {
|
||||
static_cast<T>(0.490622454069039543534e-1L),
|
||||
static_cast<T>(-0.969117530159521214579e-1L),
|
||||
static_cast<T>(-0.414983358359495381969e0L),
|
||||
static_cast<T>(-0.406567124211938417342e0L),
|
||||
static_cast<T>(-0.158413586390692192217e0L),
|
||||
static_cast<T>(-0.240149820648571559892e-1L),
|
||||
static_cast<T>(-0.100346687696279557415e-2L)
|
||||
};
|
||||
static const T Q[] = {
|
||||
static_cast<T>(0.1e1L),
|
||||
static_cast<T>(0.302349829846463038743e1L),
|
||||
static_cast<T>(0.348739585360723852576e1L),
|
||||
static_cast<T>(0.191415588274426679201e1L),
|
||||
static_cast<T>(0.507137738614363510846e0L),
|
||||
static_cast<T>(0.577039722690451849648e-1L),
|
||||
static_cast<T>(0.195768102601107189171e-2L)
|
||||
};
|
||||
|
||||
T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1);
|
||||
T prefix = zm1 * zm2;
|
||||
|
||||
result += prefix * Y + prefix * r;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Use the following form:
|
||||
//
|
||||
// lgamma(z) = (2-z)(1-z)(Y + R(2-z))
|
||||
//
|
||||
// where R(2-z) is a rational approximation optimised for
|
||||
// low absolute error - as long as it's absolute error
|
||||
// is small compared to the constant Y - then any rounding
|
||||
// error in it's computation will get wiped out.
|
||||
//
|
||||
// R(2-z) has the following properties:
|
||||
//
|
||||
// At double precision, max error found: 1.797565e-17
|
||||
// At 80-bit long double precision, max error found: 9.306419e-21
|
||||
// Maximum Deviation Found: 2.151e-021
|
||||
// Expected Error Term: 2.150e-021
|
||||
//
|
||||
static const float Y = 0.452017307281494140625f;
|
||||
|
||||
static const T P[] = {
|
||||
static_cast<T>(-0.292329721830270012337e-1L),
|
||||
static_cast<T>(0.144216267757192309184e0L),
|
||||
static_cast<T>(-0.142440390738631274135e0L),
|
||||
static_cast<T>(0.542809694055053558157e-1L),
|
||||
static_cast<T>(-0.850535976868336437746e-2L),
|
||||
static_cast<T>(0.431171342679297331241e-3L)
|
||||
};
|
||||
static const T Q[] = {
|
||||
static_cast<T>(0.1e1),
|
||||
static_cast<T>(-0.150169356054485044494e1L),
|
||||
static_cast<T>(0.846973248876495016101e0L),
|
||||
static_cast<T>(-0.220095151814995745555e0L),
|
||||
static_cast<T>(0.25582797155975869989e-1L),
|
||||
static_cast<T>(-0.100666795539143372762e-2L),
|
||||
static_cast<T>(-0.827193521891290553639e-6L)
|
||||
};
|
||||
T r = zm2 * zm1;
|
||||
T R = tools::evaluate_polynomial(P, -zm2) / tools::evaluate_polynomial(Q, -zm2);
|
||||
|
||||
result += r * Y + r * R;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
template <class T, class Policy, class L>
|
||||
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<113>&, const Policy& /* l */, const L&)
|
||||
{
|
||||
//
|
||||
// This version uses rational approximations for small
|
||||
// values of z accurate enough for 113-bit mantissas
|
||||
// (128-bit long doubles).
|
||||
//
|
||||
BOOST_MATH_STD_USING // for ADL of std names
|
||||
T result = 0;
|
||||
if(z < tools::epsilon<T>())
|
||||
{
|
||||
result = -log(z);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
}
|
||||
else if((zm1 == 0) || (zm2 == 0))
|
||||
{
|
||||
// nothing to do, result is zero....
|
||||
}
|
||||
else if(z > 2)
|
||||
{
|
||||
//
|
||||
// Begin by performing argument reduction until
|
||||
// z is in [2,3):
|
||||
//
|
||||
if(z >= 3)
|
||||
{
|
||||
do
|
||||
{
|
||||
z -= 1;
|
||||
result += log(z);
|
||||
}while(z >= 3);
|
||||
zm2 = z - 2;
|
||||
}
|
||||
BOOST_MATH_INSTRUMENT_CODE(zm2);
|
||||
BOOST_MATH_INSTRUMENT_CODE(z);
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
|
||||
//
|
||||
// Use the following form:
|
||||
//
|
||||
// lgamma(z) = (z-2)(z+1)(Y + R(z-2))
|
||||
//
|
||||
// where R(z-2) is a rational approximation optimised for
|
||||
// low absolute error - as long as it's absolute error
|
||||
// is small compared to the constant Y - then any rounding
|
||||
// error in it's computation will get wiped out.
|
||||
//
|
||||
// Maximum Deviation Found (approximation error) 3.73e-37
|
||||
|
||||
static const T P[] = {
|
||||
-0.018035568567844937910504030027467476655L,
|
||||
0.013841458273109517271750705401202404195L,
|
||||
0.062031842739486600078866923383017722399L,
|
||||
0.052518418329052161202007865149435256093L,
|
||||
0.01881718142472784129191838493267755758L,
|
||||
0.0025104830367021839316463675028524702846L,
|
||||
-0.00021043176101831873281848891452678568311L,
|
||||
-0.00010249622350908722793327719494037981166L,
|
||||
-0.11381479670982006841716879074288176994e-4L,
|
||||
-0.49999811718089980992888533630523892389e-6L,
|
||||
-0.70529798686542184668416911331718963364e-8L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1L,
|
||||
2.5877485070422317542808137697939233685L,
|
||||
2.8797959228352591788629602533153837126L,
|
||||
1.8030885955284082026405495275461180977L,
|
||||
0.69774331297747390169238306148355428436L,
|
||||
0.17261566063277623942044077039756583802L,
|
||||
0.02729301254544230229429621192443000121L,
|
||||
0.0026776425891195270663133581960016620433L,
|
||||
0.00015244249160486584591370355730402168106L,
|
||||
0.43997034032479866020546814475414346627e-5L,
|
||||
0.46295080708455613044541885534408170934e-7L,
|
||||
-0.93326638207459533682980757982834180952e-11L,
|
||||
0.42316456553164995177177407325292867513e-13L
|
||||
};
|
||||
|
||||
T R = tools::evaluate_polynomial(P, zm2);
|
||||
R /= tools::evaluate_polynomial(Q, zm2);
|
||||
|
||||
static const float Y = 0.158963680267333984375F;
|
||||
|
||||
T r = zm2 * (z + 1);
|
||||
|
||||
result += r * Y + r * R;
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If z is less than 1 use recurrance to shift to
|
||||
// z in the interval [1,2]:
|
||||
//
|
||||
if(z < 1)
|
||||
{
|
||||
result += -log(z);
|
||||
zm2 = zm1;
|
||||
zm1 = z;
|
||||
z += 1;
|
||||
}
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
BOOST_MATH_INSTRUMENT_CODE(z);
|
||||
BOOST_MATH_INSTRUMENT_CODE(zm2);
|
||||
//
|
||||
// Three approximations, on for z in [1,1.35], [1.35,1.625] and [1.625,1]
|
||||
//
|
||||
if(z <= 1.35)
|
||||
{
|
||||
//
|
||||
// Use the following form:
|
||||
//
|
||||
// lgamma(z) = (z-1)(z-2)(Y + R(z-1))
|
||||
//
|
||||
// where R(z-1) is a rational approximation optimised for
|
||||
// low absolute error - as long as it's absolute error
|
||||
// is small compared to the constant Y - then any rounding
|
||||
// error in it's computation will get wiped out.
|
||||
//
|
||||
// R(z-1) has the following properties:
|
||||
//
|
||||
// Maximum Deviation Found (approximation error) 1.659e-36
|
||||
// Expected Error Term (theoretical error) 1.343e-36
|
||||
// Max error found at 128-bit long double precision 1.007e-35
|
||||
//
|
||||
static const float Y = 0.54076099395751953125f;
|
||||
|
||||
static const T P[] = {
|
||||
0.036454670944013329356512090082402429697L,
|
||||
-0.066235835556476033710068679907798799959L,
|
||||
-0.67492399795577182387312206593595565371L,
|
||||
-1.4345555263962411429855341651960000166L,
|
||||
-1.4894319559821365820516771951249649563L,
|
||||
-0.87210277668067964629483299712322411566L,
|
||||
-0.29602090537771744401524080430529369136L,
|
||||
-0.0561832587517836908929331992218879676L,
|
||||
-0.0053236785487328044334381502530383140443L,
|
||||
-0.00018629360291358130461736386077971890789L,
|
||||
-0.10164985672213178500790406939467614498e-6L,
|
||||
0.13680157145361387405588201461036338274e-8L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1,
|
||||
4.9106336261005990534095838574132225599L,
|
||||
10.258804800866438510889341082793078432L,
|
||||
11.88588976846826108836629960537466889L,
|
||||
8.3455000546999704314454891036700998428L,
|
||||
3.6428823682421746343233362007194282703L,
|
||||
0.97465989807254572142266753052776132252L,
|
||||
0.15121052897097822172763084966793352524L,
|
||||
0.012017363555383555123769849654484594893L,
|
||||
0.0003583032812720649835431669893011257277L
|
||||
};
|
||||
|
||||
T r = tools::evaluate_polynomial(P, zm1) / tools::evaluate_polynomial(Q, zm1);
|
||||
T prefix = zm1 * zm2;
|
||||
|
||||
result += prefix * Y + prefix * r;
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
}
|
||||
else if(z <= 1.625)
|
||||
{
|
||||
//
|
||||
// Use the following form:
|
||||
//
|
||||
// lgamma(z) = (2-z)(1-z)(Y + R(2-z))
|
||||
//
|
||||
// where R(2-z) is a rational approximation optimised for
|
||||
// low absolute error - as long as it's absolute error
|
||||
// is small compared to the constant Y - then any rounding
|
||||
// error in it's computation will get wiped out.
|
||||
//
|
||||
// R(2-z) has the following properties:
|
||||
//
|
||||
// Max error found at 128-bit long double precision 9.634e-36
|
||||
// Maximum Deviation Found (approximation error) 1.538e-37
|
||||
// Expected Error Term (theoretical error) 2.350e-38
|
||||
//
|
||||
static const float Y = 0.483787059783935546875f;
|
||||
|
||||
static const T P[] = {
|
||||
-0.017977422421608624353488126610933005432L,
|
||||
0.18484528905298309555089509029244135703L,
|
||||
-0.40401251514859546989565001431430884082L,
|
||||
0.40277179799147356461954182877921388182L,
|
||||
-0.21993421441282936476709677700477598816L,
|
||||
0.069595742223850248095697771331107571011L,
|
||||
-0.012681481427699686635516772923547347328L,
|
||||
0.0012489322866834830413292771335113136034L,
|
||||
-0.57058739515423112045108068834668269608e-4L,
|
||||
0.8207548771933585614380644961342925976e-6L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1,
|
||||
-2.9629552288944259229543137757200262073L,
|
||||
3.7118380799042118987185957298964772755L,
|
||||
-2.5569815272165399297600586376727357187L,
|
||||
1.0546764918220835097855665680632153367L,
|
||||
-0.26574021300894401276478730940980810831L,
|
||||
0.03996289731752081380552901986471233462L,
|
||||
-0.0033398680924544836817826046380586480873L,
|
||||
0.00013288854760548251757651556792598235735L,
|
||||
-0.17194794958274081373243161848194745111e-5L
|
||||
};
|
||||
T r = zm2 * zm1;
|
||||
T R = tools::evaluate_polynomial(P, 0.625 - zm1) / tools::evaluate_polynomial(Q, 0.625 - zm1);
|
||||
|
||||
result += r * Y + r * R;
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Same form as above.
|
||||
//
|
||||
// Max error found (at 128-bit long double precision) 1.831e-35
|
||||
// Maximum Deviation Found (approximation error) 8.588e-36
|
||||
// Expected Error Term (theoretical error) 1.458e-36
|
||||
//
|
||||
static const float Y = 0.443811893463134765625f;
|
||||
|
||||
static const T P[] = {
|
||||
-0.021027558364667626231512090082402429494L,
|
||||
0.15128811104498736604523586803722368377L,
|
||||
-0.26249631480066246699388544451126410278L,
|
||||
0.21148748610533489823742352180628489742L,
|
||||
-0.093964130697489071999873506148104370633L,
|
||||
0.024292059227009051652542804957550866827L,
|
||||
-0.0036284453226534839926304745756906117066L,
|
||||
0.0002939230129315195346843036254392485984L,
|
||||
-0.11088589183158123733132268042570710338e-4L,
|
||||
0.13240510580220763969511741896361984162e-6L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1,
|
||||
-2.4240003754444040525462170802796471996L,
|
||||
2.4868383476933178722203278602342786002L,
|
||||
-1.4047068395206343375520721509193698547L,
|
||||
0.47583809087867443858344765659065773369L,
|
||||
-0.09865724264554556400463655444270700132L,
|
||||
0.012238223514176587501074150988445109735L,
|
||||
-0.00084625068418239194670614419707491797097L,
|
||||
0.2796574430456237061420839429225710602e-4L,
|
||||
-0.30202973883316730694433702165188835331e-6L
|
||||
};
|
||||
// (2 - x) * (1 - x) * (c + R(2 - x))
|
||||
T r = zm2 * zm1;
|
||||
T R = tools::evaluate_polynomial(P, -zm2) / tools::evaluate_polynomial(Q, -zm2);
|
||||
|
||||
result += r * Y + r * R;
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
}
|
||||
}
|
||||
BOOST_MATH_INSTRUMENT_CODE(result);
|
||||
return result;
|
||||
}
|
||||
template <class T, class Policy, class L>
|
||||
T lgamma_small_imp(T z, T zm1, T zm2, const mpl::int_<0>&, const Policy& pol, const L&)
|
||||
{
|
||||
//
|
||||
// No rational approximations are available because either
|
||||
// T has no numeric_limits support (so we can't tell how
|
||||
// many digits it has), or T has more digits than we know
|
||||
// what to do with.... we do have a Lanczos approximation
|
||||
// though, and that can be used to keep errors under control.
|
||||
//
|
||||
BOOST_MATH_STD_USING // for ADL of std names
|
||||
T result = 0;
|
||||
if(z < tools::epsilon<T>())
|
||||
{
|
||||
result = -log(z);
|
||||
}
|
||||
else if(z < 0.5)
|
||||
{
|
||||
// taking the log of tgamma reduces the error, no danger of overflow here:
|
||||
result = log(gamma_imp(z, pol, L()));
|
||||
}
|
||||
else if(z >= 3)
|
||||
{
|
||||
// taking the log of tgamma reduces the error, no danger of overflow here:
|
||||
result = log(gamma_imp(z, pol, L()));
|
||||
}
|
||||
else if(z >= 1.5)
|
||||
{
|
||||
// special case near 2:
|
||||
T dz = zm2;
|
||||
result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e<T>());
|
||||
result += boost::math::log1p(dz / (L::g() + T(1.5)), pol) * T(1.5);
|
||||
result += boost::math::log1p(L::lanczos_sum_near_2(dz), pol);
|
||||
}
|
||||
else
|
||||
{
|
||||
// special case near 1:
|
||||
T dz = zm1;
|
||||
result = dz * log((z + L::g() - T(0.5)) / boost::math::constants::e<T>());
|
||||
result += boost::math::log1p(dz / (L::g() + T(0.5)), pol) / 2;
|
||||
result += boost::math::log1p(L::lanczos_sum_near_1(dz), pol);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_FUNCTIONS_DETAIL_LGAMMA_SMALL
|
||||
@@ -1,52 +0,0 @@
|
||||
// (C) Copyright John Maddock 2005.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SERIES_INCLUDED
|
||||
#define BOOST_MATH_SERIES_INCLUDED
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std{ using ::pow; using ::fabs; }
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
//
|
||||
// Algorithm kahan_sum_series invokes Functor func until the N'th
|
||||
// term is too small to have any effect on the total, the terms
|
||||
// are added using the Kahan summation method.
|
||||
//
|
||||
// CAUTION: Optimizing compilers combined with extended-precision
|
||||
// machine registers conspire to render this algorithm partly broken:
|
||||
// double rounding of intermediate terms (first to a long double machine
|
||||
// register, and then to a double result) cause the rounding error computed
|
||||
// by the algorithm to be off by up to 1ulp. However this occurs rarely, and
|
||||
// in any case the result is still much better than a naive summation.
|
||||
//
|
||||
template <class Functor>
|
||||
typename Functor::result_type kahan_sum_series(Functor& func, int bits)
|
||||
{
|
||||
typedef typename Functor::result_type result_type;
|
||||
result_type factor = std::pow(result_type(2), bits);
|
||||
result_type result = func();
|
||||
result_type next_term, y, t;
|
||||
result_type carry = 0;
|
||||
do{
|
||||
next_term = func();
|
||||
y = next_term - carry;
|
||||
t = result + y;
|
||||
carry = t - result;
|
||||
carry -= y;
|
||||
result = t;
|
||||
}
|
||||
while(std::fabs(result) < std::fabs(factor * next_term));
|
||||
return result;
|
||||
}
|
||||
|
||||
} } } // namespaces
|
||||
|
||||
#endif // BOOST_MATH_SERIES_INCLUDED
|
||||
167
include/boost/math/special_functions/detail/simple_complex.hpp
Normal file
167
include/boost/math/special_functions/detail/simple_complex.hpp
Normal file
@@ -0,0 +1,167 @@
|
||||
// Copyright (c) 2007 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SF_DETAIL_SIMPLE_COMPLEX_HPP
|
||||
#define BOOST_MATH_SF_DETAIL_SIMPLE_COMPLEX_HPP
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{ namespace sc{
|
||||
|
||||
template <class T>
|
||||
class simple_complex
|
||||
{
|
||||
public:
|
||||
simple_complex() : r(0), i(0) {}
|
||||
simple_complex(T a) : r(a) {}
|
||||
template <class U>
|
||||
simple_complex(U a) : r(a) {}
|
||||
simple_complex(T a, T b) : r(a), i(b) {}
|
||||
|
||||
simple_complex& operator += (const simple_complex& o)
|
||||
{
|
||||
r += o.r;
|
||||
i += o.i;
|
||||
return *this;
|
||||
}
|
||||
simple_complex& operator -= (const simple_complex& o)
|
||||
{
|
||||
r -= o.r;
|
||||
i -= o.i;
|
||||
return *this;
|
||||
}
|
||||
simple_complex& operator *= (const simple_complex& o)
|
||||
{
|
||||
T lr = r * o.r - i * o.i;
|
||||
T li = i * o.r + r * o.i;
|
||||
r = lr;
|
||||
i = li;
|
||||
return *this;
|
||||
}
|
||||
simple_complex& operator /= (const simple_complex& o)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
T lr;
|
||||
T li;
|
||||
if(fabs(o.r) > fabs(o.i))
|
||||
{
|
||||
T rat = o.i / o.r;
|
||||
lr = r + i * rat;
|
||||
li = i - r * rat;
|
||||
rat = o.r + o.i * rat;
|
||||
lr /= rat;
|
||||
li /= rat;
|
||||
}
|
||||
else
|
||||
{
|
||||
T rat = o.r / o.i;
|
||||
lr = i + r * rat;
|
||||
li = i * rat - r;
|
||||
rat = o.r * rat + o.i;
|
||||
lr /= rat;
|
||||
li /= rat;
|
||||
}
|
||||
r = lr;
|
||||
i = li;
|
||||
return *this;
|
||||
}
|
||||
bool operator == (const simple_complex& o)
|
||||
{
|
||||
return (r == o.r) && (i == o.i);
|
||||
}
|
||||
bool operator != (const simple_complex& o)
|
||||
{
|
||||
return !((r == o.r) && (i == o.i));
|
||||
}
|
||||
bool operator == (const T& o)
|
||||
{
|
||||
return (r == o) && (i == 0);
|
||||
}
|
||||
simple_complex& operator += (const T& o)
|
||||
{
|
||||
r += o;
|
||||
return *this;
|
||||
}
|
||||
simple_complex& operator -= (const T& o)
|
||||
{
|
||||
r -= o;
|
||||
return *this;
|
||||
}
|
||||
simple_complex& operator *= (const T& o)
|
||||
{
|
||||
r *= o;
|
||||
i *= o;
|
||||
return *this;
|
||||
}
|
||||
simple_complex& operator /= (const T& o)
|
||||
{
|
||||
r /= o;
|
||||
i /= o;
|
||||
return *this;
|
||||
}
|
||||
T real()const
|
||||
{
|
||||
return r;
|
||||
}
|
||||
T imag()const
|
||||
{
|
||||
return i;
|
||||
}
|
||||
private:
|
||||
T r, i;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline simple_complex<T> operator+(const simple_complex<T>& a, const simple_complex<T>& b)
|
||||
{
|
||||
simple_complex<T> result(a);
|
||||
result += b;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline simple_complex<T> operator-(const simple_complex<T>& a, const simple_complex<T>& b)
|
||||
{
|
||||
simple_complex<T> result(a);
|
||||
result -= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline simple_complex<T> operator*(const simple_complex<T>& a, const simple_complex<T>& b)
|
||||
{
|
||||
simple_complex<T> result(a);
|
||||
result *= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline simple_complex<T> operator/(const simple_complex<T>& a, const simple_complex<T>& b)
|
||||
{
|
||||
simple_complex<T> result(a);
|
||||
result /= b;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T real(const simple_complex<T>& c)
|
||||
{
|
||||
return c.real();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T imag(const simple_complex<T>& c)
|
||||
{
|
||||
return c.imag();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T abs(const simple_complex<T>& c)
|
||||
{
|
||||
return hypot(c.real(), c.imag());
|
||||
}
|
||||
|
||||
}}}} // namespace
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,509 @@
|
||||
// Copyright John Maddock 2007.
|
||||
// Copyright Paul A. Bristow 2007
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SF_DETAIL_INV_T_HPP
|
||||
#define BOOST_MATH_SF_DETAIL_INV_T_HPP
|
||||
|
||||
#include <boost/math/special_functions/cbrt.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
//
|
||||
// The main method used is due to Hill:
|
||||
//
|
||||
// G. W. Hill, Algorithm 396, 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] = T(1) / 6 + T(1) / (6 * df);
|
||||
T in = 1 / df;
|
||||
c[3] = (((T(1) / 120) * in) + (T(1) / 15)) * in + (T(7) / 120);
|
||||
c[4] = ((((T(1) / 5040) * in + (T(1) / 560)) * in + (T(3) / 112)) * in + T(127) / 5040);
|
||||
c[5] = ((((T(1) / 362880) * in + (T(17) / 45360)) * in + (T(67) / 60480)) * in + (T(479) / 45360)) * in + (T(4369) / 362880);
|
||||
c[6] = ((((((T(1) / 39916800) * in + (T(2503) / 39916800)) * in + (T(11867) / 19958400)) * in + (T(1285) / 798336)) * in + (T(153161) / 39916800)) * in + (T(34807) / 5702400));
|
||||
c[7] = (((((((T(1) / 6227020800LL) * in + (T(37) / 2402400)) * in +
|
||||
(T(339929) / 2075673600LL)) * in + (T(67217) / 97297200)) * in +
|
||||
(T(870341) / 691891200LL)) * in + (T(70691) / 64864800LL)) * in +
|
||||
(T(20036983LL) / 6227020800LL));
|
||||
c[8] = (((((((T(1) / 1307674368000LL) * in + (T(1042243LL) / 261534873600LL)) * in +
|
||||
(T(21470159) / 435891456000LL)) * in + (T(326228899LL) / 1307674368000LL)) * in +
|
||||
(T(843620579) / 1307674368000LL)) * in + (T(332346031LL) / 435891456000LL)) * in +
|
||||
(T(43847599) / 1307674368000LL)) * in + (T(2280356863LL) / 1307674368000LL);
|
||||
c[9] = (((((((((T(1) / 355687428096000LL)) * in + (T(24262727LL) / 22230464256000LL)) * in +
|
||||
(T(123706507LL) / 8083805184000LL)) * in + (T(404003599LL) / 4446092851200LL)) * in +
|
||||
(T(51811946317LL) / 177843714048000LL)) * in + (T(91423417LL) / 177843714048LL)) * in +
|
||||
(T(32285445833LL) / 88921857024000LL)) * in + (T(531839683LL) / 1710035712000LL)) * in +
|
||||
(T(49020204823LL) / 50812489728000LL);
|
||||
c[10] = (((((((((T(1) / 121645100408832000LL) * in +
|
||||
(T(4222378423LL) / 13516122267648000LL)) * in +
|
||||
(T(49573465457LL) / 10137091700736000LL)) * in +
|
||||
(T(176126809LL) / 5304600576000LL)) * in +
|
||||
(T(44978231873LL) / 355687428096000LL)) * in +
|
||||
(T(5816850595639LL) / 20274183401472000LL)) * in +
|
||||
(T(73989712601LL) / 206879422464000LL)) * in +
|
||||
(T(26591354017LL) / 259925428224000LL)) * in +
|
||||
(T(14979648446341LL) / 40548366802944000LL)) * in +
|
||||
(T(65967241200001LL) / 121645100408832000LL);
|
||||
//
|
||||
// The result is then a polynomial in v (see Eq 56 of Shaw):
|
||||
//
|
||||
return tools::evaluate_odd_polynomial(c, v);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T inverse_students_t(T df, T u, T v, const Policy& pol, bool* pexact = 0)
|
||||
{
|
||||
//
|
||||
// df = number of degrees of freedom.
|
||||
// u = probablity.
|
||||
// v = 1 - u.
|
||||
// l = lanczos type to use.
|
||||
//
|
||||
BOOST_MATH_STD_USING
|
||||
bool invert = false;
|
||||
T result = 0;
|
||||
if(pexact)
|
||||
*pexact = false;
|
||||
if(u > v)
|
||||
{
|
||||
// function is symmetric, invert it:
|
||||
std::swap(u, v);
|
||||
invert = true;
|
||||
}
|
||||
if((floor(df) == df) && (df < 20))
|
||||
{
|
||||
//
|
||||
// we have integer degrees of freedom, try for the special
|
||||
// cases first:
|
||||
//
|
||||
T tolerance = ldexp(1.0f, (2 * policies::digits<T, Policy>()) / 3);
|
||||
|
||||
switch(boost::math::tools::real_cast<int>(df))
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
//
|
||||
// df = 1 is the same as the Cauchy distribution, see
|
||||
// Shaw Eq 35:
|
||||
//
|
||||
if(u == 0.5)
|
||||
result = 0;
|
||||
else
|
||||
result = -cos(constants::pi<T>() * u) / sin(constants::pi<T>() * u);
|
||||
if(pexact)
|
||||
*pexact = true;
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
//
|
||||
// df = 2 has an exact result, see Shaw Eq 36:
|
||||
//
|
||||
result =(2 * u - 1) / sqrt(2 * u * v);
|
||||
if(pexact)
|
||||
*pexact = true;
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
//
|
||||
// df = 4 has an exact result, see Shaw Eq 38 & 39:
|
||||
//
|
||||
T alpha = 4 * u * v;
|
||||
T root_alpha = sqrt(alpha);
|
||||
T r = 4 * cos(acos(root_alpha) / 3) / root_alpha;
|
||||
T x = sqrt(r - 4);
|
||||
result = u - 0.5f < 0 ? -x : x;
|
||||
if(pexact)
|
||||
*pexact = true;
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
//
|
||||
// We get numeric overflow in this area:
|
||||
//
|
||||
if(u < 1e-150)
|
||||
return (invert ? -1 : 1) * inverse_students_t_hill(df, u, pol);
|
||||
//
|
||||
// Newton-Raphson iteration of a polynomial case,
|
||||
// choice of seed value is taken from Shaw's online
|
||||
// supplement:
|
||||
//
|
||||
T a = 4 * (u - u * u);//1 - 4 * (u - 0.5f) * (u - 0.5f);
|
||||
T b = boost::math::cbrt(a);
|
||||
static const T c = 0.85498797333834849467655443627193L;
|
||||
T p = 6 * (1 + c * (1 / b - 1));
|
||||
T p0;
|
||||
do{
|
||||
T p2 = p * p;
|
||||
T p4 = p2 * p2;
|
||||
T p5 = p * p4;
|
||||
p0 = p;
|
||||
// next term is given by Eq 41:
|
||||
p = 2 * (8 * a * p5 - 270 * p2 + 2187) / (5 * (4 * a * p4 - 216 * p - 243));
|
||||
}while(fabs((p - p0) / p) > tolerance);
|
||||
//
|
||||
// Use Eq 45 to extract the result:
|
||||
//
|
||||
p = sqrt(p - df);
|
||||
result = (u - 0.5f) < 0 ? -p : p;
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
//
|
||||
// These are Shaw's "exact" but iterative solutions
|
||||
// for even df, the numerical accuracy of these is
|
||||
// rather less than Hill's method, so these are disabled
|
||||
// for now, which is a shame because they are reasonably
|
||||
// quick to evaluate...
|
||||
//
|
||||
case 8:
|
||||
{
|
||||
//
|
||||
// Newton-Raphson iteration of a polynomial case,
|
||||
// choice of seed value is taken from Shaw's online
|
||||
// supplement:
|
||||
//
|
||||
static const T c8 = 0.85994765706259820318168359251872L;
|
||||
T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
|
||||
T b = pow(a, T(1) / 4);
|
||||
T p = 8 * (1 + c8 * (1 / b - 1));
|
||||
T p0 = p;
|
||||
do{
|
||||
T p5 = p * p;
|
||||
p5 *= p5 * p;
|
||||
p0 = p;
|
||||
// Next term is given by Eq 42:
|
||||
p = 2 * (3 * p + (640 * (160 + p * (24 + p * (p + 4)))) / (-5120 + p * (-2048 - 960 * p + a * p5))) / 7;
|
||||
}while(fabs((p - p0) / p) > tolerance);
|
||||
//
|
||||
// Use Eq 45 to extract the result:
|
||||
//
|
||||
p = sqrt(p - df);
|
||||
result = (u - 0.5f) < 0 ? -p : p;
|
||||
break;
|
||||
}
|
||||
case 10:
|
||||
{
|
||||
//
|
||||
// Newton-Raphson iteration of a polynomial case,
|
||||
// choice of seed value is taken from Shaw's online
|
||||
// supplement:
|
||||
//
|
||||
static const T c10 = 0.86781292867813396759105692122285L;
|
||||
T a = 4 * (u - u * u); //1 - 4 * (u - 0.5f) * (u - 0.5f);
|
||||
T b = pow(a, T(1) / 5);
|
||||
T p = 10 * (1 + c10 * (1 / b - 1));
|
||||
T p0;
|
||||
do{
|
||||
T p6 = p * p;
|
||||
p6 *= p6 * p6;
|
||||
p0 = p;
|
||||
// Next term given by Eq 43:
|
||||
p = (8 * p) / 9 + (218750 * (21875 + 4 * p * (625 + p * (75 + 2 * p * (5 + p))))) /
|
||||
(9 * (-68359375 + 8 * p * (-2343750 + p * (-546875 - 175000 * p + 8 * a * p6))));
|
||||
}while(fabs((p - p0) / p) > tolerance);
|
||||
//
|
||||
// Use Eq 45 to extract the result:
|
||||
//
|
||||
p = sqrt(p - df);
|
||||
result = (u - 0.5f) < 0 ? -p : p;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
goto calculate_real;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
calculate_real:
|
||||
if(df < 3)
|
||||
{
|
||||
//
|
||||
// Use a roughly linear scheme to choose between Shaw's
|
||||
// tail series and body series:
|
||||
//
|
||||
T crossover = 0.2742f - df * 0.0242143f;
|
||||
if(u > crossover)
|
||||
{
|
||||
result = boost::math::detail::inverse_students_t_body_series(df, u, pol);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Use Hill's method except in the exteme tails
|
||||
// where we use Shaw's tail series.
|
||||
// The crossover point is roughly exponential in -df:
|
||||
//
|
||||
T crossover = ldexp(1.0f, tools::real_cast<int>(df / -0.654f));
|
||||
if(u > crossover)
|
||||
{
|
||||
result = boost::math::detail::inverse_students_t_hill(df, u, pol);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = boost::math::detail::inverse_students_t_tail_series(df, u, pol);
|
||||
}
|
||||
}
|
||||
}
|
||||
return invert ? -result : result;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T find_ibeta_inv_from_t_dist(T a, T p, T q, T* py, const Policy& pol)
|
||||
{
|
||||
T u = (p > q) ? 0.5f - q / 2 : p / 2;
|
||||
T v = 1 - u; // u < 0.5 so no cancellation error
|
||||
T df = a * 2;
|
||||
T t = boost::math::detail::inverse_students_t(df, u, v, pol);
|
||||
T x = df / (df + t * t);
|
||||
*py = t * t / (df + t * t);
|
||||
return x;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::false_*)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
//
|
||||
// Need to use inverse incomplete beta to get
|
||||
// required precision so not so fast:
|
||||
//
|
||||
T probability = (p > 0.5) ? 1 - p : p;
|
||||
T t, x, y;
|
||||
x = ibeta_inv(df / 2, T(0.5), 2 * probability, &y, pol);
|
||||
if(df * y > tools::max_value<T>() * x)
|
||||
t = policies::raise_overflow_error<T>("boost::math::students_t_quantile<%1%>(%1%,%1%)", 0, pol);
|
||||
else
|
||||
t = sqrt(df * y / x);
|
||||
//
|
||||
// Figure out sign based on the size of p:
|
||||
//
|
||||
if(p < 0.5)
|
||||
t = -t;
|
||||
return t;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T fast_students_t_quantile_imp(T df, T p, const Policy& pol, const mpl::true_*)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
bool invert = false;
|
||||
if((df < 2) && (floor(df) != df))
|
||||
return boost::math::detail::fast_students_t_quantile_imp(df, p, pol, static_cast<mpl::false_*>(0));
|
||||
if(p > 0.5)
|
||||
{
|
||||
p = 1 - p;
|
||||
invert = true;
|
||||
}
|
||||
//
|
||||
// Get an estimate of the result:
|
||||
//
|
||||
bool exact;
|
||||
T t = inverse_students_t(df, p, 1-p, pol, &exact);
|
||||
if((t == 0) || exact)
|
||||
return invert ? -t : t; // can't do better!
|
||||
//
|
||||
// Change variables to inverse incomplete beta:
|
||||
//
|
||||
T t2 = t * t;
|
||||
T xb = df / (df + t2);
|
||||
T y = t2 / (df + t2);
|
||||
T a = df / 2;
|
||||
//
|
||||
// t can be so large that x underflows,
|
||||
// just return our estimate in that case:
|
||||
//
|
||||
if(xb == 0)
|
||||
return t;
|
||||
//
|
||||
// Get incomplete beta and it's derivative:
|
||||
//
|
||||
T f1;
|
||||
T f0 = xb < y ? ibeta_imp(a, constants::half<T>(), xb, pol, false, true, &f1)
|
||||
: ibeta_imp(constants::half<T>(), a, y, pol, true, true, &f1);
|
||||
|
||||
// Get cdf from incomplete beta result:
|
||||
T p0 = f0 / 2 - p;
|
||||
// Get pdf from derivative:
|
||||
T p1 = f1 * sqrt(y * xb * xb * xb / df);
|
||||
//
|
||||
// Second derivative divided by p1:
|
||||
//
|
||||
// yacas gives:
|
||||
//
|
||||
// In> PrettyForm(Simplify(D(t) (1 + t^2/v) ^ (-(v+1)/2)))
|
||||
//
|
||||
// | | v + 1 | |
|
||||
// | -| ----- + 1 | |
|
||||
// | | 2 | |
|
||||
// -| | 2 | |
|
||||
// | | t | |
|
||||
// | | -- + 1 | |
|
||||
// | ( v + 1 ) * | v | * t |
|
||||
// ---------------------------------------------
|
||||
// v
|
||||
//
|
||||
// Which after some manipulation is:
|
||||
//
|
||||
// -p1 * t * (df + 1) / (t^2 + df)
|
||||
//
|
||||
T p2 = t * (df + 1) / (t * t + df);
|
||||
// Halley step:
|
||||
t = fabs(t);
|
||||
t += p0 / (p1 + p0 * p2 / 2);
|
||||
return !invert ? -t : t;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T fast_students_t_quantile(T df, T p, const Policy& pol)
|
||||
{
|
||||
typedef typename policies::evaluation<T, Policy>::type value_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
typedef mpl::bool_<
|
||||
(std::numeric_limits<T>::digits <= 53)
|
||||
&&
|
||||
(std::numeric_limits<T>::is_specialized)> tag_type;
|
||||
return policies::checked_narrowing_cast<T, forwarding_policy>(fast_students_t_quantile_imp(static_cast<value_type>(df), static_cast<value_type>(p), pol, static_cast<tag_type*>(0)), "boost::math::students_t_quantile<%1%>(%1%,%1%,%1%)");
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_SF_DETAIL_INV_T_HPP
|
||||
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
// Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SP_UC_FACTORIALS_HPP
|
||||
#define BOOST_MATH_SP_UC_FACTORIALS_HPP
|
||||
|
||||
#include <boost/array.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push) // Temporary until lexical cast fixed.
|
||||
#pragma warning(disable: 4127 4701)
|
||||
#endif
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#include <cmath>
|
||||
#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
|
||||
445
include/boost/math/special_functions/digamma.hpp
Normal file
445
include/boost/math/special_functions/digamma.hpp
Normal file
@@ -0,0 +1,445 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SF_DIGAMMA_HPP
|
||||
#define BOOST_MATH_SF_DIGAMMA_HPP
|
||||
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/mpl/comparison.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace math{
|
||||
namespace detail{
|
||||
//
|
||||
// Begin by defining the smallest value for which it is safe to
|
||||
// use the asymptotic expansion for digamma:
|
||||
//
|
||||
inline unsigned digamma_large_lim(const mpl::int_<0>*)
|
||||
{ return 20; }
|
||||
|
||||
inline unsigned digamma_large_lim(const void*)
|
||||
{ return 10; }
|
||||
//
|
||||
// Implementations of the asymptotic expansion come next,
|
||||
// the coefficients of the series have been evaluated
|
||||
// in advance at high precision, and the series truncated
|
||||
// at the first term that's too small to effect the result.
|
||||
// Note that the series becomes divergent after a while
|
||||
// so truncation is very important.
|
||||
//
|
||||
// This first one gives 34-digit precision for x >= 20:
|
||||
//
|
||||
template <class T>
|
||||
inline T digamma_imp_large(T x, const mpl::int_<0>*)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions.
|
||||
static const T P[] = {
|
||||
0.083333333333333333333333333333333333333333333333333L,
|
||||
-0.0083333333333333333333333333333333333333333333333333L,
|
||||
0.003968253968253968253968253968253968253968253968254L,
|
||||
-0.0041666666666666666666666666666666666666666666666667L,
|
||||
0.0075757575757575757575757575757575757575757575757576L,
|
||||
-0.021092796092796092796092796092796092796092796092796L,
|
||||
0.083333333333333333333333333333333333333333333333333L,
|
||||
-0.44325980392156862745098039215686274509803921568627L,
|
||||
3.0539543302701197438039543302701197438039543302701L,
|
||||
-26.456212121212121212121212121212121212121212121212L,
|
||||
281.4601449275362318840579710144927536231884057971L,
|
||||
-3607.510546398046398046398046398046398046398046398L,
|
||||
54827.583333333333333333333333333333333333333333333L,
|
||||
-974936.82385057471264367816091954022988505747126437L,
|
||||
20052695.796688078946143462272494530559046688078946L,
|
||||
-472384867.72162990196078431372549019607843137254902L,
|
||||
12635724795.916666666666666666666666666666666666667L
|
||||
};
|
||||
x -= 1;
|
||||
T result = log(x);
|
||||
result += 1 / (2 * x);
|
||||
T z = 1 / (x*x);
|
||||
result -= z * tools::evaluate_polynomial(P, z);
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// 19-digit precision for x >= 10:
|
||||
//
|
||||
template <class T>
|
||||
inline T digamma_imp_large(T x, const mpl::int_<64>*)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions.
|
||||
static const T P[] = {
|
||||
0.083333333333333333333333333333333333333333333333333L,
|
||||
-0.0083333333333333333333333333333333333333333333333333L,
|
||||
0.003968253968253968253968253968253968253968253968254L,
|
||||
-0.0041666666666666666666666666666666666666666666666667L,
|
||||
0.0075757575757575757575757575757575757575757575757576L,
|
||||
-0.021092796092796092796092796092796092796092796092796L,
|
||||
0.083333333333333333333333333333333333333333333333333L,
|
||||
-0.44325980392156862745098039215686274509803921568627L,
|
||||
3.0539543302701197438039543302701197438039543302701L,
|
||||
-26.456212121212121212121212121212121212121212121212L,
|
||||
281.4601449275362318840579710144927536231884057971L,
|
||||
};
|
||||
x -= 1;
|
||||
T result = log(x);
|
||||
result += 1 / (2 * x);
|
||||
T z = 1 / (x*x);
|
||||
result -= z * tools::evaluate_polynomial(P, z);
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// 17-digit precision for x >= 10:
|
||||
//
|
||||
template <class T>
|
||||
inline T digamma_imp_large(T x, const mpl::int_<53>*)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions.
|
||||
static const T P[] = {
|
||||
0.083333333333333333333333333333333333333333333333333L,
|
||||
-0.0083333333333333333333333333333333333333333333333333L,
|
||||
0.003968253968253968253968253968253968253968253968254L,
|
||||
-0.0041666666666666666666666666666666666666666666666667L,
|
||||
0.0075757575757575757575757575757575757575757575757576L,
|
||||
-0.021092796092796092796092796092796092796092796092796L,
|
||||
0.083333333333333333333333333333333333333333333333333L,
|
||||
-0.44325980392156862745098039215686274509803921568627L
|
||||
};
|
||||
x -= 1;
|
||||
T result = log(x);
|
||||
result += 1 / (2 * x);
|
||||
T z = 1 / (x*x);
|
||||
result -= z * tools::evaluate_polynomial(P, z);
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// 9-digit precision for x >= 10:
|
||||
//
|
||||
template <class T>
|
||||
inline T digamma_imp_large(T x, const mpl::int_<24>*)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions.
|
||||
static const T P[] = {
|
||||
0.083333333333333333333333333333333333333333333333333L,
|
||||
-0.0083333333333333333333333333333333333333333333333333L,
|
||||
0.003968253968253968253968253968253968253968253968254L
|
||||
};
|
||||
x -= 1;
|
||||
T result = log(x);
|
||||
result += 1 / (2 * x);
|
||||
T z = 1 / (x*x);
|
||||
result -= z * tools::evaluate_polynomial(P, z);
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Now follow rational approximations over the range [1,2].
|
||||
//
|
||||
// 35-digit precision:
|
||||
//
|
||||
template <class T>
|
||||
T digamma_imp_1_2(T x, const mpl::int_<0>*)
|
||||
{
|
||||
//
|
||||
// Now the approximation, we use the form:
|
||||
//
|
||||
// digamma(x) = (x - root) * (Y + R(x-1))
|
||||
//
|
||||
// Where root is the location of the positive root of digamma,
|
||||
// Y is a constant, and R is optimised for low absolute error
|
||||
// compared to Y.
|
||||
//
|
||||
// Max error found at 128-bit long double precision: 5.541e-35
|
||||
// Maximum Deviation Found (approximation error): 1.965e-35
|
||||
//
|
||||
static const float Y = 0.99558162689208984375F;
|
||||
|
||||
static const T root1 = 1569415565.0 / 1073741824uL;
|
||||
static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
|
||||
static const T root3 = ((111616537.0 / 1073741824uL) / 1073741824uL) / 1073741824uL;
|
||||
static const T root4 = (((503992070.0 / 1073741824uL) / 1073741824uL) / 1073741824uL) / 1073741824uL;
|
||||
static const T root5 = 0.52112228569249997894452490385577338504019838794544e-36L;
|
||||
|
||||
static const T P[] = {
|
||||
0.25479851061131551526977464225335883769L,
|
||||
-0.18684290534374944114622235683619897417L,
|
||||
-0.80360876047931768958995775910991929922L,
|
||||
-0.67227342794829064330498117008564270136L,
|
||||
-0.26569010991230617151285010695543858005L,
|
||||
-0.05775672694575986971640757748003553385L,
|
||||
-0.0071432147823164975485922555833274240665L,
|
||||
-0.00048740753910766168912364555706064993274L,
|
||||
-0.16454996865214115723416538844975174761e-4L,
|
||||
-0.20327832297631728077731148515093164955e-6L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1,
|
||||
2.6210924610812025425088411043163287646L,
|
||||
2.6850757078559596612621337395886392594L,
|
||||
1.4320913706209965531250495490639289418L,
|
||||
0.4410872083455009362557012239501953402L,
|
||||
0.081385727399251729505165509278152487225L,
|
||||
0.0089478633066857163432104815183858149496L,
|
||||
0.00055861622855066424871506755481997374154L,
|
||||
0.1760168552357342401304462967950178554e-4L,
|
||||
0.20585454493572473724556649516040874384e-6L,
|
||||
-0.90745971844439990284514121823069162795e-11L,
|
||||
0.48857673606545846774761343500033283272e-13L,
|
||||
};
|
||||
T g = x - root1;
|
||||
g -= root2;
|
||||
g -= root3;
|
||||
g -= root4;
|
||||
g -= root5;
|
||||
T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
|
||||
T result = g * Y + g * r;
|
||||
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// 19-digit precision:
|
||||
//
|
||||
template <class T>
|
||||
T digamma_imp_1_2(T x, const mpl::int_<64>*)
|
||||
{
|
||||
//
|
||||
// Now the approximation, we use the form:
|
||||
//
|
||||
// digamma(x) = (x - root) * (Y + R(x-1))
|
||||
//
|
||||
// Where root is the location of the positive root of digamma,
|
||||
// Y is a constant, and R is optimised for low absolute error
|
||||
// compared to Y.
|
||||
//
|
||||
// Max error found at 80-bit long double precision: 5.016e-20
|
||||
// Maximum Deviation Found (approximation error): 3.575e-20
|
||||
//
|
||||
static const float Y = 0.99558162689208984375F;
|
||||
|
||||
static const T root1 = 1569415565.0 / 1073741824uL;
|
||||
static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
|
||||
static const T root3 = 0.9016312093258695918615325266959189453125e-19L;
|
||||
|
||||
static const T P[] = {
|
||||
0.254798510611315515235L,
|
||||
-0.314628554532916496608L,
|
||||
-0.665836341559876230295L,
|
||||
-0.314767657147375752913L,
|
||||
-0.0541156266153505273939L,
|
||||
-0.00289268368333918761452L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1,
|
||||
2.1195759927055347547L,
|
||||
1.54350554664961128724L,
|
||||
0.486986018231042975162L,
|
||||
0.0660481487173569812846L,
|
||||
0.00298999662592323990972L,
|
||||
-0.165079794012604905639e-5L,
|
||||
0.317940243105952177571e-7L
|
||||
};
|
||||
T g = x - root1;
|
||||
g -= root2;
|
||||
g -= root3;
|
||||
T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
|
||||
T result = g * Y + g * r;
|
||||
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// 18-digit precision:
|
||||
//
|
||||
template <class T>
|
||||
T digamma_imp_1_2(T x, const mpl::int_<53>*)
|
||||
{
|
||||
//
|
||||
// Now the approximation, we use the form:
|
||||
//
|
||||
// digamma(x) = (x - root) * (Y + R(x-1))
|
||||
//
|
||||
// Where root is the location of the positive root of digamma,
|
||||
// Y is a constant, and R is optimised for low absolute error
|
||||
// compared to Y.
|
||||
//
|
||||
// Maximum Deviation Found: 1.466e-18
|
||||
// At double precision, max error found: 2.452e-17
|
||||
//
|
||||
static const float Y = 0.99558162689208984F;
|
||||
|
||||
static const T root1 = 1569415565.0 / 1073741824uL;
|
||||
static const T root2 = (381566830.0 / 1073741824uL) / 1073741824uL;
|
||||
static const T root3 = 0.9016312093258695918615325266959189453125e-19L;
|
||||
|
||||
static const T P[] = {
|
||||
0.25479851061131551L,
|
||||
-0.32555031186804491L,
|
||||
-0.65031853770896507L,
|
||||
-0.28919126444774784L,
|
||||
-0.045251321448739056L,
|
||||
-0.0020713321167745952L
|
||||
};
|
||||
static const T Q[] = {
|
||||
1L,
|
||||
2.0767117023730469L,
|
||||
1.4606242909763515L,
|
||||
0.43593529692665969L,
|
||||
0.054151797245674225L,
|
||||
0.0021284987017821144L,
|
||||
-0.55789841321675513e-6L
|
||||
};
|
||||
T g = x - root1;
|
||||
g -= root2;
|
||||
g -= root3;
|
||||
T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
|
||||
T result = g * Y + g * r;
|
||||
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// 9-digit precision:
|
||||
//
|
||||
template <class T>
|
||||
inline T digamma_imp_1_2(T x, const mpl::int_<24>*)
|
||||
{
|
||||
//
|
||||
// Now the approximation, we use the form:
|
||||
//
|
||||
// digamma(x) = (x - root) * (Y + R(x-1))
|
||||
//
|
||||
// Where root is the location of the positive root of digamma,
|
||||
// Y is a constant, and R is optimised for low absolute error
|
||||
// compared to Y.
|
||||
//
|
||||
// Maximum Deviation Found: 3.388e-010
|
||||
// At float precision, max error found: 2.008725e-008
|
||||
//
|
||||
static const float Y = 0.99558162689208984f;
|
||||
static const T root = 1532632.0f / 1048576;
|
||||
static const T root_minor = static_cast<T>(0.3700660185912626595423257213284682051735604e-6L);
|
||||
static const T P[] = {
|
||||
0.25479851023250261e0,
|
||||
-0.44981331915268368e0,
|
||||
-0.43916936919946835e0,
|
||||
-0.61041765350579073e-1
|
||||
};
|
||||
static const T Q[] = {
|
||||
0.1e1,
|
||||
0.15890202430554952e1,
|
||||
0.65341249856146947e0,
|
||||
0.63851690523355715e-1
|
||||
};
|
||||
T g = x - root;
|
||||
g -= root_minor;
|
||||
T r = tools::evaluate_polynomial(P, x-1) / tools::evaluate_polynomial(Q, x-1);
|
||||
T result = g * Y + g * r;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class Tag, class Policy>
|
||||
T digamma_imp(T x, const Tag* t, const Policy& pol)
|
||||
{
|
||||
//
|
||||
// This handles reflection of negative arguments, and all our
|
||||
// error handling, then forwards to the T-specific approximation.
|
||||
//
|
||||
BOOST_MATH_STD_USING // ADL of std functions.
|
||||
|
||||
T result = 0;
|
||||
//
|
||||
// Check for negative arguments and use reflection:
|
||||
//
|
||||
if(x < 0)
|
||||
{
|
||||
// Reflect:
|
||||
x = 1 - x;
|
||||
// Argument reduction for tan:
|
||||
T remainder = x - floor(x);
|
||||
// Shift to negative if > 0.5:
|
||||
if(remainder > 0.5)
|
||||
{
|
||||
remainder -= 1;
|
||||
}
|
||||
//
|
||||
// check for evaluation at a negative pole:
|
||||
//
|
||||
if(remainder == 0)
|
||||
{
|
||||
return policies::raise_pole_error<T>("boost::math::digamma<%1%>(%1%)", 0, (1-x), pol);
|
||||
}
|
||||
result = constants::pi<T>() / tan(constants::pi<T>() * remainder);
|
||||
}
|
||||
//
|
||||
// If we're above the lower-limit for the
|
||||
// asymptotic expansion then use it:
|
||||
//
|
||||
if(x >= digamma_large_lim(t))
|
||||
{
|
||||
result += digamma_imp_large(x, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// If x > 2 reduce to the interval [1,2]:
|
||||
//
|
||||
while(x > 2)
|
||||
{
|
||||
x -= 1;
|
||||
result += 1/x;
|
||||
}
|
||||
//
|
||||
// If x < 1 use recurrance to shift to > 1:
|
||||
//
|
||||
if(x < 1)
|
||||
{
|
||||
result = -1/x;
|
||||
x += 1;
|
||||
}
|
||||
result += digamma_imp_1_2(x, t);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
digamma(T x, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
typedef typename policies::precision<T, Policy>::type precision_type;
|
||||
typedef typename mpl::if_<
|
||||
mpl::or_<
|
||||
mpl::less_equal<precision_type, mpl::int_<0> >,
|
||||
mpl::greater<precision_type, mpl::int_<64> >
|
||||
>,
|
||||
mpl::int_<0>,
|
||||
typename mpl::if_<
|
||||
mpl::less<precision_type, mpl::int_<25> >,
|
||||
mpl::int_<24>,
|
||||
typename mpl::if_<
|
||||
mpl::less<precision_type, mpl::int_<54> >,
|
||||
mpl::int_<53>,
|
||||
mpl::int_<64>
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::digamma_imp(
|
||||
static_cast<value_type>(x),
|
||||
static_cast<const tag_type*>(0), pol), "boost::math::digamma<%1%>(%1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type
|
||||
digamma(T x)
|
||||
{
|
||||
return digamma(x, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
#endif
|
||||
182
include/boost/math/special_functions/ellint_1.hpp
Normal file
182
include/boost/math/special_functions/ellint_1.hpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Copyright (c) 2006 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// History:
|
||||
// XZ wrote the original of this file as part of the Google
|
||||
// Summer of Code 2006. JM modified it to fit into the
|
||||
// Boost.Math conceptual framework better, and to ensure
|
||||
// that the code continues to work no matter how many digits
|
||||
// type T has.
|
||||
|
||||
#ifndef BOOST_MATH_ELLINT_1_HPP
|
||||
#define BOOST_MATH_ELLINT_1_HPP
|
||||
|
||||
#include <boost/math/special_functions/ellint_rf.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#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 = 2 * (phi - rphi) / constants::pi<T>();
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(m);
|
||||
int s = 1;
|
||||
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
|
||||
{
|
||||
m += 1;
|
||||
s = -1;
|
||||
rphi = constants::pi<T>() / 2 - rphi;
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(rphi);
|
||||
}
|
||||
T sinp = sin(rphi);
|
||||
T cosp = cos(rphi);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(sinp);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(cosp);
|
||||
result = s * sinp * ellint_rf_imp(cosp * cosp, 1 - k * k * sinp * sinp, T(1), pol);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
||||
if(m != 0)
|
||||
{
|
||||
result += m * ellint_k_imp(k, pol);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(result);
|
||||
}
|
||||
}
|
||||
return invert ? -result : result;
|
||||
}
|
||||
|
||||
// Complete elliptic integral (Legendre form) of the first kind
|
||||
template <typename T, typename Policy>
|
||||
T ellint_k_imp(T k, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::ellint_k<%1%>(%1%)";
|
||||
|
||||
if (abs(k) > 1)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got k = %1%, function requires |k| <= 1", k, pol);
|
||||
}
|
||||
if (abs(k) == 1)
|
||||
{
|
||||
return policies::raise_overflow_error<T>(function, 0, pol);
|
||||
}
|
||||
|
||||
T x = 0;
|
||||
T y = 1 - k * k;
|
||||
T z = 1;
|
||||
T value = ellint_rf_imp(x, y, z, pol);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename Policy>
|
||||
inline typename tools::promote_args<T>::type ellint_1(T k, const Policy& pol, const mpl::true_&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_k_imp(static_cast<value_type>(k), pol), "boost::math::ellint_1<%1%>(%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const mpl::false_&)
|
||||
{
|
||||
return boost::math::ellint_1(k, phi, policies::policy<>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Complete elliptic integral (Legendre form) of the first kind
|
||||
template <typename T>
|
||||
inline typename tools::promote_args<T>::type ellint_1(T k)
|
||||
{
|
||||
return ellint_1(k, policies::policy<>());
|
||||
}
|
||||
|
||||
// Elliptic integral (Legendre form) of the first kind
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_f_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_1<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi)
|
||||
{
|
||||
typedef typename policies::is_policy<T2>::type tag_type;
|
||||
return detail::ellint_1(k, phi, tag_type());
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_ELLINT_1_HPP
|
||||
163
include/boost/math/special_functions/ellint_2.hpp
Normal file
163
include/boost/math/special_functions/ellint_2.hpp
Normal file
@@ -0,0 +1,163 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Copyright (c) 2006 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// History:
|
||||
// XZ wrote the original of this file as part of the Google
|
||||
// Summer of Code 2006. JM modified it to fit into the
|
||||
// Boost.Math conceptual framework better, and to ensure
|
||||
// that the code continues to work no matter how many digits
|
||||
// type T has.
|
||||
|
||||
#ifndef BOOST_MATH_ELLINT_2_HPP
|
||||
#define BOOST_MATH_ELLINT_2_HPP
|
||||
|
||||
#include <boost/math/special_functions/ellint_rf.hpp>
|
||||
#include <boost/math/special_functions/ellint_rd.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#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 = 2 * (phi - rphi) / constants::pi<T>();
|
||||
int s = 1;
|
||||
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
|
||||
{
|
||||
m += 1;
|
||||
s = -1;
|
||||
rphi = constants::pi<T>() / 2 - rphi;
|
||||
}
|
||||
T sinp = sin(rphi);
|
||||
T cosp = cos(rphi);
|
||||
T x = cosp * cosp;
|
||||
T t = k * k * sinp * sinp;
|
||||
T y = 1 - t;
|
||||
T z = 1;
|
||||
result = s * sinp * (ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3);
|
||||
if(m != 0)
|
||||
result += m * ellint_e_imp(k, pol);
|
||||
}
|
||||
return invert ? -result : result;
|
||||
}
|
||||
|
||||
// Complete elliptic integral (Legendre form) of the second kind
|
||||
template <typename T, typename Policy>
|
||||
T ellint_e_imp(T k, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
if (abs(k) > 1)
|
||||
{
|
||||
return policies::raise_domain_error<T>("boost::math::ellint_e<%1%>(%1%)",
|
||||
"Got k = %1%, function requires |k| <= 1", k, pol);
|
||||
}
|
||||
if (abs(k) == 1)
|
||||
{
|
||||
return static_cast<T>(1);
|
||||
}
|
||||
|
||||
T x = 0;
|
||||
T t = k * k;
|
||||
T y = 1 - t;
|
||||
T z = 1;
|
||||
T value = ellint_rf_imp(x, y, z, pol) - t * ellint_rd_imp(x, y, z, pol) / 3;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, typename Policy>
|
||||
inline typename tools::promote_args<T>::type ellint_2(T k, const Policy& pol, const mpl::true_&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%)");
|
||||
}
|
||||
|
||||
// Elliptic integral (Legendre form) of the second kind
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const mpl::false_&)
|
||||
{
|
||||
return boost::math::ellint_2(k, phi, policies::policy<>());
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
// Complete elliptic integral (Legendre form) of the second kind
|
||||
template <typename T>
|
||||
inline typename tools::promote_args<T>::type ellint_2(T k)
|
||||
{
|
||||
return ellint_2(k, policies::policy<>());
|
||||
}
|
||||
|
||||
// Elliptic integral (Legendre form) of the second kind
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi)
|
||||
{
|
||||
typedef typename policies::is_policy<T2>::type tag_type;
|
||||
return detail::ellint_2(k, phi, tag_type());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::ellint_e_imp(static_cast<value_type>(phi), static_cast<value_type>(k), pol), "boost::math::ellint_2<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_ELLINT_2_HPP
|
||||
327
include/boost/math/special_functions/ellint_3.hpp
Normal file
327
include/boost/math/special_functions/ellint_3.hpp
Normal file
@@ -0,0 +1,327 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Copyright (c) 2006 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// History:
|
||||
// XZ wrote the original of this file as part of the Google
|
||||
// Summer of Code 2006. JM modified it to fit into the
|
||||
// Boost.Math conceptual framework better, and to correctly
|
||||
// handle the various corner cases.
|
||||
//
|
||||
|
||||
#ifndef BOOST_MATH_ELLINT_3_HPP
|
||||
#define BOOST_MATH_ELLINT_3_HPP
|
||||
|
||||
#include <boost/math/special_functions/ellint_rf.hpp>
|
||||
#include <boost/math/special_functions/ellint_rj.hpp>
|
||||
#include <boost/math/special_functions/ellint_1.hpp>
|
||||
#include <boost/math/special_functions/ellint_2.hpp>
|
||||
#include <boost/math/special_functions/log1p.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#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 {
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol);
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T ellint_pi_imp(T v, T k, T vc, const Policy& pol);
|
||||
|
||||
// Elliptic integral (Legendre form) of the third kind
|
||||
template <typename T, typename Policy>
|
||||
T ellint_pi_imp(T v, T phi, T k, T vc, const Policy& pol)
|
||||
{
|
||||
// Note vc = 1-v presumably without cancellation error.
|
||||
T value, x, y, z, p, t;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
using namespace boost::math::constants;
|
||||
|
||||
static const char* function = "boost::math::ellint_3<%1%>(%1%,%1%,%1%)";
|
||||
|
||||
if (abs(k) > 1)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got k = %1%, function requires |k| <= 1", k, pol);
|
||||
}
|
||||
|
||||
T sphi = sin(fabs(phi));
|
||||
|
||||
if(v > 1 / (sphi * sphi))
|
||||
{
|
||||
// Complex result is a domain error:
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got v = %1%, but result is complex for v > 1 / sin^2(phi)", v, pol);
|
||||
}
|
||||
|
||||
// Special cases first:
|
||||
if(v == 0)
|
||||
{
|
||||
// A&S 17.7.18 & 19
|
||||
return (k == 0) ? phi : ellint_f_imp(phi, k, pol);
|
||||
}
|
||||
if(phi == constants::pi<T>() / 2)
|
||||
{
|
||||
// Have to filter this case out before the next
|
||||
// special case, otherwise we might get an infinity from
|
||||
// tan(phi).
|
||||
// Also note that since we can't represent PI/2 exactly
|
||||
// in a T, this is a bit of a guess as to the users true
|
||||
// intent...
|
||||
//
|
||||
return ellint_pi_imp(v, k, vc, pol);
|
||||
}
|
||||
if(k == 0)
|
||||
{
|
||||
// A&S 17.7.20:
|
||||
if(v < 1)
|
||||
{
|
||||
T vcr = sqrt(vc);
|
||||
return atan(vcr * tan(phi)) / vcr;
|
||||
}
|
||||
else if(v == 1)
|
||||
{
|
||||
return tan(phi);
|
||||
}
|
||||
else
|
||||
{
|
||||
// v > 1:
|
||||
T vcr = sqrt(-vc);
|
||||
T arg = vcr * tan(phi);
|
||||
return (boost::math::log1p(arg, pol) - boost::math::log1p(-arg, pol)) / (2 * vcr);
|
||||
}
|
||||
}
|
||||
|
||||
if(v < 0)
|
||||
{
|
||||
//
|
||||
// If we don't shift to 0 <= v <= 1 we get
|
||||
// cancellation errors later on. Use
|
||||
// A&S 17.7.15/16 to shift to v > 0:
|
||||
//
|
||||
T k2 = k * k;
|
||||
T N = (k2 - v) / (1 - v);
|
||||
T Nm1 = (1 - k2) / (1 - v);
|
||||
T p2 = sqrt(-v * (k2 - v) / (1 - v));
|
||||
T delta = sqrt(1 - k2 * sphi * sphi);
|
||||
T result = ellint_pi_imp(N, phi, k, Nm1, pol);
|
||||
|
||||
result *= sqrt(Nm1 * (1 - k2 / N));
|
||||
result += ellint_f_imp(phi, k, pol) * k2 / p2;
|
||||
result += atan((p2/2) * sin(2 * phi) / delta);
|
||||
result /= sqrt((1 - v) * (1 - k2 / v));
|
||||
return result;
|
||||
}
|
||||
#if 0 // disabled but retained for future reference: see below.
|
||||
if(v > 1)
|
||||
{
|
||||
//
|
||||
// If v > 1 we can use the identity in A&S 17.7.7/8
|
||||
// to shift to 0 <= v <= 1. Unfortunately this
|
||||
// identity appears only to function correctly when
|
||||
// 0 <= phi <= pi/2, but it's when phi is outside that
|
||||
// range that we really need it: That's when
|
||||
// Carlson's formula fails, and what's more the periodicity
|
||||
// reduction used below on phi doesn't work when v > 1.
|
||||
//
|
||||
// So we're stuck... the code is archived here in case
|
||||
// some bright spart can figure out the fix.
|
||||
//
|
||||
T k2 = k * k;
|
||||
T N = k2 / v;
|
||||
T Nm1 = (v - k2) / v;
|
||||
T p1 = sqrt((-vc) * (1 - k2 / v));
|
||||
T delta = sqrt(1 - k2 * sphi * sphi);
|
||||
//
|
||||
// These next two terms have a large amount of cancellation
|
||||
// so it's not clear if this relation is useable even if
|
||||
// the issues with phi > pi/2 can be fixed:
|
||||
//
|
||||
T result = -ellint_pi_imp(N, phi, k, Nm1);
|
||||
result += ellint_f_imp(phi, k);
|
||||
//
|
||||
// This log term gives the complex result when
|
||||
// n > 1/sin^2(phi)
|
||||
// However that case is dealt with as an error above,
|
||||
// so we should always get a real result here:
|
||||
//
|
||||
result += log((delta + p1 * tan(phi)) / (delta - p1 * tan(phi))) / (2 * p1);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Carlson's algorithm works only for |phi| <= pi/2,
|
||||
// use the integrand's periodicity to normalize phi
|
||||
//
|
||||
// Xiaogang's original code used a cast to long long here
|
||||
// but that fails if T has more digits than a long long,
|
||||
// so rewritten to use fmod instead:
|
||||
//
|
||||
if(fabs(phi) > 1 / tools::epsilon<T>())
|
||||
{
|
||||
if(v > 1)
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol);
|
||||
//
|
||||
// Phi is so large that phi%pi is necessarily zero (or garbage),
|
||||
// just return the second part of the duplication formula:
|
||||
//
|
||||
value = 2 * fabs(phi) * ellint_pi_imp(v, k, vc, pol) / constants::pi<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
T rphi = boost::math::tools::fmod_workaround(fabs(phi), constants::pi<T>() / 2);
|
||||
T m = 2 * (fabs(phi) - rphi) / constants::pi<T>();
|
||||
int sign = 1;
|
||||
if(boost::math::tools::fmod_workaround(m, T(2)) > 0.5)
|
||||
{
|
||||
m += 1;
|
||||
sign = -1;
|
||||
rphi = constants::pi<T>() / 2 - rphi;
|
||||
}
|
||||
|
||||
if((m > 0) && (v > 1))
|
||||
{
|
||||
//
|
||||
// The region with v > 1 and phi outside [0, pi/2] is
|
||||
// currently unsupported:
|
||||
//
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"Got v = %1%, but this is only supported for 0 <= phi <= pi/2", v, pol);
|
||||
}
|
||||
T sinp = sin(rphi);
|
||||
T cosp = cos(rphi);
|
||||
x = cosp * cosp;
|
||||
t = sinp * sinp;
|
||||
y = 1 - k * k * t;
|
||||
z = 1;
|
||||
if(v * t < 0.5)
|
||||
p = 1 - v * t;
|
||||
else
|
||||
p = x + vc * t;
|
||||
value = sign * sinp * (ellint_rf_imp(x, y, z, pol) + v * t * ellint_rj_imp(x, y, z, p, pol) / 3);
|
||||
if(m > 0)
|
||||
value += m * ellint_pi_imp(v, k, vc, pol);
|
||||
}
|
||||
|
||||
if (phi < 0)
|
||||
{
|
||||
value = -value; // odd function
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Complete elliptic integral (Legendre form) of the third kind
|
||||
template <typename T, typename Policy>
|
||||
T ellint_pi_imp(T v, T k, T vc, const Policy& pol)
|
||||
{
|
||||
// Note arg vc = 1-v, possibly without cancellation errors
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::ellint_pi<%1%>(%1%,%1%)";
|
||||
|
||||
if (abs(k) >= 1)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got k = %1%, function requires |k| <= 1", k, pol);
|
||||
}
|
||||
if(vc <= 0)
|
||||
{
|
||||
// Result is complex:
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Got v = %1%, function requires v < 1", v, pol);
|
||||
}
|
||||
|
||||
if(v == 0)
|
||||
{
|
||||
return (k == 0) ? boost::math::constants::pi<T>() / 2 : ellint_k_imp(k, pol);
|
||||
}
|
||||
|
||||
if(v < 0)
|
||||
{
|
||||
T k2 = k * k;
|
||||
T N = (k2 - v) / (1 - v);
|
||||
T Nm1 = (1 - k2) / (1 - v);
|
||||
T p2 = sqrt(-v * (k2 - v) / (1 - v));
|
||||
|
||||
T result = boost::math::detail::ellint_pi_imp(N, k, Nm1, pol);
|
||||
|
||||
result *= sqrt(Nm1 * (1 - k2 / N));
|
||||
result += ellint_k_imp(k, pol) * k2 / p2;
|
||||
result /= sqrt((1 - v) * (1 - k2 / v));
|
||||
return result;
|
||||
}
|
||||
|
||||
T x = 0;
|
||||
T y = 1 - k * k;
|
||||
T z = 1;
|
||||
T p = vc;
|
||||
T value = ellint_rf_imp(x, y, z, pol) + v * ellint_rj_imp(x, y, z, p, pol) / 3;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const mpl::false_&)
|
||||
{
|
||||
return boost::math::ellint_3(k, v, phi, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v, const Policy& pol, const mpl::true_&)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(
|
||||
detail::ellint_pi_imp(
|
||||
static_cast<value_type>(v),
|
||||
static_cast<value_type>(k),
|
||||
static_cast<value_type>(1-v),
|
||||
pol), "boost::math::ellint_3<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(
|
||||
detail::ellint_pi_imp(
|
||||
static_cast<value_type>(v),
|
||||
static_cast<value_type>(phi),
|
||||
static_cast<value_type>(k),
|
||||
static_cast<value_type>(1-v),
|
||||
pol), "boost::math::ellint_3<%1%>(%1%,%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi)
|
||||
{
|
||||
typedef typename policies::is_policy<T3>::type tag_type;
|
||||
return detail::ellint_3(k, v, phi, tag_type());
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v)
|
||||
{
|
||||
return ellint_3(k, v, policies::policy<>());
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_ELLINT_3_HPP
|
||||
110
include/boost/math/special_functions/ellint_rc.hpp
Normal file
110
include/boost/math/special_functions/ellint_rc.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// History:
|
||||
// XZ wrote the original of this file as part of the Google
|
||||
// Summer of Code 2006. JM modified it to fit into the
|
||||
// Boost.Math conceptual framework better, and to correctly
|
||||
// handle the y < 0 case.
|
||||
//
|
||||
|
||||
#ifndef BOOST_MATH_ELLINT_RC_HPP
|
||||
#define BOOST_MATH_ELLINT_RC_HPP
|
||||
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
// Carlson's degenerate elliptic integral
|
||||
// R_C(x, y) = R_F(x, y, y) = 0.5 * \int_{0}^{\infty} (t+x)^{-1/2} (t+y)^{-1} dt
|
||||
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T ellint_rc_imp(T x, T y, const Policy& pol)
|
||||
{
|
||||
T value, S, u, lambda, tolerance, prefix;
|
||||
unsigned long k;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::ellint_rc<%1%>(%1%,%1%)";
|
||||
|
||||
if(x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument x must be non-negative but got %1%", x, pol);
|
||||
}
|
||||
if(y == 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument y must not be zero but got %1%", y, pol);
|
||||
}
|
||||
|
||||
// error scales as the 6th power of tolerance
|
||||
tolerance = pow(4 * tools::epsilon<T>(), T(1) / 6);
|
||||
|
||||
// for y < 0, the integral is singular, return Cauchy principal value
|
||||
if (y < 0)
|
||||
{
|
||||
prefix = sqrt(x / (x - y));
|
||||
x = x - y;
|
||||
y = -y;
|
||||
}
|
||||
else
|
||||
prefix = 1;
|
||||
|
||||
// duplication:
|
||||
k = 1;
|
||||
do
|
||||
{
|
||||
u = (x + y + y) / 3;
|
||||
S = y / u - 1; // 1 - x / u = 2 * S
|
||||
|
||||
if (2 * abs(S) < tolerance)
|
||||
break;
|
||||
|
||||
T sx = sqrt(x);
|
||||
T sy = sqrt(y);
|
||||
lambda = 2 * sx * sy + y;
|
||||
x = (x + lambda) / 4;
|
||||
y = (y + lambda) / 4;
|
||||
++k;
|
||||
}while(k < policies::get_max_series_iterations<Policy>());
|
||||
// Check to see if we gave up too soon:
|
||||
policies::check_series_iterations(function, k, pol);
|
||||
|
||||
// Taylor series expansion to the 5th order
|
||||
value = (1 + S * S * (T(3) / 10 + S * (T(1) / 7 + S * (T(3) / 8 + S * T(9) / 22)))) / sqrt(u);
|
||||
|
||||
return value * prefix;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
ellint_rc(T1 x, T2 y, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(
|
||||
detail::ellint_rc_imp(
|
||||
static_cast<value_type>(x),
|
||||
static_cast<value_type>(y), pol), "boost::math::ellint_rc<%1%>(%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
ellint_rc(T1 x, T2 y)
|
||||
{
|
||||
return ellint_rc(x, y, policies::policy<>());
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_ELLINT_RC_HPP
|
||||
125
include/boost/math/special_functions/ellint_rd.hpp
Normal file
125
include/boost/math/special_functions/ellint_rd.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// History:
|
||||
// XZ wrote the original of this file as part of the Google
|
||||
// Summer of Code 2006. JM modified it slightly to fit into the
|
||||
// Boost.Math conceptual framework better.
|
||||
|
||||
#ifndef BOOST_MATH_ELLINT_RD_HPP
|
||||
#define BOOST_MATH_ELLINT_RD_HPP
|
||||
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
// Carlson's elliptic integral of the second kind
|
||||
// R_D(x, y, z) = R_J(x, y, z, z) = 1.5 * \int_{0}^{\infty} [(t+x)(t+y)]^{-1/2} (t+z)^{-3/2} dt
|
||||
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T ellint_rd_imp(T x, T y, T z, const Policy& pol)
|
||||
{
|
||||
T value, u, lambda, sigma, factor, tolerance;
|
||||
T X, Y, Z, EA, EB, EC, ED, EE, S1, S2;
|
||||
unsigned long k;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)";
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument x must be >= 0, but got %1%", x, pol);
|
||||
}
|
||||
if (y < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument y must be >= 0, but got %1%", y, pol);
|
||||
}
|
||||
if (z <= 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument z must be > 0, but got %1%", z, pol);
|
||||
}
|
||||
if (x + y == 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"At most one argument can be zero, but got, x + y = %1%", x+y, pol);
|
||||
}
|
||||
|
||||
// error scales as the 6th power of tolerance
|
||||
tolerance = pow(tools::epsilon<T>() / 3, T(1)/6);
|
||||
|
||||
// duplication
|
||||
sigma = 0;
|
||||
factor = 1;
|
||||
k = 1;
|
||||
do
|
||||
{
|
||||
u = (x + y + z + z + z) / 5;
|
||||
X = (u - x) / u;
|
||||
Y = (u - y) / u;
|
||||
Z = (u - z) / u;
|
||||
if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
|
||||
break;
|
||||
T sx = sqrt(x);
|
||||
T sy = sqrt(y);
|
||||
T sz = sqrt(z);
|
||||
lambda = sy * (sx + sz) + sz * sx; //sqrt(x * y) + sqrt(y * z) + sqrt(z * x);
|
||||
sigma += factor / (sz * (z + lambda));
|
||||
factor /= 4;
|
||||
x = (x + lambda) / 4;
|
||||
y = (y + lambda) / 4;
|
||||
z = (z + lambda) / 4;
|
||||
++k;
|
||||
}
|
||||
while(k < policies::get_max_series_iterations<Policy>());
|
||||
|
||||
// Check to see if we gave up too soon:
|
||||
policies::check_series_iterations(function, k, pol);
|
||||
|
||||
// Taylor series expansion to the 5th order
|
||||
EA = X * Y;
|
||||
EB = Z * Z;
|
||||
EC = EA - EB;
|
||||
ED = EA - 6 * EB;
|
||||
EE = ED + EC + EC;
|
||||
S1 = ED * (ED * T(9) / 88 - Z * EE * T(9) / 52 - T(3) / 14);
|
||||
S2 = Z * (EE / 6 + Z * (-EC * T(9) / 22 + Z * EA * T(3) / 26));
|
||||
value = 3 * sigma + factor * (1 + S1 + S2) / (u * sqrt(u));
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rd(T1 x, T2 y, T3 z, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(
|
||||
detail::ellint_rd_imp(
|
||||
static_cast<value_type>(x),
|
||||
static_cast<value_type>(y),
|
||||
static_cast<value_type>(z), pol), "boost::math::ellint_rd<%1%>(%1%,%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rd(T1 x, T2 y, T3 z)
|
||||
{
|
||||
return ellint_rd(x, y, z, policies::policy<>());
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_ELLINT_RD_HPP
|
||||
127
include/boost/math/special_functions/ellint_rf.hpp
Normal file
127
include/boost/math/special_functions/ellint_rf.hpp
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// History:
|
||||
// XZ wrote the original of this file as part of the Google
|
||||
// Summer of Code 2006. JM modified it to fit into the
|
||||
// Boost.Math conceptual framework better, and to handle
|
||||
// types longer than 80-bit reals.
|
||||
//
|
||||
#ifndef BOOST_MATH_ELLINT_RF_HPP
|
||||
#define BOOST_MATH_ELLINT_RF_HPP
|
||||
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
// Carlson's elliptic integral of the first kind
|
||||
// R_F(x, y, z) = 0.5 * \int_{0}^{\infty} [(t+x)(t+y)(t+z)]^{-1/2} dt
|
||||
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T ellint_rf_imp(T x, T y, T z, const Policy& pol)
|
||||
{
|
||||
T value, X, Y, Z, E2, E3, u, lambda, tolerance;
|
||||
unsigned long k;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)";
|
||||
|
||||
if (x < 0 || y < 0 || z < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"domain error, all arguments must be non-negative, "
|
||||
"only sensible result is %1%.",
|
||||
std::numeric_limits<T>::quiet_NaN(), pol);
|
||||
}
|
||||
if (x + y == 0 || y + z == 0 || z + x == 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"domain error, at most one argument can be zero, "
|
||||
"only sensible result is %1%.",
|
||||
std::numeric_limits<T>::quiet_NaN(), pol);
|
||||
}
|
||||
|
||||
// Carlson scales error as the 6th power of tolerance,
|
||||
// but this seems not to work for types larger than
|
||||
// 80-bit reals, this heuristic seems to work OK:
|
||||
if(policies::digits<T, Policy>() > 64)
|
||||
{
|
||||
tolerance = pow(tools::epsilon<T>(), T(1)/4.25f);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
|
||||
}
|
||||
else
|
||||
{
|
||||
tolerance = pow(4*tools::epsilon<T>(), T(1)/6);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(tolerance);
|
||||
}
|
||||
|
||||
// duplication
|
||||
k = 1;
|
||||
do
|
||||
{
|
||||
u = (x + y + z) / 3;
|
||||
X = (u - x) / u;
|
||||
Y = (u - y) / u;
|
||||
Z = (u - z) / u;
|
||||
|
||||
// Termination condition:
|
||||
if ((tools::max)(abs(X), abs(Y), abs(Z)) < tolerance)
|
||||
break;
|
||||
|
||||
T sx = sqrt(x);
|
||||
T sy = sqrt(y);
|
||||
T sz = sqrt(z);
|
||||
lambda = sy * (sx + sz) + sz * sx;
|
||||
x = (x + lambda) / 4;
|
||||
y = (y + lambda) / 4;
|
||||
z = (z + lambda) / 4;
|
||||
++k;
|
||||
}
|
||||
while(k < policies::get_max_series_iterations<Policy>());
|
||||
|
||||
// Check to see if we gave up too soon:
|
||||
policies::check_series_iterations(function, k, pol);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(k);
|
||||
|
||||
// Taylor series expansion to the 5th order
|
||||
E2 = X * Y - Z * Z;
|
||||
E3 = X * Y * Z;
|
||||
value = (1 + E2*(E2/24 - E3*T(3)/44 - T(0.1)) + E3/14) / sqrt(u);
|
||||
BOOST_MATH_INSTRUMENT_VARIABLE(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rf(T1 x, T2 y, T3 z, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(
|
||||
detail::ellint_rf_imp(
|
||||
static_cast<value_type>(x),
|
||||
static_cast<value_type>(y),
|
||||
static_cast<value_type>(z), pol), "boost::math::ellint_rf<%1%>(%1%,%1%,%1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rf(T1 x, T2 y, T3 z)
|
||||
{
|
||||
return ellint_rf(x, y, z, policies::policy<>());
|
||||
}
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif // BOOST_MATH_ELLINT_RF_HPP
|
||||
174
include/boost/math/special_functions/ellint_rj.hpp
Normal file
174
include/boost/math/special_functions/ellint_rj.hpp
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright (c) 2006 Xiaogang Zhang
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// History:
|
||||
// XZ wrote the original of this file as part of the Google
|
||||
// Summer of Code 2006. JM modified it to fit into the
|
||||
// Boost.Math conceptual framework better, and to correctly
|
||||
// handle the p < 0 case.
|
||||
//
|
||||
|
||||
#ifndef BOOST_MATH_ELLINT_RJ_HPP
|
||||
#define BOOST_MATH_ELLINT_RJ_HPP
|
||||
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/special_functions/ellint_rc.hpp>
|
||||
|
||||
// Carlson's elliptic integral of the third kind
|
||||
// R_J(x, y, z, p) = 1.5 * \int_{0}^{\infty} (t+p)^{-1} [(t+x)(t+y)(t+z)]^{-1/2} dt
|
||||
// Carlson, Numerische Mathematik, vol 33, 1 (1979)
|
||||
|
||||
namespace boost { namespace math { namespace detail{
|
||||
|
||||
template <typename T, typename Policy>
|
||||
T ellint_rj_imp(T x, T y, T z, T p, const Policy& pol)
|
||||
{
|
||||
T value, u, lambda, alpha, beta, sigma, factor, tolerance;
|
||||
T X, Y, Z, P, EA, EB, EC, E2, E3, S1, S2, S3;
|
||||
unsigned long k;
|
||||
|
||||
BOOST_MATH_STD_USING
|
||||
using namespace boost::math::tools;
|
||||
|
||||
static const char* function = "boost::math::ellint_rj<%1%>(%1%,%1%,%1%)";
|
||||
|
||||
if (x < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument x must be non-negative, but got x = %1%", x, pol);
|
||||
}
|
||||
if(y < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument y must be non-negative, but got y = %1%", y, pol);
|
||||
}
|
||||
if(z < 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument z must be non-negative, but got z = %1%", z, pol);
|
||||
}
|
||||
if(p == 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"Argument p must not be zero, but got p = %1%", p, pol);
|
||||
}
|
||||
if (x + y == 0 || y + z == 0 || z + x == 0)
|
||||
{
|
||||
return policies::raise_domain_error<T>(function,
|
||||
"At most one argument can be zero, "
|
||||
"only possible result is %1%.", std::numeric_limits<T>::quiet_NaN(), pol);
|
||||
}
|
||||
|
||||
// error scales as the 6th power of tolerance
|
||||
tolerance = pow(T(1) * tools::epsilon<T>() / 3, T(1) / 6);
|
||||
|
||||
// for p < 0, the integral is singular, return Cauchy principal value
|
||||
if (p < 0)
|
||||
{
|
||||
//
|
||||
// We must ensure that (z - y) * (y - x) is positive.
|
||||
// Since the integral is symmetrical in x, y and z
|
||||
// we can just permute the values:
|
||||
//
|
||||
if(x > y)
|
||||
std::swap(x, y);
|
||||
if(y > z)
|
||||
std::swap(y, z);
|
||||
if(x > y)
|
||||
std::swap(x, y);
|
||||
|
||||
T q = -p;
|
||||
T pmy = (z - y) * (y - x) / (y + q); // p - y
|
||||
|
||||
BOOST_ASSERT(pmy >= 0);
|
||||
|
||||
T p = pmy + y;
|
||||
value = 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
|
||||
858
include/boost/math/special_functions/erf.hpp
Normal file
858
include/boost/math/special_functions/erf.hpp
Normal file
@@ -0,0 +1,858 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_ERF_HPP
|
||||
#define BOOST_MATH_SPECIAL_ERF_HPP
|
||||
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/special_functions/gamma.hpp>
|
||||
#include <boost/math/tools/roots.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
//
|
||||
// Asymptotic series for large z:
|
||||
//
|
||||
template <class T>
|
||||
struct erf_asympt_series_t
|
||||
{
|
||||
erf_asympt_series_t(T z) : xx(2 * -z * z), tk(1)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
result = -exp(-z * z) / sqrt(boost::math::constants::pi<T>());
|
||||
result /= z;
|
||||
}
|
||||
|
||||
typedef T result_type;
|
||||
|
||||
T operator()()
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
T r = result;
|
||||
result *= tk / xx;
|
||||
tk += 2;
|
||||
if( fabs(r) < fabs(result))
|
||||
result = 0;
|
||||
return r;
|
||||
}
|
||||
private:
|
||||
T result;
|
||||
T xx;
|
||||
int tk;
|
||||
};
|
||||
//
|
||||
// How large z has to be in order to ensure that the series converges:
|
||||
//
|
||||
template <class T>
|
||||
inline float erf_asymptotic_limit_N(const T&)
|
||||
{
|
||||
return (std::numeric_limits<float>::max)();
|
||||
}
|
||||
inline float erf_asymptotic_limit_N(const mpl::int_<24>&)
|
||||
{
|
||||
return 2.8F;
|
||||
}
|
||||
inline float erf_asymptotic_limit_N(const mpl::int_<53>&)
|
||||
{
|
||||
return 4.3F;
|
||||
}
|
||||
inline float erf_asymptotic_limit_N(const mpl::int_<64>&)
|
||||
{
|
||||
return 4.8F;
|
||||
}
|
||||
inline float erf_asymptotic_limit_N(const mpl::int_<106>&)
|
||||
{
|
||||
return 6.5F;
|
||||
}
|
||||
inline float erf_asymptotic_limit_N(const mpl::int_<113>&)
|
||||
{
|
||||
return 6.8F;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T erf_asymptotic_limit()
|
||||
{
|
||||
typedef typename policies::precision<T, Policy>::type precision_type;
|
||||
typedef typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<24> >,
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<0> >,
|
||||
mpl::int_<0>,
|
||||
mpl::int_<24>
|
||||
>::type,
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<53> >,
|
||||
mpl::int_<53>,
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<64> >,
|
||||
mpl::int_<64>,
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<106> >,
|
||||
mpl::int_<106>,
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<113> >,
|
||||
mpl::int_<113>,
|
||||
mpl::int_<0>
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
return erf_asymptotic_limit_N(tag_type());
|
||||
}
|
||||
|
||||
template <class T, class Policy, class Tag>
|
||||
T erf_imp(T z, bool invert, const Policy& pol, const Tag& t)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("Generic erf_imp called");
|
||||
|
||||
if(z < 0)
|
||||
{
|
||||
if(!invert)
|
||||
return -erf_imp(-z, invert, pol, t);
|
||||
else
|
||||
return 1 + erf_imp(-z, false, pol, t);
|
||||
}
|
||||
|
||||
T result;
|
||||
|
||||
if(!invert && (z > detail::erf_asymptotic_limit<T, Policy>()))
|
||||
{
|
||||
detail::erf_asympt_series_t<T> s(z);
|
||||
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
||||
result = boost::math::tools::sum_series(s, policies::digits<T, Policy>(), max_iter, 1);
|
||||
policies::check_series_iterations("boost::math::erf<%1%>(%1%, %1%)", max_iter, pol);
|
||||
}
|
||||
else
|
||||
{
|
||||
T x = z * z;
|
||||
if(x < 0.6)
|
||||
{
|
||||
// Compute P:
|
||||
result = z * exp(-x);
|
||||
result /= sqrt(boost::math::constants::pi<T>());
|
||||
if(result != 0)
|
||||
result *= 2 * detail::lower_gamma_series(T(0.5f), x, pol);
|
||||
}
|
||||
else if(x < 1.1f)
|
||||
{
|
||||
// Compute Q:
|
||||
invert = !invert;
|
||||
result = tgamma_small_upper_part(T(0.5f), x, pol);
|
||||
result /= sqrt(boost::math::constants::pi<T>());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute Q:
|
||||
invert = !invert;
|
||||
result = z * exp(-x);
|
||||
result /= sqrt(boost::math::constants::pi<T>());
|
||||
result *= upper_gamma_fraction(T(0.5f), x, policies::digits<T, Policy>());
|
||||
}
|
||||
}
|
||||
if(invert)
|
||||
result = 1 - result;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<53>& t)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("53-bit precision erf_imp called");
|
||||
|
||||
if(z < 0)
|
||||
{
|
||||
if(!invert)
|
||||
return -erf_imp(-z, invert, pol, t);
|
||||
else if(z < -0.5)
|
||||
return 2 - erf_imp(-z, invert, pol, t);
|
||||
else
|
||||
return 1 + erf_imp(-z, false, pol, t);
|
||||
}
|
||||
|
||||
T result;
|
||||
|
||||
//
|
||||
// Big bunch of selection statements now to pick
|
||||
// which implementation to use,
|
||||
// try to put most likely options first:
|
||||
//
|
||||
if(z < 0.5)
|
||||
{
|
||||
//
|
||||
// We're going to calculate erf:
|
||||
//
|
||||
if(z == 0)
|
||||
{
|
||||
result = T(0);
|
||||
}
|
||||
else if(z < 1e-10)
|
||||
{
|
||||
result = static_cast<T>(z * 1.125f + z * 0.003379167095512573896158903121545171688L);
|
||||
}
|
||||
else
|
||||
{
|
||||
static const T n[7] = { 0.00337916709551257778174L, -0.000147024115786688745475L, -0.37463022236812520164L, 0.0163061594494816999803L, -0.0534354147807331748737L, 0.00161898096813581982844L, -0.0059528010489182840404L };
|
||||
static const T d[7] = { 1, -0.0435089806536379531594L, 0.442761965043509204727L, -0.017375974533016704678L, 0.0772756490303260060769L, -0.00210552465858669941879L, 0.00544772980263244037286L };
|
||||
result = static_cast<T>(z * 1.125f + z * tools::evaluate_polynomial(n, z) / tools::evaluate_polynomial(d, z));
|
||||
}
|
||||
}
|
||||
else if((z < 14) || ((z < 28) && invert))
|
||||
{
|
||||
//
|
||||
// We'll be calculating erfc:
|
||||
//
|
||||
invert = !invert;
|
||||
T r, b;
|
||||
if(z < 0.75)
|
||||
{
|
||||
// Worst case absolute error found: 8.554649561e-018
|
||||
static const T n[5] = { -0.0361790390718262468222L, 0.301888464724047222196L, 0.201731143672633894981L, 0.0659353268087389983319L, 0.00721876720062364930761L };
|
||||
static const T d[6] = { 1, 1.58814245739127341535L, 0.99354580430196422336L, 0.291753007176902027213L, 0.033994791234913855515L, -0.000104234653166533504303L };
|
||||
static const float f0 = 0.3440242112F;
|
||||
r = tools::evaluate_polynomial(n, z - 0.5) / tools::evaluate_polynomial(d, z - 0.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 1.25)
|
||||
{
|
||||
// Worst case absolute error found: 6.50251514e-018
|
||||
static const T n[6] = { -0.039787689261113685983L, 0.160309168830518003303L, 0.163049978514596540313L, 0.0710685660158400750009L, 0.01497188097404877543L, 0.00130080628375002584279L };
|
||||
static const T d[6] = { 1, 1.77564880074171280407L, 1.31438791181040008779L, 0.509359151038517059748L, 0.103958527905812829559L, 0.00901292460643094469406L };
|
||||
static const float f0 = 0.419990927F;
|
||||
r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 2.25)
|
||||
{
|
||||
// Worst case absolute error found: 1.132743504e-017
|
||||
static const T n[6] = { -0.0300838560557949724172L, 0.0592886319615167248092L, 0.0622294724048409148736L, 0.0248575228109427909578L, 0.00463781847004901844581L, 0.000347305179334822548368L };
|
||||
static const T d[7] = { 1, 1.57915060645728571344L, 1.03342495188878679417L, 0.35158678814344218974L, 0.062469256580984456783L, 0.00466640448020624599948L, 0.290106403940303572448e-6L };
|
||||
static const float f0 = 0.4898625016F;
|
||||
r = tools::evaluate_polynomial(n, z - 1.25) / tools::evaluate_polynomial(d, z - 1.25);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 3.5)
|
||||
{
|
||||
// Worst case absolute error found: 3.446364609e-018
|
||||
static const T n[6] = { -0.0117907570137227857015L, 0.0162667227692515660221L, 0.0175329212378413544794L, 0.00620897681269247137578L, 0.000986614895094589251706L, 0.601354618401624353425e-4L };
|
||||
static const T d[6] = { 1, 1.33374851361555383557L, 0.73227756904205983415L, 0.207410266363727673685L, 0.0304034048466731110163L, 0.00185296959991832048613L };
|
||||
static const float f0 = 0.5317370892F;
|
||||
r = tools::evaluate_polynomial(n, z - 2.25) / tools::evaluate_polynomial(d, z - 2.25);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 5.5)
|
||||
{
|
||||
// Worst case absolute error found: 1.579588208e-018
|
||||
static const T n[6] = { -0.00588219091116732271979L, 0.00434428684527812140098L, 0.00466899990542371512895L, 0.00139937567253199794533L, 0.000179205902444982389766L, 0.845033527560949509345e-5L };
|
||||
static const T d[6] = { 1, 1.07389345953392962127L, 0.470965611895885060643L, 0.105594730223366124873L, 0.0121252833787344059719L, 0.000571755036133730341579L };
|
||||
static const float f0 = 0.5494099855F;
|
||||
r = tools::evaluate_polynomial(n, z - 3.5) / tools::evaluate_polynomial(d, z - 3.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 9)
|
||||
{
|
||||
// Worst case absolute error found: 1.410768708e-017
|
||||
static const T n[5] = { -0.00273864253749621265032L, 0.0013089921066773026803L, 0.000775841526778089659703L, 0.000110909476102006410909L, 0.472577590124068298534e-5L };
|
||||
static const T d[6] = { 1, 0.650694792327863647878L, 0.161126734432670927888L, 0.0180081468446110640846L, 0.000767341359508884026192L, -0.287636719206664167616e-9L };
|
||||
static const float f0 = 0.5580308437F;
|
||||
r = tools::evaluate_polynomial(n, z - 5.5) / tools::evaluate_polynomial(d, z - 5.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 14)
|
||||
{
|
||||
// Worst case absolute error found: 1.458310511e-018
|
||||
static const T n[5] = { -0.000995856413171151859346L, 0.000320252910249376187643L, 0.000129085624923151780987L, 0.121577881306587454509e-4L, 0.33293110334156470348e-6L };
|
||||
static const T d[5] = { 1, 0.428034987547594828954L, 0.0692297359775940896439L, 0.00501515176145997560701L, 0.00013733589151338416322L };
|
||||
static const float f0 = 0.5617653728F;
|
||||
r = tools::evaluate_polynomial(n, z - 9) / tools::evaluate_polynomial(d, z - 9);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 21)
|
||||
{
|
||||
// Worst case absolute error found: 1.08182873e-019
|
||||
static const T n[5] = { -0.000395463268432048215535L, 0.91155953112698182321e-4L, 0.237451641259281193813e-4L, 0.145759953022524466816e-5L, 0.259395907606548998142e-7L };
|
||||
static const T d[5] = { 1, 0.281604524251560309285L, 0.0298468482900092392397L, 0.00141114575715338885136L, 0.251128951158576064819e-4L };
|
||||
static const float f0 = 0.5631566644F;
|
||||
r = tools::evaluate_polynomial(n, z - 14) / tools::evaluate_polynomial(d, z - 14);
|
||||
b = f0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Worst case absolute error found: 7.010370259e-018
|
||||
static const T n[4] = { -0.000139182098873874523526L, 0.395254617101737287826e-4L, 0.376801239136290345387e-5L, 0.629017242098850415839e-7L };
|
||||
static const T d[4] = { 1, 0.15077096006891495258L, 0.00756136203065884121997L, 0.000126226197336507576933L };
|
||||
static const float f0 = 0.5636912584F;
|
||||
r = tools::evaluate_polynomial(n, z - 21) / tools::evaluate_polynomial(d, z - 21);
|
||||
b = f0;
|
||||
}
|
||||
T g = exp(-z * z) / z;
|
||||
result = g * b + g * r;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Any value of z larger than 28 will underflow to zero:
|
||||
//
|
||||
result = 0;
|
||||
invert = !invert;
|
||||
}
|
||||
|
||||
if(invert)
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
|
||||
return result;
|
||||
} // template <class T, class L>T erf_imp(T z, bool invert, const L& l, const mpl::int_<53>& t)
|
||||
|
||||
|
||||
template <class T, class Policy>
|
||||
T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<64>& t)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("64-bit precision erf_imp called");
|
||||
|
||||
if(z < 0)
|
||||
{
|
||||
if(!invert)
|
||||
return -erf_imp(-z, invert, pol, t);
|
||||
else if(z < -0.5)
|
||||
return 2 - erf_imp(-z, invert, pol, t);
|
||||
else
|
||||
return 1 + erf_imp(-z, false, pol, t);
|
||||
}
|
||||
|
||||
T result;
|
||||
|
||||
//
|
||||
// Big bunch of selection statements now to pick which
|
||||
// implementation to use, try to put most likely options
|
||||
// first:
|
||||
//
|
||||
if(z < 0.5)
|
||||
{
|
||||
//
|
||||
// We're going to calculate erf:
|
||||
//
|
||||
if(z == 0)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
else if(z < 1e-10)
|
||||
{
|
||||
result = z * 1.125 + z * 0.003379167095512573896158903121545171688L;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Worst case absolute error found: 6.688618532e-21
|
||||
static const T n[8] = { 0.00337916709551257388990745L, -0.00073695653048167948530905L, -0.374732337392919607868241L, 0.0817442448733587196071743L, -0.0421089319936548595203468L, 0.0070165709512095756344528L, -0.00495091255982435110337458L, 0.000871646599037922480317225L };
|
||||
static const T d[8] = { 1L, -0.218088218087924645390535L, 0.412542972725442099083918L, -0.0841891147873106755410271L, 0.0655338856400241519690695L, -0.0120019604454941768171266L, 0.00408165558926174048329689L, -0.000615900721557769691924509L };
|
||||
result = z * 1.125 + z * tools::evaluate_polynomial(n, z) / tools::evaluate_polynomial(d, z);
|
||||
}
|
||||
}
|
||||
else if((z < 110) || ((z < 110) && invert)) // TODO FIXME!!!
|
||||
{
|
||||
//
|
||||
// We'll be calculating erfc:
|
||||
//
|
||||
invert = !invert;
|
||||
T r, b;
|
||||
if(z < 0.75)
|
||||
{
|
||||
// Worst case absolute error found: 5.582813374e-21
|
||||
static const T n[6] = { -0.0361790390718262471360258L, 0.292251883444882683221149L, 0.281447041797604512774415L, 0.125610208862766947294894L, 0.0274135028268930549240776L, 0.00250839672168065762786937L };
|
||||
static const T d[6] = { 1L, 1.8545005897903486499845L, 1.43575803037831418074962L, 0.582827658753036572454135L, 0.124810476932949746447682L, 0.0113724176546353285778481L };
|
||||
static const float f0 = 0.3440242112F;
|
||||
r = tools::evaluate_polynomial(n, z - 0.5) / tools::evaluate_polynomial(d, z - 0.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 1.25)
|
||||
{
|
||||
// Worst case absolute error found: 4.01854729e-21
|
||||
static const T n[7] = { -0.0397876892611136856954425L, 0.153165212467878293257683L, 0.191260295600936245503129L, 0.10276327061989304213645L, 0.029637090615738836726027L, 0.0046093486780275489468812L, 0.000307607820348680180548455L };
|
||||
static const T d[7] = { 1L, 1.95520072987627704987886L, 1.64762317199384860109595L, 0.768238607022126250082483L, 0.209793185936509782784315L, 0.0319569316899913392596356L, 0.00213363160895785378615014L };
|
||||
static const float f0 = 0.419990927F;
|
||||
r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 2.25)
|
||||
{
|
||||
// Worst case absolute error found: 2.866005373e-21
|
||||
static const T n[7] = { -0.0300838560557949717328341L, 0.0538578829844454508530552L, 0.0726211541651914182692959L, 0.0367628469888049348429018L, 0.00964629015572527529605267L, 0.00133453480075291076745275L, 0.778087599782504251917881e-4L };
|
||||
static const T d[8] = { 1L, 1.75967098147167528287343L, 1.32883571437961120556307L, 0.552528596508757581287907L, 0.133793056941332861912279L, 0.0179509645176280768640766L, 0.00104712440019937356634038L, -0.106640381820357337177643e-7L };
|
||||
static const float f0 = 0.4898625016F;
|
||||
r = tools::evaluate_polynomial(n, z - 1.25) / tools::evaluate_polynomial(d, z - 1.25);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 3.5)
|
||||
{
|
||||
// Worst case absolute error found: 1.045355789e-21
|
||||
static const T n[7] = { -0.0117907570137227847827732L, 0.014262132090538809896674L, 0.0202234435902960820020765L, 0.00930668299990432009042239L, 0.00213357802422065994322516L, 0.00025022987386460102395382L, 0.120534912219588189822126e-4L };
|
||||
static const T d[7] = { 1L, 1.50376225203620482047419L, 0.965397786204462896346934L, 0.339265230476796681555511L, 0.0689740649541569716897427L, 0.00771060262491768307365526L, 0.000371421101531069302990367L };
|
||||
static const float f0 = 0.5317370892F;
|
||||
r = tools::evaluate_polynomial(n, z - 2.25) / tools::evaluate_polynomial(d, z - 2.25);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 5.25)
|
||||
{
|
||||
// Worst case absolute error found: 8.300028706e-22
|
||||
static const T n[7] = { -0.00546954795538729307482955L, 0.00404190278731707110245394L, 0.0054963369553161170521356L, 0.00212616472603945399437862L, 0.000394984014495083900689956L, 0.365565477064442377259271e-4L, 0.135485897109932323253786e-5L };
|
||||
static const T d[8] = { 1L, 1.21019697773630784832251L, 0.620914668221143886601045L, 0.173038430661142762569515L, 0.0276550813773432047594539L, 0.00240625974424309709745382L, 0.891811817251336577241006e-4L, -0.465528836283382684461025e-11L };
|
||||
static const float f0 = 0.5489973426F;
|
||||
r = tools::evaluate_polynomial(n, z - 3.5) / tools::evaluate_polynomial(d, z - 3.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 8)
|
||||
{
|
||||
// Worst case absolute error found: 1.700157534e-21
|
||||
static const T n[6] = { -0.00270722535905778347999196L, 0.0013187563425029400461378L, 0.00119925933261002333923989L, 0.00027849619811344664248235L, 0.267822988218331849989363e-4L, 0.923043672315028197865066e-6L };
|
||||
static const T d[7] = { 1L, 0.814632808543141591118279L, 0.268901665856299542168425L, 0.0449877216103041118694989L, 0.00381759663320248459168994L, 0.000131571897888596914350697L, 0.404815359675764138445257e-11L };
|
||||
static const float f0 = 0.5571740866F;
|
||||
r = tools::evaluate_polynomial(n, z - 5.25) / tools::evaluate_polynomial(d, z - 5.25);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 11.5)
|
||||
{
|
||||
//Worst case absolute error found: 3.002278011e-22
|
||||
static const T n[6] = { -0.00109946720691742196814323L, 0.000406425442750422675169153L, 0.000274499489416900707787024L, 0.465293770646659383436343e-4L, 0.320955425395767463401993e-5L, 0.778286018145020892261936e-7L };
|
||||
static const T d[6] = { 1L, 0.588173710611846046373373L, 0.139363331289409746077541L, 0.0166329340417083678763028L, 0.00100023921310234908642639L, 0.24254837521587225125068e-4L };
|
||||
static const float f0 = 0.5609807968F;
|
||||
r = tools::evaluate_polynomial(n, z - 8) / tools::evaluate_polynomial(d, z - 8);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 17)
|
||||
{
|
||||
//Worst case absolute error found: 6.741114695e-21
|
||||
static const T n[5] = { -0.00056907993601094962855594L, 0.000169498540373762264416984L, 0.518472354581100890120501e-4L, 0.382819312231928859704678e-5L, 0.824989931281894431781794e-7L };
|
||||
static const T d[6] = { 1L, 0.339637250051139347430323L, 0.043472647870310663055044L, 0.00248549335224637114641629L, 0.535633305337152900549536e-4L, -0.117490944405459578783846e-12L };
|
||||
static const float f0 = 0.5626493692F;
|
||||
r = tools::evaluate_polynomial(n, z - 11.5) / tools::evaluate_polynomial(d, z - 11.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 24)
|
||||
{
|
||||
// Worst case absolute error found: 7.802346984e-22
|
||||
static const T n[5] = { -0.000241313599483991337479091L, 0.574224975202501512365975e-4L, 0.115998962927383778460557e-4L, 0.581762134402593739370875e-6L, 0.853971555085673614607418e-8L };
|
||||
static const T d[5] = { 1L, 0.233044138299687841018015L, 0.0204186940546440312625597L, 0.000797185647564398289151125L, 0.117019281670172327758019e-4L };
|
||||
static const float f0 = 0.5634598136F;
|
||||
r = tools::evaluate_polynomial(n, z - 17) / tools::evaluate_polynomial(d, z - 17);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 38)
|
||||
{
|
||||
// Worst case absolute error found: 2.414228989e-22
|
||||
static const T n[5] = { -0.000146674699277760365803642L, 0.162666552112280519955647e-4L, 0.269116248509165239294897e-5L, 0.979584479468091935086972e-7L, 0.101994647625723465722285e-8L };
|
||||
static const T d[5] = { 1L, 0.165907812944847226546036L, 0.0103361716191505884359634L, 0.000286593026373868366935721L, 0.298401570840900340874568e-5L };
|
||||
static const float f0 = 0.5638477802F;
|
||||
r = tools::evaluate_polynomial(n, z - 24) / tools::evaluate_polynomial(d, z - 24);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 60)
|
||||
{
|
||||
// Worst case absolute error found: 5.896543869e-24
|
||||
static const T n[5] = { -0.583905797629771786720406e-4L, 0.412510325105496173512992e-5L, 0.431790922420250949096906e-6L, 0.993365155590013193345569e-8L, 0.653480510020104699270084e-10L };
|
||||
static const T d[5] = { 1L, 0.105077086072039915406159L, 0.00414278428675475620830226L, 0.726338754644523769144108e-4L, 0.477818471047398785369849e-6L };
|
||||
static const float f0 = 0.5640528202F;
|
||||
r = tools::evaluate_polynomial(n, z - 38) / tools::evaluate_polynomial(d, z - 38);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 85)
|
||||
{
|
||||
// Worst case absolute error found: 3.080612264e-21
|
||||
static const T n[4] = { -0.196457797609229579459841e-4L, 0.157243887666800692441195e-5L, 0.543902511192700878690335e-7L, 0.317472492369117710852685e-9L };
|
||||
static const T d[5] = { 1L, 0.052803989240957632204885L, 0.000926876069151753290378112L, 0.541011723226630257077328e-5L, 0.535093845803642394908747e-15L };
|
||||
static const float f0 = 0.5641309023F;
|
||||
r = tools::evaluate_polynomial(n, z - 60) / tools::evaluate_polynomial(d, z - 60);
|
||||
b = f0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Worst case absolute error found: 8.094633491e-22
|
||||
static const T n[4] = { -0.789224703978722689089794e-5L, 0.622088451660986955124162e-6L, 0.145728445676882396797184e-7L, 0.603715505542715364529243e-10L };
|
||||
static const T d[4] = { 1L, 0.0375328846356293715248719L, 0.000467919535974625308126054L, 0.193847039275845656900547e-5L };
|
||||
static const float f0 = 0.5641584396F;
|
||||
r = tools::evaluate_polynomial(n, z - 85) / tools::evaluate_polynomial(d, z - 85);
|
||||
b = f0;
|
||||
}
|
||||
T g = exp(-z * z) / z;
|
||||
result = g * b + g * r;
|
||||
BOOST_MATH_INSTRUMENT_CODE("r = " << r);
|
||||
BOOST_MATH_INSTRUMENT_CODE("b = " << b);
|
||||
BOOST_MATH_INSTRUMENT_CODE("g = " << g);
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Any value of z larger than 28 will underflow to zero:
|
||||
//
|
||||
result = 0;
|
||||
invert = !invert;
|
||||
}
|
||||
|
||||
if(invert)
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
|
||||
return result;
|
||||
} // template <class T, class L>T erf_imp(T z, bool invert, const L& l, const mpl::int_<64>& t)
|
||||
|
||||
|
||||
template <class T, class Policy>
|
||||
T erf_imp(T z, bool invert, const Policy& pol, const mpl::int_<113>& t)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("113-bit precision erf_imp called");
|
||||
|
||||
if(z < 0)
|
||||
{
|
||||
if(!invert)
|
||||
return -erf_imp(-z, invert, pol, t);
|
||||
else if(z < -0.5)
|
||||
return 2 - erf_imp(-z, invert, pol, t);
|
||||
else
|
||||
return 1 + erf_imp(-z, false, pol, t);
|
||||
}
|
||||
|
||||
T result;
|
||||
|
||||
//
|
||||
// Big bunch of selection statements now to pick which
|
||||
// implementation to use, try to put most likely options
|
||||
// first:
|
||||
//
|
||||
if(z < 0.5)
|
||||
{
|
||||
//
|
||||
// We're going to calculate erf:
|
||||
//
|
||||
if(z == 0)
|
||||
{
|
||||
result = 0;
|
||||
}
|
||||
else if(z < 1e-20)
|
||||
{
|
||||
result = z * 1.125 + z * 0.003379167095512573896158903121545171688L;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Worst case absolute error found: 1.928180863e-35
|
||||
static const T n[13] = { 0.0033791670955125738961589031215451706772L, -0.000356604747854533671135323429762519216044L, -0.374476838669183581687167228866769133591L, 0.0395338132469809122364498388174446488042L, -0.070405473508786506375820161461872523315L, 0.00575264725772369303419496752516485264994L, -0.0122324470706306942925087773122510971344L, 0.000982833333252586078523570049842642796291L, -0.000937806155615159592441487275938040285833L, 0.485407838108763091860415874932955355755e-4L, -0.50171236926234625577876479444632561922e-4L, 0.19406068817888598455243350289053451571e-5L, -0.119351103792049576459000102632508734863e-5L };
|
||||
static const T d[13] = { 1L, -0.105530368216503232473476334993759958083L, 0.488152943026846232046726653294817930988L, -0.0470361716364117780901924633553851211874L, 0.107663671943702835026199580597519084906L, -0.00919493879447389180633447493128337242362L, 0.0138231121717229362691899919242806829805L, -0.000994048559663865788847688218108232247441L, 0.00109769834527023265969224251892094019735L, -0.600458401801636062015615549258555311545e-4L, 0.51530723974502946291624848874654212384e-4L, -0.164121264470361558910636548509486296153e-5L, 0.112643498977070218963888579607359294396e-5L };
|
||||
|
||||
result = z * 1.125 + z * tools::evaluate_rational(n, d, z);
|
||||
}
|
||||
}
|
||||
else if((z < 9) || ((z < 110) && invert)) // TODO FIXME!!
|
||||
{
|
||||
//
|
||||
// We'll be calculating erfc:
|
||||
//
|
||||
invert = !invert;
|
||||
T r, b;
|
||||
if(z < 0.75)
|
||||
{
|
||||
// Worst case absolute error found: 9.46579566e-36
|
||||
static const T n[10] = { -0.0361790390718262471349157886581290316118L, 0.268773785250238404882137450640472787307L, 0.46350995084084251624649426251701042395L, 0.368375435727102373204587584306335625665L, 0.177618123820303858190236222513516291818L, 0.0566304173556669007529719743050764079095L, 0.0121631149481817424284077180037019529004L, 0.00171397353209314111395429418066990259845L, 0.000144662387395699594624184141956722488753L, 0.559870522050008635715382724858714587198e-5L };
|
||||
static const T d[10] = { 1L, 2.50344259590701770420935329380375393716L, 2.84905597172139276093882199286535521011L, 1.93691730181297099541395314232750876411L, 0.868059574796050528229446630538462280596L, 0.266360035323208212078527036132085926692L, 0.0560555526482963925944703505114360693216L, 0.0078174400311465420803366235814673576269L, 0.000657067309046405057499687417839930873806L, 0.254293850077789079098316521097979388983e-4L };
|
||||
static const float f0 = 0.3440242112F;
|
||||
r = tools::evaluate_rational(n, d, z - 0.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 1.25)
|
||||
{
|
||||
// Worst case absolute error found: 1.222145602e-35
|
||||
static const T n[10] = { -0.03978768926111368569548863384587917014L, 0.136218360681765349252731304877153919181L, 0.252782160406474440925641829129129001834L, 0.198264231106182362320012632943145619752L, 0.0923045825293507328801206570363391760624L, 0.0281157216148097885766639832985410722743L, 0.00573041663561645197870019701493117161792L, 0.000762341440133027349203518836487137709687L, 0.60471020134417423449877859375492618899e-4L, 0.219005333943510376644902615714724932217e-5L };
|
||||
static const T d[11] = { 1L, 2.38113277319993574121349184069891082204L, 2.57380422881476860215664207822277590181L, 1.65937045609044738941173490190122101824L, 0.704055811320312044285417250966993014161L, 0.20414913933328592198279939394283925451L, 0.0405162285360227740710964820549709038107L, 0.00531638867177288975915820230980317499728L, 0.000419364368135139398723983192742319455284L, 0.151874665979234971229096136924566078234e-4L, 0.807869459506748684117962248796937508011e-11L };
|
||||
static const float f0 = 0.419990927F;
|
||||
r = tools::evaluate_polynomial(n, z - 0.75) / tools::evaluate_polynomial(d, z - 0.75);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 2)
|
||||
{
|
||||
// Worst case absolute error found: 5.893842955e-36
|
||||
static const T n[11] = { -0.0255063683486569102096736247449691465143L, 0.045782379672906795594927072060091308408L, 0.113248439610400562258072020811195716817L, 0.0996016254422112410086711272219455446695L, 0.0508749250027894453228337309651895478017L, 0.0171081937013828309576540212196644542209L, 0.00395354196550210630440706013523069756354L, 0.000629022203390154585475081628606234279007L, 0.664903286194855400689101617763591823345e-4L, 0.423935693893425355108071655059640137208e-5L, 0.124304036910852727351487636048151737214e-6L };
|
||||
static const T d[11] = { 1L, 2.39207679390801118396945702674440915308L, 2.62237869972649377524874287442154430843L, 1.73645189911172997548091140085423843725L, 0.769812706091926741262865732006953282036L, 0.238986814887891859065369830215615790694L, 0.0526759147274379214313767032352419949829L, 0.00814993801398361741777997755108018659382L, 0.00084829993036396244429607826663252633817L, 0.537276435448416921594616417908288527881e-4L, 0.157537193656690184073389824392669625417e-5L };
|
||||
static const float f0 = 0.4852850139F;
|
||||
r = tools::evaluate_rational(n, d, z - 1.25);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 2.75)
|
||||
{
|
||||
// Worst case absolute error found: 4.024770853e-36
|
||||
static const T n[10] = { -0.0108897177067473013323228381829144739013L, 0.0202210475357865979950082670101965963435L, 0.0403242149078991892599316678797913295452L, 0.0288492313188655084113941326565482276741L, 0.0116982647742533555237861890442866083526L, 0.00301908913020213436098518520436147263177L, 0.000511140165864993121203730804407968689429L, 0.555507897975436549741754647662158917103e-4L, 0.354571088276496768574495922471690102061e-5L, 0.101789333060641482357520298518780163915e-6L };
|
||||
static const T d[11] = { 1L, 1.98184247277299581801610266575921553552L, 1.77518826058984218945272444617044495028L, 0.943934346956188464279312722940302202684L, 0.328630002685235061519039528479761588138L, 0.0777535542351039388345270792222146705189L, 0.0125143974181120800829065248546370953609L, 0.00132270605931460450441108147393979771563L, 0.834118048375722123506409257130329786209e-4L, 0.239456257167492104073765911366304033453e-5L, 0.197067742893785800814802969598122120027e-13L };
|
||||
static const float f0 = 0.5216810703F;
|
||||
r = tools::evaluate_polynomial(n, z - 2) / tools::evaluate_polynomial(d, z - 2);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 3.75)
|
||||
{
|
||||
// Worst case absolute error found: 2.119317982e-36
|
||||
static const T n[10] = { -0.00669534469911386821762042893742722704704L, 0.00779239067529714323524154862288379264056L, 0.0167670669587476509267036865033136655094L, 0.0113887916348251443051357686146040093464L, 0.00426976750247047946700539147728477144579L, 0.00100469100574064832665606356894416652764L, 0.000153533145320881108157829902752192859922L, 0.149337551064665413462766906201269176262e-4L, 0.846377837919513024118176704010972579138e-6L, 0.214045773545256889299689737489755489478e-7L };
|
||||
static const T d[11] = { 1L, 1.78724215851193637544287795626580411105L, 1.44052576962222794702178612920219772782L, 0.687639905608366315245841860669607532265L, 0.214374367225822611754443822822738563207L, 0.0452948320968245754796139856381504201504L, 0.00649108394178118005887118777181540680812L, 0.000608904720665003139414993591868256489088L, 0.33959064390570911588709483563995284603e-4L, 0.858811916085393051026834431509997486704e-6L, 0.618878592093890510233502654703683447468e-15L };
|
||||
static const float f0 = 0.5392661095F;
|
||||
r = tools::evaluate_polynomial(n, z - 2.75) / tools::evaluate_polynomial(d, z - 2.75);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 5)
|
||||
{
|
||||
// Worst case absolute error found: 3.131502824e-36
|
||||
static const T n[10] = { -0.00378088626017041998499190989910098718437L, 0.0029008905292996011997575492874095588328L, 0.00662431938391549599757244232386689480515L, 0.00417809740399798845564363621020984935218L, 0.00142019749135652688012034919213168974543L, 0.000299107980170253223293530710056814995102L, 0.405161538841561396150507786831930770839e-4L, 0.346344371670880861875666253626975779945e-5L, 0.171091054330494778613793054233437928605e-6L, 0.373924433717749484258186454458704819755e-8L };
|
||||
static const T d[10] = { 1L, 1.5810750672399887547849540367499389454L, 1.12479852885403050655678225945856872694L, 0.47277272679268851560291322980574597267L, 0.129444913616967588584693095240544707208L, 0.0239544490709674941887988416318107990646L, 0.00299775294496053944060700963645084591246L, 0.00024478412843088575835960648397300177201L, 0.118424712755145205302405346348931402917e-4L, 0.2588206250858483868392167535345681119e-6L };
|
||||
static const float f0 = 0.549742341F;
|
||||
r = tools::evaluate_rational(n, d, z - 3.75);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 6.5)
|
||||
{
|
||||
// Worst case absolute error found: 3.352877573e-35
|
||||
static const T n[9] = { -0.00210683958249012010206456754123471415706L, 0.00146329021314062287670019911742786780092L, 0.00242029064025351202243048169807220157512L, 0.0011321990764681390160708960047630195582L, 0.000277123780759366982673218537550876769487L, 0.401236501288775561636453586216146028714e-4L, 0.347799938323835778216424009916867086167e-5L, 0.167678812729975154456097184107934455429e-6L, 0.346722083660429051057284107535869165775e-8L };
|
||||
static const T d[10] = { 1L, 1.22334833521124956366395053444841951468L, 0.661433457507589455018784737495591428263L, 0.206503622658778732280997770028712044451L, 0.0407323027711252752353388616742333806362L, 0.00519969889874877079704615143005539754407L, 0.000419679230772141031030427156828631265963L, 0.195896640254171597965013007459411704085e-4L, 0.405070207572551760879797790899826058473e-6L, -0.949400883467250846930389103621356900319e-17L };
|
||||
static const float f0 = 0.5556300282F;
|
||||
r = tools::evaluate_polynomial(n, z - 5) / tools::evaluate_polynomial(d, z - 5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 8)
|
||||
{
|
||||
// Worst case absolute error found: 2.10254551e-36
|
||||
static const T n[9] = { -0.00107224589975857477185569028693588970638L, 0.00081159959093417892787006088639848404179L, 0.00105587689576932891666032146026668833287L, 0.000416243954540394829165805666548948771809L, 0.861189599093384016322579078144012057531e-4L, 0.105064862265647286966467927732505059558e-4L, 0.763674245263385902692134637353517251296e-6L, 0.306964079269190247526141442183490066292e-7L, 0.525762928524110511201313708396204710874e-9L };
|
||||
static const T d[9] = { 1L, 1.03391233015873996503551085347368889767L, 0.471295765635712684194436077437130977978L, 0.123736066749315618886080242926593910851L, 0.0204690897886919138685460664198600282119L, 0.00218521816743913946855947853274936296576L, 0.000147057386621380823003258590658747813774L, 0.570514093706434168568509838021466564264e-5L, 0.977166974697066620826028345712327325748e-7L };
|
||||
static const float f0 = 0.5588091016F;
|
||||
r = tools::evaluate_rational(n, d, z - 6.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 10)
|
||||
{
|
||||
// Worst case absolute error found: 8.006848023e-37
|
||||
static const T n[9] = { -0.000764310289345400483607004463638641680792L, 0.000375959928342415987920641866513058424701L, 0.000477297615927227258961911005347799033473L, 0.000165573027183931250708334564452626717999L, 0.296617493157889183515359094859055088531e-4L, 0.310848843632513098624143817615592253324e-5L, 0.192932185180269434271810693046412848027e-6L, 0.658630702075882625552897504189436319318e-8L, 0.952880249971934343233104137698620618851e-10L };
|
||||
static const T d[9] = { 1L, 0.885953297549629585611202995885653291163L, 0.345435500008639080844920938390800739845L, 0.0774289910213823638414558561872084410517L, 0.0109142290775434200609901181618181718948L, 0.000990815749814504617347317658063197107511L, 0.565801964505889288566864514277149126893e-4L, 0.185846832474795168475989869562411740416e-5L, 0.268875677412705938842038805073576012915e-7L };
|
||||
static const float f0 = 0.5606456399F;
|
||||
r = tools::evaluate_rational(n, d, z - 8);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 12.5)
|
||||
{
|
||||
// Worst case absolute error found: 1.920487881e-37
|
||||
static const T n[9] = { -0.00049563543942917072170112779531688430711L, 0.000181627479476470045833245371263435213396L, 0.000205326116055098869964168775605689851547L, 0.602131211119027087508128340443602490578e-4L, 0.904046610725767796892834734953040318357e-5L, 0.790026495730279360618915285828083295597e-6L, 0.407154634490633661408148126521656550974e-7L, 0.114947371191075676274146563385045083492e-8L, 0.136959786076422777905476122283384578138e-10L };
|
||||
static const T d[9] = { 1L, 0.738936412939629363226408445024616124644L, 0.239911614287295587917806937612822134282L, 0.0447038494121568822243673246874110377585L, 0.00522920850086320874490830611785659031521L, 0.000393238307986133717620560371515858231357L, 0.18566831172454022627187937328433090172e-4L, 0.503267648562793696253090536560738864711e-6L, 0.599643373938283798258195761814169705225e-8L };
|
||||
static const float f0 = 0.5619055629F;
|
||||
r = tools::evaluate_rational(n, d, z - 10);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 15.5)
|
||||
{
|
||||
// Worst case absolute error found: 1.257535398e-36
|
||||
static const T n[8] = { -0.000310716603972278501158850534578560332617L, 0.00011678083970731888844953949114132723885L, 0.800190190430061077253903477346761222901e-4L, 0.156297703728913451581100601056534652076e-4L, 0.151432948873760306237990776980248434808e-5L, 0.798843820137664551611401320879346402013e-7L, 0.219398460602279142004550137383605410162e-8L, 0.244774638611231694720102050826438123042e-10L };
|
||||
static const T d[9] = { 1L, 0.536396467095662522242258924420035847546L, 0.12368534422025248132153213926057643819L, 0.0158935327926481775020421628983323726346L, 0.00122923842249710594941031294559763761829L, 0.572250268558063378795115723535491980973e-4L, 0.148480028895780193980507551658637328542e-5L, 0.165653602646537759781637790321962585489e-7L, 0.159564067829807076335030582566349996674e-21L };
|
||||
static const float f0 = 0.5627119541F;
|
||||
r = tools::evaluate_polynomial(n, z - 12.5) / tools::evaluate_polynomial(d, z - 12.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 20)
|
||||
{
|
||||
// Worst case absolute error found: 8.757869781e-37
|
||||
static const T n[8] = { -0.000232165799411403604511899928682939571679L, 0.473280617901953093430938763139716601257e-4L, 0.322197983787538821545512424866901113822e-4L, 0.53341606003892328294004958671866936958e-5L, 0.429392533762301420884052643595872389588e-6L, 0.186707830002841677949013638707964861935e-7L, 0.420531779988891521855765212230340499168e-9L, 0.38311153882270641561622347190918577449e-11L };
|
||||
static const T d[9] = { 1L, 0.440698415779467873589164469370853517393L, 0.0834079018864546179293964148377602724235L, 0.00878845776227345123101968908701592510214L, 0.000556792236817609981676018545344816931862L, 0.212109697877283363015270621439889468055e-4L, 0.449886743173619367191275104721917344569e-6L, 0.409854405005280582884236774230760402868e-8L, 0.185071069100878210011727114952196630136e-23L };
|
||||
static const float f0 = 0.5632548332F;
|
||||
r = tools::evaluate_polynomial(n, z - 15.5) / tools::evaluate_polynomial(d, z - 15.5);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 26)
|
||||
{
|
||||
// Worst case absolute error found: 6.571456853e-37
|
||||
static const T n[8] = { -0.000143129243915019877016909310584833592972L, 0.203555078616578752774553439209122798188e-4L, 0.116664173863253360297276766667046754002e-4L, 0.153607643549360281089355497044679566329e-5L, 0.976486412462035616905934994399021437658e-7L, 0.33416295362298759817564985788402188186e-8L, 0.590812660432887787644458409396105030781e-10L, 0.421471133628743008309458424282421874073e-12L };
|
||||
static const T d[8] = { 1L, 0.346848503043261151874606241871432055165L, 0.0516236057301875770334953837585483539519L, 0.0042740199483843978391191804633398315544L, 0.000212586135154357046245694533825075007902L, 0.635258188334431428038271842518161892901e-5L, 0.105600415847309067601860633252823051505e-6L, 0.753327238218310630683194279382721367469e-9L };
|
||||
static const float f0 = 0.5636301041F;
|
||||
r = tools::evaluate_polynomial(n, z - 20) / tools::evaluate_polynomial(d, z - 20);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 34)
|
||||
{
|
||||
// Worst case absolute error found: 2.529847851e-38
|
||||
static const T n[8] = { -0.863162280463127451272161303767299107489e-4L, 0.876391266908317792353253474461536821127e-5L, 0.407624004719762912183133597708988715137e-5L, 0.418371930808379615690956857824418800194e-6L, 0.206376792034344913360458422974245946873e-7L, 0.546878311460852031076829190722479684e-9L, 0.74760305098509923829341087347518769626e-11L, 0.411832046806658129073165530819472782663e-13L };
|
||||
static const T d[9] = { 1L, 0.268714425336129161136892060316889824437L, 0.0309686025544536788982104017649851516554L, 0.00198426609900573235086828549632290797514L, 0.763402107420631006526499294753645914808e-4L, 0.176354119917411263184292422389304506735e-5L, 0.226504369338582253171306523992412653547e-7L, 0.124774448034213281307712525982862926228e-9L, 0.541581693417048102342931921476367282462e-28L };
|
||||
static const float f0 = 0.5638595223F;
|
||||
r = tools::evaluate_polynomial(n, z - 26) / tools::evaluate_polynomial(d, z - 26);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 46)
|
||||
{
|
||||
// Worst case absolute error found: 4.880939969e-36
|
||||
static const T n[7] = { -0.552701065525823960321509114250962372959e-4L, 0.459798238451342341380837226471283129117e-5L, 0.117462487430397988459985818542278619172e-5L, 0.704965053290383355071079647747711714696e-7L, 0.191250482739845326510859812663255140286e-8L, 0.245913419605775857221974833985059356312e-10L, 0.120466123381598216554945834019040289508e-12L };
|
||||
static const T d[8] = { 1L, 0.175852634004021068883919193145643406305L, 0.0128923775281953424344037205817061020944L, 0.000504385604406829419856756492198778141939L, 0.111061123996047697713589874603922096536e-4L, 0.130499191758882778721577274330215931713e-6L, 0.639279131688964342759306361922751772829e-9L, -0.10503012469906917938721140272475203112e-26L };
|
||||
static const float f0 = 0.564001143F;
|
||||
r = tools::evaluate_polynomial(n, z - 34) / tools::evaluate_polynomial(d, z - 34);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 62)
|
||||
{
|
||||
// Worst case absolute error found: 8.634961697e-37
|
||||
static const T n[7] = { -0.299551937061912926289705712581858190494e-4L, 0.188783643501597286680709990049243153264e-5L, 0.353403900815908094401075506391935032602e-6L, 0.156779149815977342177830075875441013335e-7L, 0.31456307256618424444443489905810774564e-9L, 0.29912544832845265905351204765862702307e-11L, 0.108360038290329929702659864116372774364e-13L };
|
||||
static const T d[7] = { 1L, 0.13020345740128026085404079010013007005L, 0.00706598549835633149505923515407700416484L, 0.000204578844720147762058725212299415091588L, 0.333280847765611305843836201217690887394e-5L, 0.289666303356425428524772241712503072453e-7L, 0.104933404691983708511908027657434756019e-9L };
|
||||
static const float f0 = 0.564086318F;
|
||||
r = tools::evaluate_polynomial(n, z - 46) / tools::evaluate_polynomial(d, z - 46);
|
||||
b = f0;
|
||||
}
|
||||
else if(z < 80)
|
||||
{
|
||||
// Worst case absolute error found: 6.10700166e-39
|
||||
static const T n[7] = { -0.146162619512779884168960178459825270831e-4L, 0.952303834226435420147786300516273108344e-6L, 0.114559890033396819882468040960469980168e-6L, 0.368994353517438072494331750992706039868e-8L, 0.545158660461829568567388818070830588533e-10L, 0.383569328729331398089160922704933035281e-12L, 0.103104113324271568678309317039606225294e-14L };
|
||||
static const T d[7] = { 1L, 0.0966822058944670599111360985490948186413L, 0.00389546596914826027568119425228340291579L, 0.837237328321088890541798035513749762375e-4L, 0.101236677684940943809478588316884539423e-5L, 0.652985528810044575089151077574382356898e-8L, 0.175523663960756825512727785416137345625e-10L };
|
||||
static const float f0 = 0.5641308427F;
|
||||
r = tools::evaluate_polynomial(n, z - 62) / tools::evaluate_polynomial(d, z - 62);
|
||||
b = f0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Worst case absolute error found: 3.409761622e-39
|
||||
static const T n[7] = { -0.103600733768855845278685109220598569282e-4L, 0.324846376725138276091774803419773168357e-6L, 0.376580042454826796817160322889753111347e-7L, 0.971125540805193703472871419997820785081e-9L, 0.112499588573918670534994853431614458564e-10L, 0.6161310085325929027114924903443564594e-13L, 0.128358125353302055468778305481781957985e-15L };
|
||||
static const T d[7] = { 1L, 0.0749579802028981336679035635535776767532L, 0.00234137768051079846068630120744888560113L, 0.390095348825177571970348898222511084593e-4L, 0.365628111271063883320224395719085602867e-6L, 0.182790705425846241876560215158605843026e-8L, 0.380806548535012144489621218246876843627e-11L };
|
||||
static const float f0 = 0.5641558766F;
|
||||
r = tools::evaluate_polynomial(n, z - 80) / tools::evaluate_polynomial(d, z - 80);
|
||||
b = f0;
|
||||
}
|
||||
T g = exp(-z * z) / z;
|
||||
result = g * b + g * r;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// Any value of z larger than 110 will underflow to zero:
|
||||
//
|
||||
result = 0;
|
||||
invert = !invert;
|
||||
}
|
||||
|
||||
if(invert)
|
||||
{
|
||||
result = 1 - result;
|
||||
}
|
||||
|
||||
return result;
|
||||
} // template <class T, class L>T erf_imp(T z, bool invert, const L& l, const mpl::int_<113>& t)
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type erf(T z, const Policy& /* pol */)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
typedef typename policies::precision<result_type, Policy>::type precision_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("result_type = " << typeid(result_type).name());
|
||||
BOOST_MATH_INSTRUMENT_CODE("value_type = " << typeid(value_type).name());
|
||||
BOOST_MATH_INSTRUMENT_CODE("precision_type = " << typeid(precision_type).name());
|
||||
|
||||
typedef typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<0> >,
|
||||
mpl::int_<0>,
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<53> >,
|
||||
mpl::int_<53>, // double
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<64> >,
|
||||
mpl::int_<64>, // 80-bit long double
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<113> >,
|
||||
mpl::int_<113>, // 128-bit long double
|
||||
mpl::int_<0> // too many bits, use generic version.
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("tag_type = " << typeid(tag_type).name());
|
||||
|
||||
return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::erf_imp(
|
||||
static_cast<value_type>(z),
|
||||
false,
|
||||
forwarding_policy(),
|
||||
tag_type()), "boost::math::erf<%1%>(%1%, %1%)");
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type erfc(T z, const Policy& /* pol */)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
typedef typename policies::precision<result_type, Policy>::type precision_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("result_type = " << typeid(result_type).name());
|
||||
BOOST_MATH_INSTRUMENT_CODE("value_type = " << typeid(value_type).name());
|
||||
BOOST_MATH_INSTRUMENT_CODE("precision_type = " << typeid(precision_type).name());
|
||||
|
||||
typedef typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<0> >,
|
||||
mpl::int_<0>,
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<53> >,
|
||||
mpl::int_<53>, // double
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<64> >,
|
||||
mpl::int_<64>, // 80-bit long double
|
||||
typename mpl::if_<
|
||||
mpl::less_equal<precision_type, mpl::int_<113> >,
|
||||
mpl::int_<113>, // 128-bit long double
|
||||
mpl::int_<0> // too many bits, use generic version.
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
|
||||
BOOST_MATH_INSTRUMENT_CODE("tag_type = " << typeid(tag_type).name());
|
||||
|
||||
return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::erf_imp(
|
||||
static_cast<value_type>(z),
|
||||
true,
|
||||
forwarding_policy(),
|
||||
tag_type()), "boost::math::erfc<%1%>(%1%, %1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type erf(T z)
|
||||
{
|
||||
return boost::math::erf(z, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type erfc(T z)
|
||||
{
|
||||
return boost::math::erfc(z, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/math/special_functions/detail/erf_inv.hpp>
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_ERF_HPP
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// (C) Copyright John Maddock 2005.
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,7 +9,13 @@
|
||||
#include <cmath>
|
||||
#include <math.h> // platform's ::expm1
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/math/special_functions/detail/series.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/series.hpp>
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/tools/rational.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/mpl/less_equal.hpp>
|
||||
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
# include <boost/static_assert.hpp>
|
||||
@@ -17,87 +23,203 @@
|
||||
# include <boost/assert.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std{ using ::exp; using ::fabs; }
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace detail{
|
||||
//
|
||||
// Functor expm1_series returns the next term in the Taylor series
|
||||
// x^k / k!
|
||||
// each time that operator() is invoked.
|
||||
//
|
||||
template <class T>
|
||||
struct expm1_series
|
||||
namespace detail
|
||||
{
|
||||
typedef T result_type;
|
||||
// Functor expm1_series returns the next term in the Taylor series
|
||||
// x^k / k!
|
||||
// each time that operator() is invoked.
|
||||
//
|
||||
template <class T>
|
||||
struct expm1_series
|
||||
{
|
||||
typedef T result_type;
|
||||
|
||||
expm1_series(T x)
|
||||
: k(0), m_x(x), m_term(1) {}
|
||||
expm1_series(T x)
|
||||
: k(0), m_x(x), m_term(1) {}
|
||||
|
||||
T operator()()
|
||||
{
|
||||
++k;
|
||||
m_term *= m_x;
|
||||
m_term /= k;
|
||||
return m_term;
|
||||
}
|
||||
T operator()()
|
||||
{
|
||||
++k;
|
||||
m_term *= m_x;
|
||||
m_term /= k;
|
||||
return m_term;
|
||||
}
|
||||
|
||||
int count()const
|
||||
{
|
||||
return k;
|
||||
}
|
||||
int count()const
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
private:
|
||||
int k;
|
||||
const T m_x;
|
||||
T m_term;
|
||||
expm1_series(const expm1_series&);
|
||||
expm1_series& operator=(const expm1_series&);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
private:
|
||||
int k;
|
||||
const T m_x;
|
||||
T m_term;
|
||||
expm1_series(const expm1_series&);
|
||||
expm1_series& operator=(const expm1_series&);
|
||||
};
|
||||
|
||||
//
|
||||
// Algorithm expm1 is part of C99, but is not yet provided by many compilers.
|
||||
//
|
||||
// This version uses a Taylor series expansion for 0.5 > |x| > epsilon.
|
||||
//
|
||||
template <class T>
|
||||
T expm1(T x)
|
||||
template <class T, class Policy>
|
||||
T expm1_imp(T x, const mpl::int_<0>&, const Policy& pol)
|
||||
{
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized);
|
||||
#else
|
||||
BOOST_ASSERT(std::numeric_limits<T>::is_specialized);
|
||||
#endif
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
T a = std::fabs(x);
|
||||
T a = fabs(x);
|
||||
if(a > T(0.5L))
|
||||
return std::exp(x) - T(1);
|
||||
if(a < std::numeric_limits<T>::epsilon())
|
||||
return exp(x) - T(1);
|
||||
if(a < tools::epsilon<T>())
|
||||
return x;
|
||||
detail::expm1_series<T> s(x);
|
||||
T result = detail::kahan_sum_series(s, std::numeric_limits<T>::digits + 2);
|
||||
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
T result = tools::sum_series(s, policies::digits<T, Policy>(), max_iter);
|
||||
#else
|
||||
T zero = 0;
|
||||
T result = tools::sum_series(s, policies::digits<T, Policy>(), max_iter, zero);
|
||||
#endif
|
||||
policies::check_series_iterations("boost::math::expm1<%1%>(%1%)", max_iter, pol);
|
||||
return result;
|
||||
}
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
inline float expm1(float z)
|
||||
|
||||
template <class T, class P>
|
||||
T expm1_imp(T x, const mpl::int_<53>&, const P&)
|
||||
{
|
||||
return expm1<float>(z);
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
T a = fabs(x);
|
||||
if(a > T(0.5L))
|
||||
return exp(x) - T(1);
|
||||
if(a < tools::epsilon<T>())
|
||||
return x;
|
||||
|
||||
static const float Y = 0.10281276702880859e1f;
|
||||
static const T n[] = { -0.28127670288085937e-1, 0.51278186299064534e0, -0.6310029069350198e-1, 0.11638457975729296e-1, -0.52143390687521003e-3, 0.21491399776965688e-4 };
|
||||
static const T d[] = { 1, -0.45442309511354755e0, 0.90850389570911714e-1, -0.10088963629815502e-1, 0.63003407478692265e-3, -0.17976570003654402e-4 };
|
||||
|
||||
T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
|
||||
return result;
|
||||
}
|
||||
inline double expm1(double z)
|
||||
|
||||
template <class T, class P>
|
||||
T expm1_imp(T x, const mpl::int_<64>&, const P&)
|
||||
{
|
||||
return expm1<double>(z);
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
T a = fabs(x);
|
||||
if(a > T(0.5L))
|
||||
return exp(x) - T(1);
|
||||
if(a < tools::epsilon<T>())
|
||||
return x;
|
||||
|
||||
static const float Y = 0.10281276702880859375e1f;
|
||||
static const T n[] = {
|
||||
-0.281276702880859375e-1L,
|
||||
0.512980290285154286358e0L,
|
||||
-0.667758794592881019644e-1L,
|
||||
0.131432469658444745835e-1L,
|
||||
-0.72303795326880286965e-3L,
|
||||
0.447441185192951335042e-4L,
|
||||
-0.714539134024984593011e-6L
|
||||
};
|
||||
static const T d[] = {
|
||||
1,
|
||||
-0.461477618025562520389e0L,
|
||||
0.961237488025708540713e-1L,
|
||||
-0.116483957658204450739e-1L,
|
||||
0.873308008461557544458e-3L,
|
||||
-0.387922804997682392562e-4L,
|
||||
0.807473180049193557294e-6L
|
||||
};
|
||||
|
||||
T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
|
||||
return result;
|
||||
}
|
||||
inline long double expm1(long double z)
|
||||
|
||||
template <class T, class P>
|
||||
T expm1_imp(T x, const mpl::int_<113>&, const P&)
|
||||
{
|
||||
return expm1<long double>(z);
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
T a = fabs(x);
|
||||
if(a > T(0.5L))
|
||||
return exp(x) - T(1);
|
||||
if(a < tools::epsilon<T>())
|
||||
return x;
|
||||
|
||||
static const float Y = 0.10281276702880859375e1f;
|
||||
static const T n[] = {
|
||||
-0.28127670288085937499999999999999999854e-1L,
|
||||
0.51278156911210477556524452177540792214e0L,
|
||||
-0.63263178520747096729500254678819588223e-1L,
|
||||
0.14703285606874250425508446801230572252e-1L,
|
||||
-0.8675686051689527802425310407898459386e-3L,
|
||||
0.88126359618291165384647080266133492399e-4L,
|
||||
-0.25963087867706310844432390015463138953e-5L,
|
||||
0.14226691087800461778631773363204081194e-6L,
|
||||
-0.15995603306536496772374181066765665596e-8L,
|
||||
0.45261820069007790520447958280473183582e-10L
|
||||
};
|
||||
static const T d[] = {
|
||||
1,
|
||||
-0.45441264709074310514348137469214538853e0L,
|
||||
0.96827131936192217313133611655555298106e-1L,
|
||||
-0.12745248725908178612540554584374876219e-1L,
|
||||
0.11473613871583259821612766907781095472e-2L,
|
||||
-0.73704168477258911962046591907690764416e-4L,
|
||||
0.34087499397791555759285503797256103259e-5L,
|
||||
-0.11114024704296196166272091230695179724e-6L,
|
||||
0.23987051614110848595909588343223896577e-8L,
|
||||
-0.29477341859111589208776402638429026517e-10L,
|
||||
0.13222065991022301420255904060628100924e-12L
|
||||
};
|
||||
|
||||
T result = x * Y + x * tools::evaluate_polynomial(n, x) / tools::evaluate_polynomial(d, x);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type expm1(T x, const Policy& /* pol */)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
typedef typename policies::precision<result_type, Policy>::type precision_type;
|
||||
typedef typename policies::normalise<
|
||||
Policy,
|
||||
policies::promote_float<false>,
|
||||
policies::promote_double<false>,
|
||||
policies::discrete_quantile<>,
|
||||
policies::assert_undefined<> >::type forwarding_policy;
|
||||
|
||||
typedef typename mpl::if_c<
|
||||
::std::numeric_limits<result_type>::is_specialized == 0,
|
||||
mpl::int_<0>, // no numeric_limits, use generic solution
|
||||
typename mpl::if_<
|
||||
typename mpl::less_equal<precision_type, mpl::int_<53> >::type,
|
||||
mpl::int_<53>, // double
|
||||
typename mpl::if_<
|
||||
typename mpl::less_equal<precision_type, mpl::int_<64> >::type,
|
||||
mpl::int_<64>, // 80-bit long double
|
||||
typename mpl::if_<
|
||||
typename mpl::less_equal<precision_type, mpl::int_<113> >::type,
|
||||
mpl::int_<113>, // 128-bit long double
|
||||
mpl::int_<0> // too many bits, use generic version.
|
||||
>::type
|
||||
>::type
|
||||
>::type
|
||||
>::type tag_type;
|
||||
|
||||
return policies::checked_narrowing_cast<result_type, forwarding_policy>(detail::expm1_imp(
|
||||
static_cast<value_type>(x),
|
||||
tag_type(), forwarding_policy()), "boost::math::expm1<%1%>(%1%)");
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef expm1
|
||||
# ifndef BOOST_HAS_expm1
|
||||
@@ -108,14 +230,40 @@ inline long double expm1(long double z)
|
||||
|
||||
#ifdef BOOST_HAS_EXPM1
|
||||
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
|
||||
inline float expm1(float x){ return ::expm1f(x); }
|
||||
inline long double expm1(long double x){ return ::expm1l(x); }
|
||||
inline float expm1(float x, const policies::policy<>&){ return ::expm1f(x); }
|
||||
inline long double expm1(long double x, const policies::policy<>&){ return ::expm1l(x); }
|
||||
#else
|
||||
inline float expm1(float x){ return ::expm1(x); }
|
||||
inline float expm1(float x, const policies::policy<>&){ return ::expm1(x); }
|
||||
#endif
|
||||
inline double expm1(double x){ return ::expm1(x); }
|
||||
inline double expm1(double x, const policies::policy<>&){ return ::expm1(x); }
|
||||
#endif
|
||||
|
||||
} } // namespaces
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type expm1(T x)
|
||||
{
|
||||
return expm1(x, policies::policy<>());
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
inline float expm1(float z)
|
||||
{
|
||||
return expm1<float>(z);
|
||||
}
|
||||
inline double expm1(double z)
|
||||
{
|
||||
return expm1<double>(z);
|
||||
}
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline long double expm1(long double z)
|
||||
{
|
||||
return expm1<long double>(z);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_HYPOT_INCLUDED
|
||||
|
||||
|
||||
|
||||
224
include/boost/math/special_functions/factorials.hpp
Normal file
224
include/boost/math/special_functions/factorials.hpp
Normal file
@@ -0,0 +1,224 @@
|
||||
// Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SP_FACTORIALS_HPP
|
||||
#define BOOST_MATH_SP_FACTORIALS_HPP
|
||||
|
||||
#include <boost/math/special_functions/gamma.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/special_functions/detail/unchecked_factorial.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push) // Temporary until lexical cast fixed.
|
||||
#pragma warning(disable: 4127 4701)
|
||||
#endif
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#include <cmath>
|
||||
|
||||
namespace boost { namespace math
|
||||
{
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T factorial(unsigned i, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // Aid ADL for floor.
|
||||
|
||||
if(i <= max_factorial<T>::value)
|
||||
return unchecked_factorial<T>(i);
|
||||
T result = boost::math::tgamma(static_cast<T>(i+1), pol);
|
||||
if(result > tools::max_value<T>())
|
||||
return result; // Overflowed value! (But tgamma will have signalled the error already).
|
||||
return floor(result + 0.5f);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T factorial(unsigned i)
|
||||
{
|
||||
return factorial<T>(i, policies::policy<>());
|
||||
}
|
||||
/*
|
||||
// Can't have these in a policy enabled world?
|
||||
template<>
|
||||
inline float factorial<float>(unsigned i)
|
||||
{
|
||||
if(i <= max_factorial<float>::value)
|
||||
return unchecked_factorial<float>(i);
|
||||
return tools::overflow_error<float>(BOOST_CURRENT_FUNCTION);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline double factorial<double>(unsigned i)
|
||||
{
|
||||
if(i <= max_factorial<double>::value)
|
||||
return unchecked_factorial<double>(i);
|
||||
return tools::overflow_error<double>(BOOST_CURRENT_FUNCTION);
|
||||
}
|
||||
*/
|
||||
template <class T, class Policy>
|
||||
T double_factorial(unsigned i, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL lookup of std names
|
||||
if(i & 1)
|
||||
{
|
||||
// odd i:
|
||||
if(i < max_factorial<T>::value)
|
||||
{
|
||||
unsigned n = (i - 1) / 2;
|
||||
return ceil(unchecked_factorial<T>(i) / (ldexp(T(1), (int)n) * unchecked_factorial<T>(n)) - 0.5f);
|
||||
}
|
||||
//
|
||||
// Fallthrough: i is too large to use table lookup, try the
|
||||
// gamma function instead.
|
||||
//
|
||||
T result = boost::math::tgamma(static_cast<T>(i) / 2 + 1, pol) / sqrt(constants::pi<T>());
|
||||
if(ldexp(tools::max_value<T>(), -static_cast<int>(i+1) / 2) > result)
|
||||
return ceil(result * ldexp(T(1), (i+1) / 2) - 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
// even i:
|
||||
unsigned n = i / 2;
|
||||
T result = factorial<T>(n, pol);
|
||||
if(ldexp(tools::max_value<T>(), -(int)n) > result)
|
||||
return result * ldexp(T(1), (int)n);
|
||||
}
|
||||
//
|
||||
// If we fall through to here then the result is infinite:
|
||||
//
|
||||
return policies::raise_overflow_error<T>("boost::math::double_factorial<%1%>(unsigned)", 0, pol);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T double_factorial(unsigned i)
|
||||
{
|
||||
return double_factorial<T>(i, policies::policy<>());
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class T, class Policy>
|
||||
T rising_factorial_imp(T x, int n, const Policy& pol)
|
||||
{
|
||||
if(x < 0)
|
||||
{
|
||||
//
|
||||
// For x less than zero, we really have a falling
|
||||
// factorial, modulo a possible change of sign.
|
||||
//
|
||||
// Note that the falling factorial isn't defined
|
||||
// for negative n, so we'll get rid of that case
|
||||
// first:
|
||||
//
|
||||
bool inv = false;
|
||||
if(n < 0)
|
||||
{
|
||||
x += n;
|
||||
n = -n;
|
||||
inv = true;
|
||||
}
|
||||
T result = ((n&1) ? -1 : 1) * falling_factorial(-x, n, pol);
|
||||
if(inv)
|
||||
result = 1 / result;
|
||||
return result;
|
||||
}
|
||||
if(n == 0)
|
||||
return 1;
|
||||
//
|
||||
// We don't optimise this for small n, because
|
||||
// tgamma_delta_ratio is alreay optimised for that
|
||||
// use case:
|
||||
//
|
||||
return 1 / boost::math::tgamma_delta_ratio(x, static_cast<T>(n), pol);
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T falling_factorial_imp(T x, unsigned n, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
if(x == 0)
|
||||
return 0;
|
||||
if(x < 0)
|
||||
{
|
||||
//
|
||||
// For x < 0 we really have a rising factorial
|
||||
// modulo a possible change of sign:
|
||||
//
|
||||
return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol);
|
||||
}
|
||||
if(n == 0)
|
||||
return 1;
|
||||
if(x < n-1)
|
||||
{
|
||||
//
|
||||
// x+1-n will be negative and tgamma_delta_ratio won't
|
||||
// handle it, split the product up into three parts:
|
||||
//
|
||||
T xp1 = x + 1;
|
||||
unsigned n2 = tools::real_cast<unsigned>(floor(xp1));
|
||||
if(n2 == xp1)
|
||||
return 0;
|
||||
T result = boost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol);
|
||||
x -= n2;
|
||||
result *= x;
|
||||
++n2;
|
||||
if(n2 < n)
|
||||
result *= falling_factorial(x - 1, n - n2, pol);
|
||||
return result;
|
||||
}
|
||||
//
|
||||
// Simple case: just the ratio of two
|
||||
// (positive argument) gamma functions.
|
||||
// Note that we don't optimise this for small n,
|
||||
// because tgamma_delta_ratio is alreay optimised
|
||||
// for that use case:
|
||||
//
|
||||
return boost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class RT>
|
||||
inline typename tools::promote_args<RT>::type
|
||||
falling_factorial(RT x, unsigned n)
|
||||
{
|
||||
typedef typename tools::promote_args<RT>::type result_type;
|
||||
return detail::falling_factorial_imp(
|
||||
static_cast<result_type>(x), n, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class RT, class Policy>
|
||||
inline typename tools::promote_args<RT>::type
|
||||
falling_factorial(RT x, unsigned n, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<RT>::type result_type;
|
||||
return detail::falling_factorial_imp(
|
||||
static_cast<result_type>(x), n, pol);
|
||||
}
|
||||
|
||||
template <class RT>
|
||||
inline typename tools::promote_args<RT>::type
|
||||
rising_factorial(RT x, int n)
|
||||
{
|
||||
typedef typename tools::promote_args<RT>::type result_type;
|
||||
return detail::rising_factorial_imp(
|
||||
static_cast<result_type>(x), n, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class RT, class Policy>
|
||||
inline typename tools::promote_args<RT>::type
|
||||
rising_factorial(RT x, int n, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<RT>::type result_type;
|
||||
return detail::rising_factorial_imp(
|
||||
static_cast<result_type>(x), n, pol);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SP_FACTORIALS_HPP
|
||||
240
include/boost/math/special_functions/fpclassify.hpp
Normal file
240
include/boost/math/special_functions/fpclassify.hpp
Normal file
@@ -0,0 +1,240 @@
|
||||
// Copyright John Maddock 2005-2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_FPCLASSIFY_HPP
|
||||
#define BOOST_MATH_FPCLASSIFY_HPP
|
||||
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/math/tools/real_cast.hpp>
|
||||
#include <boost/type_traits/is_floating_point.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#include <float.h>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std{ using ::abs; using ::fabs; }
|
||||
#endif
|
||||
|
||||
#ifndef FP_NORMAL
|
||||
|
||||
#define FP_ZERO 0
|
||||
#define FP_NORMAL 1
|
||||
#define FP_INFINITE 2
|
||||
#define FP_NAN 3
|
||||
#define FP_SUBNORMAL 4
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_HAS_FPCLASSIFY
|
||||
|
||||
#ifndef fpclassify
|
||||
# if (defined(__GLIBCPP__) || defined(__GLIBCXX__)) && defined(_GLIBCXX_USE_C99_MATH) && !(defined(_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC) && (_GLIBCXX_USE_C99_FP_MACROS_DYNAMIC != 0))
|
||||
# define BOOST_FPCLASSIFY_PREFIX ::std::
|
||||
# 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{
|
||||
|
||||
#if defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
|
||||
//
|
||||
// This must not be located in any namespace under boost::math
|
||||
// otherwise we can get into an infinite loop if isnan is
|
||||
// a #define for "isnan" !
|
||||
//
|
||||
namespace math_detail{
|
||||
|
||||
template <class T>
|
||||
inline bool is_nan_helper(T t, const boost::true_type&)
|
||||
{
|
||||
#ifdef isnan
|
||||
return isnan(t);
|
||||
#else // BOOST_HAS_FPCLASSIFY
|
||||
return (BOOST_FPCLASSIFY_PREFIX fpclassify(t) == FP_NAN);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool is_nan_helper(T t, const boost::false_type&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // defined(BOOST_HAS_FPCLASSIFY) || defined(isnan)
|
||||
|
||||
namespace math{
|
||||
|
||||
namespace detail{
|
||||
|
||||
template <class T>
|
||||
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const mpl::true_&)
|
||||
{
|
||||
// whenever possible check for Nan's first:
|
||||
#ifdef BOOST_HAS_FPCLASSIFY
|
||||
if(::boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
|
||||
return FP_NAN;
|
||||
#elif defined(isnan)
|
||||
if(boost::math_detail::is_nan_helper(t, ::boost::is_floating_point<T>()))
|
||||
return FP_NAN;
|
||||
#elif defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
if(::_isnan(boost::math::tools::real_cast<double>(t)))
|
||||
return FP_NAN;
|
||||
#endif
|
||||
// std::fabs broken on a few systems especially for long long!!!!
|
||||
T at = (t < T(0)) ? -t : t;
|
||||
|
||||
// Use a process of exclusion to figure out
|
||||
// what kind of type we have, this relies on
|
||||
// IEEE conforming reals that will treat
|
||||
// Nan's as unordered. Some compilers
|
||||
// don't do this once optimisations are
|
||||
// turned on, hence the check for nan's above.
|
||||
if(at <= (std::numeric_limits<T>::max)())
|
||||
{
|
||||
if(at >= (std::numeric_limits<T>::min)())
|
||||
return FP_NORMAL;
|
||||
return (at != 0) ? FP_SUBNORMAL : FP_ZERO;
|
||||
}
|
||||
else if(at > (std::numeric_limits<T>::max)())
|
||||
return FP_INFINITE;
|
||||
return FP_NAN;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int fpclassify_imp BOOST_NO_MACRO_EXPAND(T t, const mpl::false_&)
|
||||
{
|
||||
//
|
||||
// An unknown type with no numeric_limits support,
|
||||
// so what are we supposed to do we do here?
|
||||
//
|
||||
return t == 0 ? FP_ZERO : FP_NORMAL;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline int fpclassify BOOST_NO_MACRO_EXPAND(T t)
|
||||
{
|
||||
#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
if(std::numeric_limits<T>::is_specialized)
|
||||
return detail::fpclassify_imp(t, mpl::true_());
|
||||
return detail::fpclassify_imp(t, mpl::false_());
|
||||
#else
|
||||
return detail::fpclassify_imp(t, mpl::bool_< ::std::numeric_limits<T>::is_specialized>());
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_FPCLASSIFY)
|
||||
inline int fpclassify BOOST_NO_MACRO_EXPAND(float t)
|
||||
{
|
||||
return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
|
||||
}
|
||||
inline int fpclassify BOOST_NO_MACRO_EXPAND(double t)
|
||||
{
|
||||
return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
|
||||
}
|
||||
#if !defined(__CYGWIN__) && !defined(__HP_aCC) && !defined(BOOST_INTEL) && !defined(BOOST_NO_NATIVE_LONG_DOUBLE_FP_CLASSIFY)
|
||||
// The native fpclassify broken for long doubles with aCC
|
||||
// use portable one instead....
|
||||
inline int fpclassify BOOST_NO_MACRO_EXPAND(long double t)
|
||||
{
|
||||
return BOOST_FPCLASSIFY_PREFIX fpclassify(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
// This only works for type double, for both float
|
||||
// and long double it gives misleading answers.
|
||||
inline int fpclassify BOOST_NO_MACRO_EXPAND(double t)
|
||||
{
|
||||
switch(::_fpclass(t))
|
||||
{
|
||||
case _FPCLASS_SNAN /* Signaling NaN */ :
|
||||
case _FPCLASS_QNAN /* Quiet NaN */ :
|
||||
return FP_NAN;
|
||||
case _FPCLASS_NINF /*Negative infinity ( –INF) */ :
|
||||
case _FPCLASS_PINF /* Positive infinity (+INF) */ :
|
||||
return FP_INFINITE;
|
||||
case _FPCLASS_NN /* Negative normalized non-zero */ :
|
||||
case _FPCLASS_PN /* Positive normalized non-zero */ :
|
||||
return FP_NORMAL;
|
||||
case _FPCLASS_ND /* Negative denormalized */:
|
||||
case _FPCLASS_PD /* Positive denormalized */ :
|
||||
return FP_SUBNORMAL;
|
||||
case _FPCLASS_NZ /* Negative zero ( – 0) */ :
|
||||
case _FPCLASS_PZ /* Positive 0 (+0) */ :
|
||||
return FP_ZERO;
|
||||
default:
|
||||
/**/ ;
|
||||
}
|
||||
return FP_NAN; // should never get here!!!
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline bool isfinite BOOST_NO_MACRO_EXPAND(T z)
|
||||
{
|
||||
int t = (::boost::math::fpclassify)(z);
|
||||
return (t != FP_NAN) && (t != FP_INFINITE);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool isinf BOOST_NO_MACRO_EXPAND(T t)
|
||||
{
|
||||
return (::boost::math::fpclassify)(t) == FP_INFINITE;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool isnan BOOST_NO_MACRO_EXPAND(T t)
|
||||
{
|
||||
return (::boost::math::fpclassify)(t) == FP_NAN;
|
||||
}
|
||||
#ifdef isnan
|
||||
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
|
||||
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
|
||||
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return ::boost::math_detail::is_nan_helper(t, boost::true_type()); }
|
||||
#elif defined(BOOST_MSVC)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
|
||||
# pragma warning(disable: 4244) // conversion from 'long double' to 'double',
|
||||
// No possible loss of data because they are same size.
|
||||
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<float>(float t){ return _isnan(t); }
|
||||
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<double>(double t){ return _isnan(t); }
|
||||
template <> inline bool isnan BOOST_NO_MACRO_EXPAND<long double>(long double t){ return _isnan(t); }
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
inline bool isnormal BOOST_NO_MACRO_EXPAND(T t)
|
||||
{
|
||||
return (::boost::math::fpclassify)(t) == FP_NORMAL;
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_FPCLASSIFY_HPP
|
||||
|
||||
|
||||
|
||||
1471
include/boost/math/special_functions/gamma.hpp
Normal file
1471
include/boost/math/special_functions/gamma.hpp
Normal file
File diff suppressed because it is too large
Load Diff
71
include/boost/math/special_functions/hermite.hpp
Normal file
71
include/boost/math/special_functions/hermite.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_HERMITE_HPP
|
||||
#define BOOST_MATH_SPECIAL_HERMITE_HPP
|
||||
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace math{
|
||||
|
||||
// Recurrance relation for Hermite polynomials:
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
hermite_next(unsigned n, T1 x, T2 Hn, T3 Hnm1)
|
||||
{
|
||||
return (2 * x * Hn - 2 * n * Hnm1);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
|
||||
// Implement Hermite polynomials via recurrance:
|
||||
template <class T>
|
||||
T hermite_imp(unsigned n, T x)
|
||||
{
|
||||
T p0 = 1;
|
||||
T p1 = 2 * x;
|
||||
|
||||
if(n == 0)
|
||||
return p0;
|
||||
|
||||
unsigned c = 1;
|
||||
|
||||
while(c < n)
|
||||
{
|
||||
std::swap(p0, p1);
|
||||
p1 = hermite_next(c, x, p0, p1);
|
||||
++c;
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
hermite(unsigned n, T x, const Policy&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::hermite_imp(n, static_cast<value_type>(x)), "boost::math::hermite<%1%>(unsigned, %1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type
|
||||
hermite(unsigned n, T x)
|
||||
{
|
||||
return boost::math::hermite(n, x, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_HERMITE_HPP
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// (C) Copyright John Maddock 2005.
|
||||
// (C) Copyright John Maddock 2005-2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -6,79 +6,76 @@
|
||||
#ifndef BOOST_MATH_HYPOT_INCLUDED
|
||||
#define BOOST_MATH_HYPOT_INCLUDED
|
||||
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <cmath>
|
||||
#include <boost/limits.hpp>
|
||||
#include <algorithm> // swap
|
||||
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
# include <boost/static_assert.hpp>
|
||||
#else
|
||||
# include <boost/assert.hpp>
|
||||
#endif
|
||||
#include <algorithm> // for swap
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std{ using ::sqrt; using ::fabs; }
|
||||
#endif
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
template <class T>
|
||||
T hypot(T x, T y)
|
||||
template <class T, class Policy>
|
||||
T hypot_imp(T x, T y, const Policy& pol)
|
||||
{
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized);
|
||||
#else
|
||||
BOOST_ASSERT(std::numeric_limits<T>::is_specialized);
|
||||
//
|
||||
// Normalize x and y, so that both are positive and x >= y:
|
||||
//
|
||||
using std::fabs; using std::sqrt; // ADL of std names
|
||||
|
||||
x = fabs(x);
|
||||
y = fabs(y);
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
|
||||
//
|
||||
// normalize x and y, so that both are positive and x >= y:
|
||||
//
|
||||
x = (std::fabs)(x);
|
||||
y = (std::fabs)(y);
|
||||
|
||||
// special case, see C99 Annex F:
|
||||
if(std::numeric_limits<T>::has_infinity
|
||||
&& ((x == std::numeric_limits<T>::infinity())
|
||||
|| (y == std::numeric_limits<T>::infinity())))
|
||||
return std::numeric_limits<T>::infinity();
|
||||
return policies::raise_overflow_error<T>("boost::math::hypot<%1%>(%1%,%1%)", 0, pol);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
if(y > x)
|
||||
if(y > x)
|
||||
(std::swap)(x, y);
|
||||
//
|
||||
// figure out overflow and underflow limits:
|
||||
//
|
||||
T safe_upper = (std::sqrt)((std::numeric_limits<T>::max)()) / 2;
|
||||
T safe_lower = (std::sqrt)((std::numeric_limits<T>::min)());
|
||||
static const T one = 1;
|
||||
//
|
||||
// Now handle special cases:
|
||||
//
|
||||
if(x >= safe_upper)
|
||||
{
|
||||
if(y <= one)
|
||||
{
|
||||
// y is neligible:
|
||||
return x;
|
||||
}
|
||||
return (std::sqrt)(x) * (std::sqrt)(y) * (std::sqrt)(x/y + y/x);
|
||||
}
|
||||
else if(y <= safe_lower)
|
||||
{
|
||||
if((x >= one) || (y == 0))
|
||||
{
|
||||
// y is negligible:
|
||||
return x;
|
||||
}
|
||||
return (std::sqrt)(x) * (std::sqrt)(y) * (std::sqrt)(x/y + y/x);
|
||||
}
|
||||
//
|
||||
// If we get here then x^2+y^2 will not overflow or underflow:
|
||||
//
|
||||
return (std::sqrt)(x*x + y*y);
|
||||
|
||||
if(x * tools::epsilon<T>() >= y)
|
||||
return x;
|
||||
|
||||
T rat = y / x;
|
||||
return x * sqrt(1 + rat*rat);
|
||||
} // template <class T> T hypot(T x, T y)
|
||||
|
||||
}
|
||||
|
||||
} } // namespaces
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
hypot(T1 x, T2 y)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
return detail::hypot_imp(
|
||||
static_cast<result_type>(x), static_cast<result_type>(y), policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
hypot(T1 x, T2 y, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
return detail::hypot_imp(
|
||||
static_cast<result_type>(x), static_cast<result_type>(y), pol);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_HYPOT_INCLUDED
|
||||
|
||||
|
||||
|
||||
134
include/boost/math/special_functions/laguerre.hpp
Normal file
134
include/boost/math/special_functions/laguerre.hpp
Normal file
@@ -0,0 +1,134 @@
|
||||
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_LAGUERRE_HPP
|
||||
#define BOOST_MATH_SPECIAL_LAGUERRE_HPP
|
||||
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace math{
|
||||
|
||||
// Recurrance relation for Laguerre polynomials:
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
laguerre_next(unsigned n, T1 x, T2 Ln, T3 Lnm1)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
|
||||
return ((2 * n + 1 - result_type(x)) * result_type(Ln) - n * result_type(Lnm1)) / (n + 1);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
|
||||
// Implement Laguerre polynomials via recurrance:
|
||||
template <class T>
|
||||
T laguerre_imp(unsigned n, T x)
|
||||
{
|
||||
T p0 = 1;
|
||||
T p1 = 1 - x;
|
||||
|
||||
if(n == 0)
|
||||
return p0;
|
||||
|
||||
unsigned c = 1;
|
||||
|
||||
while(c < n)
|
||||
{
|
||||
std::swap(p0, p1);
|
||||
p1 = laguerre_next(c, x, p0, p1);
|
||||
++c;
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
laguerre(unsigned n, T x, const Policy&, const mpl::true_&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::laguerre_imp(n, static_cast<value_type>(x)), "boost::math::laguerre<%1%>(unsigned, %1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type
|
||||
laguerre(unsigned n, unsigned m, T x, const mpl::false_&)
|
||||
{
|
||||
return boost::math::laguerre(n, m, x, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type
|
||||
laguerre(unsigned n, T x)
|
||||
{
|
||||
return laguerre(n, x, policies::policy<>());
|
||||
}
|
||||
|
||||
// Recurrence for associated polynomials:
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
laguerre_next(unsigned n, unsigned l, T1 x, T2 Pl, T3 Plm1)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
|
||||
return ((2 * n + l + 1 - result_type(x)) * result_type(Pl) - (n + l) * result_type(Plm1)) / (n+1);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
// Laguerre Associated Polynomial:
|
||||
template <class T, class Policy>
|
||||
T laguerre_imp(unsigned n, unsigned m, T x, const Policy& pol)
|
||||
{
|
||||
// Special cases:
|
||||
if(m == 0)
|
||||
return boost::math::laguerre(n, x, pol);
|
||||
|
||||
T p0 = 1;
|
||||
|
||||
if(n == 0)
|
||||
return p0;
|
||||
|
||||
T p1 = m + 1 - x;
|
||||
|
||||
unsigned c = 1;
|
||||
|
||||
while(c < n)
|
||||
{
|
||||
std::swap(p0, p1);
|
||||
p1 = laguerre_next(c, m, x, p0, p1);
|
||||
++c;
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
laguerre(unsigned n, unsigned m, T x, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::laguerre_imp(n, m, static_cast<value_type>(x), pol), "boost::math::laguerre<%1%>(unsigned, unsigned, %1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename laguerre_result<T1, T2>::type
|
||||
laguerre(unsigned n, T1 m, T2 x)
|
||||
{
|
||||
typedef typename policies::is_policy<T2>::type tag_type;
|
||||
return detail::laguerre(n, m, x, tag_type());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_LAGUERRE_HPP
|
||||
|
||||
|
||||
1231
include/boost/math/special_functions/lanczos.hpp
Normal file
1231
include/boost/math/special_functions/lanczos.hpp
Normal file
File diff suppressed because it is too large
Load Diff
189
include/boost/math/special_functions/legendre.hpp
Normal file
189
include/boost/math/special_functions/legendre.hpp
Normal file
@@ -0,0 +1,189 @@
|
||||
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_LEGENDRE_HPP
|
||||
#define BOOST_MATH_SPECIAL_LEGENDRE_HPP
|
||||
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/math/special_functions/factorials.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace math{
|
||||
|
||||
// Recurrance relation for legendre P and Q polynomials:
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
legendre_next(unsigned l, T1 x, T2 Pl, T3 Plm1)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
|
||||
return ((2 * l + 1) * result_type(x) * result_type(Pl) - l * result_type(Plm1)) / (l + 1);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
|
||||
// Implement Legendre P and Q polynomials via recurrance:
|
||||
template <class T, class Policy>
|
||||
T legendre_imp(unsigned l, T x, const Policy& pol, bool second = false)
|
||||
{
|
||||
static const char* function = "boost::math::legrendre_p<%1%>(unsigned, %1%)";
|
||||
// Error handling:
|
||||
if((x < -1) || (x > 1))
|
||||
return policies::raise_domain_error<T>(
|
||||
function,
|
||||
"The Legendre Polynomial is defined for"
|
||||
" -1 <= x <= 1, but got x = %1%.", x, pol);
|
||||
|
||||
T p0, p1;
|
||||
if(second)
|
||||
{
|
||||
// A solution of the second kind (Q):
|
||||
p0 = (boost::math::log1p(x, pol) - boost::math::log1p(-x, pol)) / 2;
|
||||
p1 = x * p0 - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// A solution of the first kind (P):
|
||||
p0 = 1;
|
||||
p1 = x;
|
||||
}
|
||||
if(l == 0)
|
||||
return p0;
|
||||
|
||||
unsigned n = 1;
|
||||
|
||||
while(n < l)
|
||||
{
|
||||
std::swap(p0, p1);
|
||||
p1 = boost::math::legendre_next(n, x, p0, p1);
|
||||
++n;
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
legendre_p(int l, T x, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
static const char* function = "boost::math::legendre_p<%1%>(unsigned, %1%)";
|
||||
if(l < 0)
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(-l-1, static_cast<value_type>(x), pol, false), function);
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(l, static_cast<value_type>(x), pol, false), function);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type
|
||||
legendre_p(int l, T x)
|
||||
{
|
||||
return boost::math::legendre_p(l, x, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
legendre_q(unsigned l, T x, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_imp(l, static_cast<value_type>(x), pol, true), "boost::math::legendre_q<%1%>(unsigned, %1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type
|
||||
legendre_q(unsigned l, T x)
|
||||
{
|
||||
return boost::math::legendre_q(l, x, policies::policy<>());
|
||||
}
|
||||
|
||||
// Recurrence for associated polynomials:
|
||||
template <class T1, class T2, class T3>
|
||||
inline typename tools::promote_args<T1, T2, T3>::type
|
||||
legendre_next(unsigned l, unsigned m, T1 x, T2 Pl, T3 Plm1)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2, T3>::type result_type;
|
||||
return ((2 * l + 1) * result_type(x) * result_type(Pl) - (l + m) * result_type(Plm1)) / (l + 1 - m);
|
||||
}
|
||||
|
||||
namespace detail{
|
||||
// Legendre P associated polynomial:
|
||||
template <class T, class Policy>
|
||||
T legendre_p_imp(int l, int m, T x, T sin_theta_power, const Policy& pol)
|
||||
{
|
||||
// Error handling:
|
||||
if((x < -1) || (x > 1))
|
||||
return policies::raise_domain_error<T>(
|
||||
"boost::math::legendre_p<%1%>(int, int, %1%)",
|
||||
"The associated Legendre Polynomial is defined for"
|
||||
" -1 <= x <= 1, but got x = %1%.", x, pol);
|
||||
// Handle negative arguments first:
|
||||
if(l < 0)
|
||||
return legendre_p_imp(-l-1, m, x, sin_theta_power, pol);
|
||||
if(m < 0)
|
||||
{
|
||||
int sign = (m&1) ? -1 : 1;
|
||||
return sign * boost::math::tgamma_ratio(static_cast<T>(l+m+1), static_cast<T>(l+1-m), pol) * legendre_p_imp(l, -m, x, sin_theta_power, pol);
|
||||
}
|
||||
// Special cases:
|
||||
if(m > l)
|
||||
return 0;
|
||||
if(m == 0)
|
||||
return boost::math::legendre_p(l, x, pol);
|
||||
|
||||
T p0 = boost::math::double_factorial<T>(2 * m - 1, pol) * sin_theta_power;
|
||||
|
||||
if(m&1)
|
||||
p0 *= -1;
|
||||
if(m == l)
|
||||
return p0;
|
||||
|
||||
T p1 = x * (2 * m + 1) * p0;
|
||||
|
||||
int n = m + 1;
|
||||
|
||||
while(n < l)
|
||||
{
|
||||
std::swap(p0, p1);
|
||||
p1 = boost::math::legendre_next(n, m, x, p0, p1);
|
||||
++n;
|
||||
}
|
||||
return p1;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T legendre_p_imp(int l, int m, T x, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
// TODO: we really could use that mythical "pow1p" function here:
|
||||
return legendre_p_imp(l, m, x, pow(1 - x*x, T(abs(m))/2), pol);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
legendre_p(int l, int m, T x, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::legendre_p_imp(l, m, static_cast<value_type>(x), pol), "bost::math::legendre_p<%1%>(int, int, %1%)");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type
|
||||
legendre_p(int l, int m, T x)
|
||||
{
|
||||
return boost::math::legendre_p(l, m, x, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_LEGENDRE_HPP
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// (C) Copyright John Maddock 2005.
|
||||
// (C) Copyright John Maddock 2005-2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -9,7 +9,10 @@
|
||||
#include <cmath>
|
||||
#include <math.h> // platform's ::log1p
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/math/special_functions/detail/series.hpp>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/series.hpp>
|
||||
#include <boost/math/policies/error_handling.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
# include <boost/static_assert.hpp>
|
||||
@@ -17,77 +20,90 @@
|
||||
# include <boost/assert.hpp>
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std{ using ::fabs; using ::log; }
|
||||
#endif
|
||||
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
namespace detail{
|
||||
|
||||
//
|
||||
// Functor log1p_series returns the next term in the Taylor series
|
||||
// pow(-1, k-1)*pow(x, k) / k
|
||||
// each time that operator() is invoked.
|
||||
//
|
||||
template <class T>
|
||||
struct log1p_series
|
||||
namespace detail
|
||||
{
|
||||
typedef T result_type;
|
||||
// Functor log1p_series returns the next term in the Taylor series
|
||||
// pow(-1, k-1)*pow(x, k) / k
|
||||
// each time that operator() is invoked.
|
||||
//
|
||||
template <class T>
|
||||
struct log1p_series
|
||||
{
|
||||
typedef T result_type;
|
||||
|
||||
log1p_series(T x)
|
||||
: k(0), m_mult(-x), m_prod(-1){}
|
||||
log1p_series(T x)
|
||||
: k(0), m_mult(-x), m_prod(-1){}
|
||||
|
||||
T operator()()
|
||||
{
|
||||
m_prod *= m_mult;
|
||||
return m_prod / ++k;
|
||||
}
|
||||
T operator()()
|
||||
{
|
||||
m_prod *= m_mult;
|
||||
return m_prod / ++k;
|
||||
}
|
||||
|
||||
int count()const
|
||||
{
|
||||
return k;
|
||||
}
|
||||
int count()const
|
||||
{
|
||||
return k;
|
||||
}
|
||||
|
||||
private:
|
||||
int k;
|
||||
const T m_mult;
|
||||
T m_prod;
|
||||
log1p_series(const log1p_series&);
|
||||
log1p_series& operator=(const log1p_series&);
|
||||
};
|
||||
private:
|
||||
int k;
|
||||
const T m_mult;
|
||||
T m_prod;
|
||||
log1p_series(const log1p_series&);
|
||||
log1p_series& operator=(const log1p_series&);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace detail
|
||||
|
||||
//
|
||||
// Algorithm log1p is part of C99, but is not yet provided by many compilers.
|
||||
//
|
||||
// This version uses a Taylor series expansion for 0.5 > x > epsilon, which may
|
||||
// require up to std::numeric_limits<T>::digits+1 terms to be calculated. It would
|
||||
// be much more efficient to use the equivalence:
|
||||
// log(1+x) == (log(1+x) * x) / ((1-x) - 1)
|
||||
// Unfortunately optimizing compilers make such a mess of this, that it performs
|
||||
// no better than log(1+x): which is to say not very well at all.
|
||||
// require up to std::numeric_limits<T>::digits+1 terms to be calculated.
|
||||
// It would be much more efficient to use the equivalence:
|
||||
// log(1+x) == (log(1+x) * x) / ((1-x) - 1)
|
||||
// Unfortunately many optimizing compilers make such a mess of this, that
|
||||
// it performs no better than log(1+x): which is to say not very well at all.
|
||||
//
|
||||
template <class T>
|
||||
T log1p(T x)
|
||||
{
|
||||
#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
|
||||
BOOST_STATIC_ASSERT(::std::numeric_limits<T>::is_specialized);
|
||||
#else
|
||||
BOOST_ASSERT(std::numeric_limits<T>::is_specialized);
|
||||
#endif
|
||||
T a = std::fabs(x);
|
||||
if(a > T(0.5L))
|
||||
return std::log(T(1.0) + x);
|
||||
if(a < std::numeric_limits<T>::epsilon())
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type log1p(T x, const Policy& pol)
|
||||
{ // The function returns the natural logarithm of 1 + x.
|
||||
// A domain error occurs if x < -1. TODO should there be a check?
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
BOOST_MATH_STD_USING
|
||||
using std::abs;
|
||||
|
||||
static const char* function = "boost::math::log1p<%1%>(%1%)";
|
||||
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<T>(
|
||||
function, "log1p(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<T>(
|
||||
function, 0, pol);
|
||||
|
||||
result_type a = abs(result_type(x));
|
||||
if(a > result_type(0.5L))
|
||||
return log(1 + result_type(x));
|
||||
// Note that without numeric_limits specialisation support,
|
||||
// epsilon just returns zero, and our "optimisation" will always fail:
|
||||
if(a < tools::epsilon<result_type>())
|
||||
return x;
|
||||
detail::log1p_series<T> s(x);
|
||||
return detail::kahan_sum_series(s, std::numeric_limits<T>::digits + 2);
|
||||
detail::log1p_series<result_type> s(x);
|
||||
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
result_type result = tools::sum_series(s, policies::digits<result_type, Policy>(), max_iter);
|
||||
#else
|
||||
result_type zero = 0;
|
||||
result_type result = tools::sum_series(s, policies::digits<result_type, Policy>(), max_iter, zero);
|
||||
#endif
|
||||
policies::check_series_iterations(function, max_iter, pol);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
|
||||
// these overloads work around a type deduction bug:
|
||||
// These overloads work around a type deduction bug:
|
||||
inline float log1p(float z)
|
||||
{
|
||||
return log1p<float>(z);
|
||||
@@ -96,11 +112,13 @@ inline double log1p(double z)
|
||||
{
|
||||
return log1p<double>(z);
|
||||
}
|
||||
#ifndef BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
inline long double log1p(long double z)
|
||||
{
|
||||
return log1p<long double>(z);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef log1p
|
||||
# ifndef BOOST_HAS_LOG1P
|
||||
@@ -110,15 +128,150 @@ inline long double log1p(long double z)
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_HAS_LOG1P
|
||||
# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)
|
||||
inline float log1p(float x){ return ::log1pf(x); }
|
||||
inline long double log1p(long double x){ return ::log1pl(x); }
|
||||
# if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901)) \
|
||||
|| ((defined(linux) || defined(__linux) || defined(__linux__)) && !defined(__SUNPRO_CC)) \
|
||||
|| (defined(__hpux) && !defined(__hppa))
|
||||
template <class Policy>
|
||||
inline float log1p(float x, const Policy& pol)
|
||||
{
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<float>(
|
||||
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<float>(
|
||||
"log1p<%1%>(%1%)", 0, pol);
|
||||
return ::log1pf(x);
|
||||
}
|
||||
template <class Policy>
|
||||
inline long double log1p(long double x, const Policy& pol)
|
||||
{
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<long double>(
|
||||
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<long double>(
|
||||
"log1p<%1%>(%1%)", 0, pol);
|
||||
return ::log1pl(x);
|
||||
}
|
||||
#else
|
||||
inline float log1p(float x){ return ::log1p(x); }
|
||||
template <class Policy>
|
||||
inline float log1p(float x, const Policy& pol)
|
||||
{
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<float>(
|
||||
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<float>(
|
||||
"log1p<%1%>(%1%)", 0, pol);
|
||||
return ::log1p(x);
|
||||
}
|
||||
#endif
|
||||
inline double log1p(double x){ return ::log1p(x); }
|
||||
template <class Policy>
|
||||
inline double log1p(double x, const Policy& pol)
|
||||
{
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<double>(
|
||||
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<double>(
|
||||
"log1p<%1%>(%1%)", 0, pol);
|
||||
return ::log1p(x);
|
||||
}
|
||||
#elif defined(_MSC_VER) && (BOOST_MSVC >= 1400)
|
||||
//
|
||||
// You should only enable this branch if you are absolutely sure
|
||||
// that your compilers optimizer won't mess this code up!!
|
||||
// Currently tested with VC8 and Intel 9.1.
|
||||
//
|
||||
template <class Policy>
|
||||
inline double log1p(double x, const Policy& pol)
|
||||
{
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<double>(
|
||||
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<double>(
|
||||
"log1p<%1%>(%1%)", 0, pol);
|
||||
double u = 1+x;
|
||||
if(u == 1.0)
|
||||
return x;
|
||||
else
|
||||
return log(u)*(x/(u-1.0));
|
||||
}
|
||||
template <class Policy>
|
||||
inline float log1p(float x, const Policy& pol)
|
||||
{
|
||||
return static_cast<float>(boost::math::log1p(static_cast<double>(x), pol));
|
||||
}
|
||||
template <class Policy>
|
||||
inline long double log1p(long double x, const Policy& pol)
|
||||
{
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<long double>(
|
||||
"log1p<%1%>(%1%)", "log1p(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<long double>(
|
||||
"log1p<%1%>(%1%)", 0, pol);
|
||||
long double u = 1+x;
|
||||
if(u == 1.0)
|
||||
return x;
|
||||
else
|
||||
return log(u)*(x/(u-1.0));
|
||||
}
|
||||
#endif
|
||||
|
||||
} } // namespaces
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type log1p(T x)
|
||||
{
|
||||
return boost::math::log1p(x, policies::policy<>());
|
||||
}
|
||||
//
|
||||
// Compute log(1+x)-x:
|
||||
//
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type
|
||||
log1pmx(T x, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
BOOST_MATH_STD_USING
|
||||
static const char* function = "boost::math::log1pmx<%1%>(%1%)";
|
||||
|
||||
if(x < -1)
|
||||
return policies::raise_domain_error<T>(
|
||||
function, "log1pmx(x) requires x > -1, but got x = %1%.", x, pol);
|
||||
if(x == -1)
|
||||
return -policies::raise_overflow_error<T>(
|
||||
function, 0, pol);
|
||||
|
||||
result_type a = abs(result_type(x));
|
||||
if(a > result_type(0.95L))
|
||||
return log(1 + result_type(x)) - result_type(x);
|
||||
// Note that without numeric_limits specialisation support,
|
||||
// epsilon just returns zero, and our "optimisation" will always fail:
|
||||
if(a < tools::epsilon<result_type>())
|
||||
return -x * x / 2;
|
||||
boost::math::detail::log1p_series<T> s(x);
|
||||
s();
|
||||
boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
T zero = 0;
|
||||
T result = boost::math::tools::sum_series(s, policies::digits<T, Policy>(), max_iter, zero);
|
||||
#else
|
||||
T result = boost::math::tools::sum_series(s, policies::digits<T, Policy>(), max_iter);
|
||||
#endif
|
||||
policies::check_series_iterations(function, max_iter, pol);
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T log1pmx(T x)
|
||||
{
|
||||
return log1pmx(x, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_LOG1P_INCLUDED
|
||||
|
||||
|
||||
#endif // BOOST_MATH_HYPOT_INCLUDED
|
||||
|
||||
912
include/boost/math/special_functions/math_fwd.hpp
Normal file
912
include/boost/math/special_functions/math_fwd.hpp
Normal file
@@ -0,0 +1,912 @@
|
||||
// math_fwd.hpp
|
||||
|
||||
// TODO revise completely for new distribution classes.
|
||||
|
||||
// Copyright Paul A. Bristow 2006.
|
||||
// Copyright John Maddock 2006.
|
||||
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// Omnibus list of forward declarations of math special functions.
|
||||
|
||||
// IT = Integer type.
|
||||
// RT = Real type (built-in floating-point types, float, double, long double) & User Defined Types
|
||||
// AT = Integer or Real type
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_MATH_FWD_HPP
|
||||
#define BOOST_MATH_SPECIAL_MATH_FWD_HPP
|
||||
|
||||
#include <boost/math/tools/promotion.hpp> // for argument promotion.
|
||||
#include <boost/math/policies/policy.hpp>
|
||||
#include <boost/mpl/comparison.hpp>
|
||||
#include <boost/config/no_tr1/complex.hpp>
|
||||
|
||||
#define BOOST_NO_MACRO_EXPAND /**/
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace math
|
||||
{ // Math functions (in roughly alphabetic order).
|
||||
|
||||
// Beta functions.
|
||||
template <class RT1, class RT2>
|
||||
typename tools::promote_args<RT1, RT2>::type
|
||||
beta(RT1 a, RT2 b); // Beta function (2 arguments).
|
||||
|
||||
template <class RT1, class RT2, class A>
|
||||
typename tools::promote_args<RT1, RT2, A>::type
|
||||
beta(RT1 a, RT2 b, A x); // Beta function (3 arguments).
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
beta(RT1 a, RT2 b, RT3 x, const Policy& pol); // Beta function (3 arguments).
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
betac(RT1 a, RT2 b, RT3 x);
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
betac(RT1 a, RT2 b, RT3 x, const Policy& pol);
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta(RT1 a, RT2 b, RT3 x); // Incomplete beta function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta(RT1 a, RT2 b, RT3 x, const Policy& pol); // Incomplete beta function.
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac(RT1 a, RT2 b, RT3 x); // Incomplete beta complement function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac(RT1 a, RT2 b, RT3 x, const Policy& pol); // Incomplete beta complement function.
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibeta_inv(T1 a, T2 b, T3 p, T4* py);
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class Policy>
|
||||
typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibeta_inv(T1 a, T2 b, T3 p, T4* py, const Policy& pol);
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_inv(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_inv(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_inva(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_inva(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_invb(RT1 a, RT2 b, RT3 p); // Incomplete beta inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_invb(RT1 a, RT2 b, RT3 p, const Policy&); // Incomplete beta inverse function.
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibetac_inv(T1 a, T2 b, T3 q, T4* py);
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class Policy>
|
||||
typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ibetac_inv(T1 a, T2 b, T3 q, T4* py, const Policy& pol);
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac_inv(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac_inv(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac_inva(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac_inva(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac_invb(RT1 a, RT2 b, RT3 q); // Incomplete beta complement inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibetac_invb(RT1 a, RT2 b, RT3 q, const Policy&); // Incomplete beta complement inverse function.
|
||||
|
||||
template <class RT1, class RT2, class RT3>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_derivative(RT1 a, RT2 b, RT3 x); // derivative of incomplete beta
|
||||
|
||||
template <class RT1, class RT2, class RT3, class Policy>
|
||||
typename tools::promote_args<RT1, RT2, RT3>::type
|
||||
ibeta_derivative(RT1 a, RT2 b, RT3 x, const Policy& pol); // derivative of incomplete beta
|
||||
|
||||
// erf & erfc error functions.
|
||||
template <class RT> // Error function.
|
||||
typename tools::promote_args<RT>::type erf(RT z);
|
||||
template <class RT, class Policy> // Error function.
|
||||
typename tools::promote_args<RT>::type erf(RT z, const Policy&);
|
||||
|
||||
template <class RT>// Error function complement.
|
||||
typename tools::promote_args<RT>::type erfc(RT z);
|
||||
template <class RT, class Policy>// Error function complement.
|
||||
typename tools::promote_args<RT>::type erfc(RT z, const Policy&);
|
||||
|
||||
template <class RT>// Error function inverse.
|
||||
typename tools::promote_args<RT>::type erf_inv(RT z);
|
||||
template <class RT, class Policy>// Error function inverse.
|
||||
typename tools::promote_args<RT>::type erf_inv(RT z, const Policy& pol);
|
||||
|
||||
template <class RT>// Error function complement inverse.
|
||||
typename tools::promote_args<RT>::type erfc_inv(RT z);
|
||||
template <class RT, class Policy>// Error function complement inverse.
|
||||
typename tools::promote_args<RT>::type erfc_inv(RT z, const Policy& pol);
|
||||
|
||||
// Polynomials:
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
legendre_next(unsigned l, T1 x, T2 Pl, T3 Plm1);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type
|
||||
legendre_p(int l, T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type
|
||||
legendre_p(int l, T x, const Policy& pol);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type
|
||||
legendre_q(unsigned l, T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type
|
||||
legendre_q(unsigned l, T x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
legendre_next(unsigned l, unsigned m, T1 x, T2 Pl, T3 Plm1);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type
|
||||
legendre_p(int l, int m, T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type
|
||||
legendre_p(int l, int m, T x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
laguerre_next(unsigned n, T1 x, T2 Ln, T3 Lnm1);
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
laguerre_next(unsigned n, unsigned l, T1 x, T2 Pl, T3 Plm1);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type
|
||||
laguerre(unsigned n, T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type
|
||||
laguerre(unsigned n, unsigned m, T x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
struct laguerre_result
|
||||
{
|
||||
typedef typename mpl::if_<
|
||||
policies::is_policy<T2>,
|
||||
typename tools::promote_args<T1>::type,
|
||||
typename tools::promote_args<T2>::type
|
||||
>::type type;
|
||||
};
|
||||
|
||||
template <class T1, class T2>
|
||||
typename laguerre_result<T1, T2>::type
|
||||
laguerre(unsigned n, T1 m, T2 x);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type
|
||||
hermite(unsigned n, T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type
|
||||
hermite(unsigned n, T x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
hermite_next(unsigned n, T1 x, T2 Hn, T3 Hnm1);
|
||||
|
||||
template <class T1, class T2>
|
||||
std::complex<typename tools::promote_args<T1, T2>::type>
|
||||
spherical_harmonic(unsigned n, int m, T1 theta, T2 phi);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
std::complex<typename tools::promote_args<T1, T2>::type>
|
||||
spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);
|
||||
|
||||
// Elliptic integrals:
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rf(T1 x, T2 y, T3 z);
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rf(T1 x, T2 y, T3 z, const Policy& pol);
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rd(T1 x, T2 y, T3 z);
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
typename tools::promote_args<T1, T2, T3>::type
|
||||
ellint_rd(T1 x, T2 y, T3 z, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
ellint_rc(T1 x, T2 y);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
ellint_rc(T1 x, T2 y, const Policy& pol);
|
||||
|
||||
template <class T1, class T2, class T3, class T4>
|
||||
typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ellint_rj(T1 x, T2 y, T3 z, T4 p);
|
||||
|
||||
template <class T1, class T2, class T3, class T4, class Policy>
|
||||
typename tools::promote_args<T1, T2, T3, T4>::type
|
||||
ellint_rj(T1 x, T2 y, T3 z, T4 p, const Policy& pol);
|
||||
|
||||
template <typename T>
|
||||
typename tools::promote_args<T>::type ellint_2(T k);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi, const Policy& pol);
|
||||
|
||||
template <typename T>
|
||||
typename tools::promote_args<T>::type ellint_1(T k);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi, const Policy& pol);
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi);
|
||||
|
||||
template <class T1, class T2, class T3, class Policy>
|
||||
typename tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v);
|
||||
|
||||
// Factorial functions.
|
||||
// Note: not for integral types, at present.
|
||||
template <class RT>
|
||||
struct max_factorial;
|
||||
template <class RT>
|
||||
RT factorial(unsigned int);
|
||||
template <class RT, class Policy>
|
||||
RT factorial(unsigned int, const Policy& pol);
|
||||
template <class RT>
|
||||
RT unchecked_factorial(unsigned int BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(RT));
|
||||
template <class RT>
|
||||
RT double_factorial(unsigned i);
|
||||
template <class RT, class Policy>
|
||||
RT double_factorial(unsigned i, const Policy& pol);
|
||||
|
||||
template <class RT>
|
||||
typename tools::promote_args<RT>::type falling_factorial(RT x, unsigned n);
|
||||
|
||||
template <class RT, class Policy>
|
||||
typename tools::promote_args<RT>::type falling_factorial(RT x, unsigned n, const Policy& pol);
|
||||
|
||||
template <class RT>
|
||||
typename tools::promote_args<RT>::type rising_factorial(RT x, int n);
|
||||
|
||||
template <class RT, class Policy>
|
||||
typename tools::promote_args<RT>::type rising_factorial(RT x, int n, const Policy& pol);
|
||||
|
||||
// Gamma functions.
|
||||
template <class RT>
|
||||
typename tools::promote_args<RT>::type tgamma(RT z);
|
||||
|
||||
template <class RT>
|
||||
typename tools::promote_args<RT>::type tgamma1pm1(RT z);
|
||||
|
||||
template <class RT, class Policy>
|
||||
typename tools::promote_args<RT>::type tgamma1pm1(RT z, const Policy& pol);
|
||||
|
||||
template <class RT1, class RT2>
|
||||
typename tools::promote_args<RT1, RT2>::type tgamma(RT1 a, RT2 z);
|
||||
|
||||
template <class RT1, class RT2, class Policy>
|
||||
typename tools::promote_args<RT1, RT2>::type tgamma(RT1 a, RT2 z, const Policy& pol);
|
||||
|
||||
template <class RT>
|
||||
typename tools::promote_args<RT>::type lgamma(RT z, int* sign);
|
||||
|
||||
template <class RT, class Policy>
|
||||
typename tools::promote_args<RT>::type lgamma(RT z, int* sign, const Policy& pol);
|
||||
|
||||
template <class RT>
|
||||
typename tools::promote_args<RT>::type lgamma(RT x);
|
||||
|
||||
template <class RT, class Policy>
|
||||
typename tools::promote_args<RT>::type lgamma(RT x, const Policy& pol);
|
||||
|
||||
template <class RT1, class RT2>
|
||||
typename tools::promote_args<RT1, RT2>::type tgamma_lower(RT1 a, RT2 z);
|
||||
|
||||
template <class RT1, class RT2, class Policy>
|
||||
typename tools::promote_args<RT1, RT2>::type tgamma_lower(RT1 a, RT2 z, const Policy&);
|
||||
|
||||
template <class RT1, class RT2>
|
||||
typename tools::promote_args<RT1, RT2>::type gamma_q(RT1 a, RT2 z);
|
||||
|
||||
template <class RT1, class RT2, class Policy>
|
||||
typename tools::promote_args<RT1, RT2>::type gamma_q(RT1 a, RT2 z, const Policy&);
|
||||
|
||||
template <class RT1, class RT2>
|
||||
typename tools::promote_args<RT1, RT2>::type gamma_p(RT1 a, RT2 z);
|
||||
|
||||
template <class RT1, class RT2, class Policy>
|
||||
typename tools::promote_args<RT1, RT2>::type gamma_p(RT1 a, RT2 z, const Policy&);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type tgamma_delta_ratio(T1 z, T2 delta);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type tgamma_delta_ratio(T1 z, T2 delta, const Policy&);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type tgamma_ratio(T1 a, T2 b);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type tgamma_ratio(T1 a, T2 b, const Policy&);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type gamma_p_derivative(T1 a, T2 x);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type gamma_p_derivative(T1 a, T2 x, const Policy&);
|
||||
|
||||
// gamma inverse.
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type gamma_p_inv(T1 a, T2 p);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type gamma_p_inva(T1 a, T2 p, const Policy&);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type gamma_p_inva(T1 a, T2 p);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type gamma_p_inv(T1 a, T2 p, const Policy&);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type gamma_q_inv(T1 a, T2 q);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type gamma_q_inv(T1 a, T2 q, const Policy&);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type gamma_q_inva(T1 a, T2 q);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type gamma_q_inva(T1 a, T2 q, const Policy&);
|
||||
|
||||
// digamma:
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type digamma(T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type digamma(T x, const Policy&);
|
||||
|
||||
// Hypotenuse function sqrt(x ^ 2 + y ^ 2).
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
hypot(T1 x, T2 y);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
hypot(T1 x, T2 y, const Policy&);
|
||||
|
||||
// cbrt - cube root.
|
||||
template <class RT>
|
||||
typename tools::promote_args<RT>::type cbrt(RT z);
|
||||
|
||||
template <class RT, class Policy>
|
||||
typename tools::promote_args<RT>::type cbrt(RT z, const Policy&);
|
||||
|
||||
// log1p is log(x + 1)
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type log1p(T);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type log1p(T, const Policy&);
|
||||
|
||||
// log1pmx is log(x + 1) - x
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type log1pmx(T);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type log1pmx(T, const Policy&);
|
||||
|
||||
// Exp (x) minus 1 functions.
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type expm1(T);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type expm1(T, const Policy&);
|
||||
|
||||
// Power - 1
|
||||
template <class T1, class T2>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
powm1(const T1 a, const T2 z);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename tools::promote_args<T1, T2>::type
|
||||
powm1(const T1 a, const T2 z, const Policy&);
|
||||
|
||||
// sqrt(1+x) - 1
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type sqrt1pm1(const T& val);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type sqrt1pm1(const T& val, const Policy&);
|
||||
|
||||
// sinus cardinals:
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type sinc_pi(T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type sinc_pi(T x, const Policy&);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type sinhc_pi(T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type sinhc_pi(T x, const Policy&);
|
||||
|
||||
// inverse hyperbolics:
|
||||
template<typename T>
|
||||
typename tools::promote_args<T>::type asinh(const T x);
|
||||
|
||||
template<typename T, class Policy>
|
||||
typename tools::promote_args<T>::type asinh(const T x, const Policy&);
|
||||
|
||||
template<typename T>
|
||||
typename tools::promote_args<T>::type acosh(const T x);
|
||||
|
||||
template<typename T, class Policy>
|
||||
typename tools::promote_args<T>::type acosh(const T x, const Policy&);
|
||||
|
||||
template<typename T>
|
||||
typename tools::promote_args<T>::type atanh(const T x);
|
||||
|
||||
template<typename T, class Policy>
|
||||
typename tools::promote_args<T>::type atanh(const T x, const Policy&);
|
||||
|
||||
namespace detail{
|
||||
|
||||
typedef mpl::int_<0> bessel_no_int_tag; // No integer optimisation possible.
|
||||
typedef mpl::int_<1> bessel_maybe_int_tag; // Maybe integer optimisation.
|
||||
typedef mpl::int_<2> bessel_int_tag; // Definite integer optimistaion.
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
struct bessel_traits
|
||||
{
|
||||
typedef typename tools::promote_args<
|
||||
T1, T2
|
||||
>::type result_type;
|
||||
|
||||
typedef typename policies::precision<result_type, Policy>::type precision_type;
|
||||
|
||||
typedef typename mpl::if_<
|
||||
mpl::or_<
|
||||
mpl::less_equal<precision_type, mpl::int_<0> >,
|
||||
mpl::greater<precision_type, mpl::int_<64> > >,
|
||||
bessel_no_int_tag,
|
||||
typename mpl::if_<
|
||||
is_integral<T1>,
|
||||
bessel_int_tag,
|
||||
bessel_maybe_int_tag
|
||||
>::type
|
||||
>::type optimisation_tag;
|
||||
};
|
||||
} // detail
|
||||
|
||||
// Bessel functions:
|
||||
template <class T1, class T2, class Policy>
|
||||
typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_j(T1 v, T2 x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_j(T1 v, T2 x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename detail::bessel_traits<T, T, Policy>::result_type sph_bessel(unsigned v, T x, const Policy& pol);
|
||||
|
||||
template <class T>
|
||||
typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_bessel(unsigned v, T x);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_i(T1 v, T2 x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_i(T1 v, T2 x);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_bessel_k(T1 v, T2 x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_bessel_k(T1 v, T2 x);
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
typename detail::bessel_traits<T1, T2, Policy>::result_type cyl_neumann(T1 v, T2 x, const Policy& pol);
|
||||
|
||||
template <class T1, class T2>
|
||||
typename detail::bessel_traits<T1, T2, policies::policy<> >::result_type cyl_neumann(T1 v, T2 x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename detail::bessel_traits<T, T, Policy>::result_type sph_neumann(unsigned v, T x, const Policy& pol);
|
||||
|
||||
template <class T>
|
||||
typename detail::bessel_traits<T, T, policies::policy<> >::result_type sph_neumann(unsigned v, T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type sin_pi(T x, const Policy&);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type sin_pi(T x);
|
||||
|
||||
template <class T, class Policy>
|
||||
typename tools::promote_args<T>::type cos_pi(T x, const Policy&);
|
||||
|
||||
template <class T>
|
||||
typename tools::promote_args<T>::type cos_pi(T x);
|
||||
|
||||
template <class T>
|
||||
int fpclassify BOOST_NO_MACRO_EXPAND(T t);
|
||||
|
||||
template <class T>
|
||||
bool isfinite BOOST_NO_MACRO_EXPAND(T z);
|
||||
|
||||
template <class T>
|
||||
bool isinf BOOST_NO_MACRO_EXPAND(T t);
|
||||
|
||||
template <class T>
|
||||
bool isnan BOOST_NO_MACRO_EXPAND(T t);
|
||||
|
||||
template <class T>
|
||||
bool isnormal BOOST_NO_MACRO_EXPAND(T t);
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#define BOOST_MATH_DECLARE_SPECIAL_FUNCTIONS(Policy)\
|
||||
template <class RT1, class RT2>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2>::type \
|
||||
beta(RT1 a, RT2 b) { return ::boost::math::beta(a, b, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class A>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, A>::type \
|
||||
beta(RT1 a, RT2 b, A x){ return ::boost::math::beta(a, b, x, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
betac(RT1 a, RT2 b, RT3 x) { return ::boost::math::betac(a, b, x, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
ibeta(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibeta(a, b, x, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
ibetac(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibetac(a, b, x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class T3, class T4>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3, T4>::type \
|
||||
ibeta_inv(T1 a, T2 b, T3 p, T4* py){ return ::boost::math::ibeta_inv(a, b, p, py, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
ibeta_inv(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_inv(a, b, p, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class T3, class T4>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3, T4>::type \
|
||||
ibetac_inv(T1 a, T2 b, T3 q, T4* py){ return ::boost::math::ibetac_inv(a, b, q, py, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
ibeta_inva(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_inva(a, b, p, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class T3>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
|
||||
ibetac_inva(T1 a, T2 b, T3 q){ return ::boost::math::ibetac_inva(a, b, q, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
ibeta_invb(RT1 a, RT2 b, RT3 p){ return ::boost::math::ibeta_invb(a, b, p, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class T3>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
|
||||
ibetac_invb(T1 a, T2 b, T3 q){ return ::boost::math::ibetac_invb(a, b, q, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
ibetac_inv(RT1 a, RT2 b, RT3 q){ return ::boost::math::ibetac_inv(a, b, q, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2, class RT3>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2, RT3>::type \
|
||||
ibeta_derivative(RT1 a, RT2 b, RT3 x){ return ::boost::math::ibeta_derivative(a, b, x, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type erf(RT z) { return ::boost::math::erf(z, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type erfc(RT z){ return ::boost::math::erfc(z, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type erf_inv(RT z) { return ::boost::math::erf_inv(z, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type erfc_inv(RT z){ return ::boost::math::erfc_inv(z, Policy()); }\
|
||||
\
|
||||
using boost::math::legendre_next;\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type \
|
||||
legendre_p(int l, T x){ return ::boost::math::legendre_p(l, x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type \
|
||||
legendre_q(unsigned l, T x){ return ::boost::math::legendre_q(l, x, Policy()); }\
|
||||
\
|
||||
using ::boost::math::legendre_next;\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type \
|
||||
legendre_p(int l, int m, T x){ return ::boost::math::legendre_p(l, m, x, Policy()); }\
|
||||
\
|
||||
using ::boost::math::laguerre_next;\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type \
|
||||
laguerre(unsigned n, T x){ return ::boost::math::laguerre(n, x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::laguerre_result<T1, T2>::type \
|
||||
laguerre(unsigned n, T1 m, T2 x) { return ::boost::math::laguerre(n, m, x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type \
|
||||
hermite(unsigned n, T x){ return ::boost::math::hermite(n, x, Policy()); }\
|
||||
\
|
||||
using boost::math::hermite_next;\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline std::complex<typename boost::math::tools::promote_args<T1, T2>::type> \
|
||||
spherical_harmonic(unsigned n, int m, T1 theta, T2 phi){ return boost::math::spherical_harmonic(n, m, theta, phi, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type \
|
||||
spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi){ return ::boost::math::spherical_harmonic_r(n, m, theta, phi, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type \
|
||||
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi){ return boost::math::spherical_harmonic_i(n, m, theta, phi, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class Policy>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type \
|
||||
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol);\
|
||||
\
|
||||
template <class T1, class T2, class T3>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
|
||||
ellint_rf(T1 x, T2 y, T3 z){ return ::boost::math::ellint_rf(x, y, z, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class T3>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3>::type \
|
||||
ellint_rd(T1 x, T2 y, T3 z){ return ::boost::math::ellint_rd(x, y, z, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type \
|
||||
ellint_rc(T1 x, T2 y){ return ::boost::math::ellint_rc(x, y, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class T3, class T4>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3, T4>::type \
|
||||
ellint_rj(T1 x, T2 y, T3 z, T4 p){ return boost::math::ellint_rj(x, y, z, p, Policy()); }\
|
||||
\
|
||||
template <typename T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type ellint_2(T k){ return boost::math::ellint_2(k, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type ellint_2(T1 k, T2 phi){ return boost::math::ellint_2(k, phi, Policy()); }\
|
||||
\
|
||||
template <typename T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type ellint_1(T k){ return boost::math::ellint_1(k, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type ellint_1(T1 k, T2 phi){ return boost::math::ellint_1(k, phi, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2, class T3>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2, T3>::type ellint_3(T1 k, T2 v, T3 phi){ return boost::math::ellint_3(k, v, phi, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type ellint_3(T1 k, T2 v){ return boost::math::ellint_3(k, v, Policy()); }\
|
||||
\
|
||||
using boost::math::max_factorial;\
|
||||
template <class RT>\
|
||||
inline RT factorial(unsigned int i) { return boost::math::factorial<RT>(i, Policy()); }\
|
||||
using boost::math::unchecked_factorial;\
|
||||
template <class RT>\
|
||||
inline RT double_factorial(unsigned i){ return boost::math::double_factorial<RT>(i, Policy()); }\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type falling_factorial(RT x, unsigned n){ return boost::math::falling_factorial(x, n, Policy()); }\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type rising_factorial(RT x, unsigned n){ return boost::math::rising_factorial(x, n, Policy()); }\
|
||||
using boost::math::fpclassify;\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type tgamma(RT z){ return boost::math::tgamma(z, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type tgamma1pm1(RT z){ return boost::math::tgamma1pm1(z, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2>::type tgamma(RT1 a, RT2 z){ return boost::math::tgamma(a, z, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type lgamma(RT z, int* sign){ return boost::math::lgamma(z, sign, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type lgamma(RT x){ return boost::math::lgamma(x, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2>::type tgamma_lower(RT1 a, RT2 z){ return boost::math::tgamma_lower(a, z, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2>::type gamma_q(RT1 a, RT2 z){ return boost::math::gamma_q(a, z, Policy()); }\
|
||||
\
|
||||
template <class RT1, class RT2>\
|
||||
inline typename boost::math::tools::promote_args<RT1, RT2>::type gamma_p(RT1 a, RT2 z){ return boost::math::gamma_p(a, z, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type tgamma_delta_ratio(T1 z, T2 delta){ return boost::math::tgamma_delta_ratio(z, delta, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type tgamma_ratio(T1 a, T2 b) { return boost::math::tgamma_ratio(a, b, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type gamma_p_derivative(T1 a, T2 x){ return boost::math::gamma_p_derivative(a, x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type gamma_p_inv(T1 a, T2 p){ return boost::math::gamma_p_inv(a, p, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type gamma_p_inva(T1 a, T2 p){ return boost::math::gamma_p_inva(a, p, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type gamma_q_inv(T1 a, T2 q){ return boost::math::gamma_q_inv(a, q, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type gamma_q_inva(T1 a, T2 q){ return boost::math::gamma_q_inva(a, q, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type digamma(T x){ return boost::math::digamma(x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type \
|
||||
hypot(T1 x, T2 y){ return boost::math::hypot(x, y, Policy()); }\
|
||||
\
|
||||
template <class RT>\
|
||||
inline typename boost::math::tools::promote_args<RT>::type cbrt(RT z){ return boost::math::cbrt(z, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type log1p(T x){ return boost::math::log1p(x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type log1pmx(T x){ return boost::math::log1pmx(x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type expm1(T x){ return boost::math::expm1(x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::tools::promote_args<T1, T2>::type \
|
||||
powm1(const T1 a, const T2 z){ return boost::math::powm1(a, z, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type sqrt1pm1(const T& val){ return boost::math::sqrt1pm1(val, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type sinc_pi(T x){ return boost::math::sinc_pi(x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type sinhc_pi(T x){ return boost::math::sinhc_pi(x, Policy()); }\
|
||||
\
|
||||
template<typename T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type asinh(const T x){ return boost::math::asinh(x, Policy()); }\
|
||||
\
|
||||
template<typename T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type acosh(const T x){ return boost::math::acosh(x, Policy()); }\
|
||||
\
|
||||
template<typename T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type atanh(const T x){ return boost::math::atanh(x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type cyl_bessel_j(T1 v, T2 x)\
|
||||
{ return boost::math::cyl_bessel_j(v, x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::detail::bessel_traits<T, T, Policy >::result_type sph_bessel(unsigned v, T x)\
|
||||
{ return boost::math::sph_bessel(v, x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type \
|
||||
cyl_bessel_i(T1 v, T2 x) { return boost::math::cyl_bessel_i(v, x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type \
|
||||
cyl_bessel_k(T1 v, T2 x) { return boost::math::cyl_bessel_k(v, x, Policy()); }\
|
||||
\
|
||||
template <class T1, class T2>\
|
||||
inline typename boost::math::detail::bessel_traits<T1, T2, Policy >::result_type \
|
||||
cyl_neumann(T1 v, T2 x){ return boost::math::cyl_neumann(v, x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::detail::bessel_traits<T, T, Policy >::result_type \
|
||||
sph_neumann(unsigned v, T x){ return boost::math::sph_neumann(v, x, Policy()); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type sin_pi(T x){ return boost::math::sin_pi(x); }\
|
||||
\
|
||||
template <class T>\
|
||||
inline typename boost::math::tools::promote_args<T>::type cos_pi(T x){ return boost::math::cos_pi(x); }\
|
||||
\
|
||||
using boost::math::fpclassify;\
|
||||
using boost::math::isfinite;\
|
||||
using boost::math::isinf;\
|
||||
using boost::math::isnan;\
|
||||
using boost::math::isnormal;
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_MATH_FWD_HPP
|
||||
56
include/boost/math/special_functions/powm1.hpp
Normal file
56
include/boost/math/special_functions/powm1.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_POWM1
|
||||
#define BOOST_MATH_POWM1
|
||||
|
||||
#include <boost/math/special_functions/log1p.hpp>
|
||||
#include <boost/math/special_functions/expm1.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
template <class T, class Policy>
|
||||
inline T powm1_imp(const T a, const T z, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
if((fabs(a) < 1) || (fabs(z) < 1))
|
||||
{
|
||||
T p = log(a) * z;
|
||||
if(fabs(p) < 2)
|
||||
return boost::math::expm1(p, pol);
|
||||
// otherwise fall though:
|
||||
}
|
||||
return pow(a, z) - 1;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
powm1(const T1 a, const T2 z)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
return detail::powm1_imp(static_cast<result_type>(a), static_cast<result_type>(z), policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
powm1(const T1 a, const T2 z, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
return detail::powm1_imp(static_cast<result_type>(a), static_cast<result_type>(z), pol);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_POWM1
|
||||
|
||||
|
||||
|
||||
|
||||
38
include/boost/math/special_functions/sign.hpp
Normal file
38
include/boost/math/special_functions/sign.hpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_TOOLS_SIGN_HPP
|
||||
#define BOOST_MATH_TOOLS_SIGN_HPP
|
||||
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
template <class T>
|
||||
inline int sign BOOST_NO_MACRO_EXPAND(const T& z)
|
||||
{
|
||||
return (z == 0) ? 0 : (z < 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline int signbit BOOST_NO_MACRO_EXPAND(const T& z)
|
||||
{
|
||||
return (z < 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T copysign BOOST_NO_MACRO_EXPAND(const T& x, const T& y)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
return fabs(x) * boost::math::sign(y);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_MATH_TOOLS_SIGN_HPP
|
||||
|
||||
64
include/boost/math/special_functions/sin_pi.hpp
Normal file
64
include/boost/math/special_functions/sin_pi.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2007 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SIN_PI_HPP
|
||||
#define BOOST_MATH_SIN_PI_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/real_cast.hpp>
|
||||
#include <boost/math/tools/promotion.hpp>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
|
||||
namespace boost{ namespace math{ namespace detail{
|
||||
|
||||
template <class T>
|
||||
T sin_pi_imp(T x)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std names
|
||||
// sin of pi*x:
|
||||
bool invert;
|
||||
if(x < 0.5)
|
||||
return sin(constants::pi<T>() * x);
|
||||
if(x < 1)
|
||||
{
|
||||
invert = true;
|
||||
x = -x;
|
||||
}
|
||||
else
|
||||
invert = false;
|
||||
|
||||
T rem = floor(x);
|
||||
if(tools::real_cast<int>(rem) & 1)
|
||||
invert = !invert;
|
||||
rem = x - rem;
|
||||
if(rem > 0.5f)
|
||||
rem = 1 - rem;
|
||||
if(rem == 0.5f)
|
||||
return static_cast<T>(invert ? -1 : 1);
|
||||
|
||||
rem = sin(constants::pi<T>() * rem);
|
||||
return invert ? -rem : rem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type sin_pi(T x, const Policy&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return boost::math::detail::sin_pi_imp<result_type>(x);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type sin_pi(T x)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return boost::math::detail::sin_pi_imp<result_type>(x);
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
#endif
|
||||
@@ -11,6 +11,10 @@
|
||||
#define BOOST_SINC_HPP
|
||||
|
||||
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/policies/policy.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <cmath>
|
||||
#include <boost/limits.hpp>
|
||||
#include <string>
|
||||
@@ -26,6 +30,8 @@ namespace 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:
|
||||
@@ -40,9 +46,9 @@ namespace boost
|
||||
// This is the "Sinus Cardinal" of index Pi.
|
||||
|
||||
template<typename T>
|
||||
inline T sinc_pi(const T x)
|
||||
inline T sinc_pi_imp(const T x)
|
||||
{
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
|
||||
using ::abs;
|
||||
using ::sin;
|
||||
using ::sqrt;
|
||||
@@ -52,9 +58,8 @@ namespace boost
|
||||
using ::std::sqrt;
|
||||
#endif /* BOOST_NO_STDC_NAMESPACE */
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
static T const taylor_0_bound = numeric_limits<T>::epsilon();
|
||||
// Note: this code is *not* thread safe!
|
||||
static T const taylor_0_bound = tools::epsilon<T>();
|
||||
static T const taylor_2_bound = sqrt(taylor_0_bound);
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
|
||||
@@ -85,6 +90,21 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type sinc_pi(T x)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::sinc_pi_imp(static_cast<result_type>(x));
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type sinc_pi(T x, const Policy&)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::sinc_pi_imp(static_cast<result_type>(x));
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_TEMPLATE_TEMPLATES
|
||||
#else /* BOOST_NO_TEMPLATE_TEMPLATES */
|
||||
@@ -105,7 +125,7 @@ namespace boost
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
static T const taylor_0_bound = numeric_limits<T>::epsilon();
|
||||
static T const taylor_0_bound = tools::epsilon<T>();
|
||||
static T const taylor_2_bound = sqrt(taylor_0_bound);
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
|
||||
@@ -139,6 +159,12 @@ namespace boost
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, template<typename> class U, class Policy>
|
||||
inline U<T> sinc_pi(const U<T> x, const Policy&)
|
||||
{
|
||||
return sinc_pi(x);
|
||||
}
|
||||
#endif /* BOOST_NO_TEMPLATE_TEMPLATES */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
#define BOOST_SINHC_HPP
|
||||
|
||||
|
||||
#include <boost/math/tools/config.hpp>
|
||||
#include <boost/math/tools/precision.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
#include <cmath>
|
||||
#include <boost/limits.hpp>
|
||||
#include <string>
|
||||
@@ -26,6 +29,8 @@ namespace 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:
|
||||
@@ -40,9 +45,9 @@ namespace boost
|
||||
// This is the "Hyperbolic Sinus Cardinal" of index Pi.
|
||||
|
||||
template<typename T>
|
||||
inline T sinhc_pi(const T x)
|
||||
inline T sinhc_pi_imp(const T x)
|
||||
{
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
#if defined(BOOST_NO_STDC_NAMESPACE) && !defined(__SUNPRO_CC)
|
||||
using ::abs;
|
||||
using ::sinh;
|
||||
using ::sqrt;
|
||||
@@ -52,9 +57,7 @@ namespace boost
|
||||
using ::std::sqrt;
|
||||
#endif /* BOOST_NO_STDC_NAMESPACE */
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
static T const taylor_0_bound = numeric_limits<T>::epsilon();
|
||||
static T const taylor_0_bound = tools::epsilon<T>();
|
||||
static T const taylor_2_bound = sqrt(taylor_0_bound);
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
|
||||
@@ -85,6 +88,20 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type sinhc_pi(T x)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
return detail::sinhc_pi_imp(static_cast<result_type>(x));
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type sinhc_pi(T x, const Policy&)
|
||||
{
|
||||
return boost::math::sinhc_pi(x);
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_TEMPLATE_TEMPLATES
|
||||
#else /* BOOST_NO_TEMPLATE_TEMPLATES */
|
||||
@@ -105,7 +122,7 @@ namespace boost
|
||||
|
||||
using ::std::numeric_limits;
|
||||
|
||||
static T const taylor_0_bound = numeric_limits<T>::epsilon();
|
||||
static T const taylor_0_bound = tools::epsilon<T>();
|
||||
static T const taylor_2_bound = sqrt(taylor_0_bound);
|
||||
static T const taylor_n_bound = sqrt(taylor_2_bound);
|
||||
|
||||
|
||||
199
include/boost/math/special_functions/spherical_harmonic.hpp
Normal file
199
include/boost/math/special_functions/spherical_harmonic.hpp
Normal file
@@ -0,0 +1,199 @@
|
||||
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
|
||||
#define BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
|
||||
|
||||
#include <boost/math/special_functions/legendre.hpp>
|
||||
#include <boost/math/tools/workaround.hpp>
|
||||
#include <complex>
|
||||
|
||||
namespace boost{
|
||||
namespace math{
|
||||
|
||||
namespace detail{
|
||||
|
||||
//
|
||||
// Calculates the prefix term that's common to the real
|
||||
// and imaginary parts. Does *not* fix up the sign of the result
|
||||
// though.
|
||||
//
|
||||
template <class T, class Policy>
|
||||
inline T spherical_harmonic_prefix(unsigned n, unsigned m, T theta, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
if(m > n)
|
||||
return 0;
|
||||
|
||||
T sin_theta = sin(theta);
|
||||
T x = cos(theta);
|
||||
|
||||
T leg = detail::legendre_p_imp(n, m, x, pow(fabs(sin_theta), T(m)), pol);
|
||||
|
||||
T prefix = boost::math::tgamma_delta_ratio(static_cast<T>(n - m + 1), static_cast<T>(2 * m), pol);
|
||||
prefix *= (2 * n + 1) / (4 * constants::pi<T>());
|
||||
prefix = sqrt(prefix);
|
||||
return prefix * leg;
|
||||
}
|
||||
//
|
||||
// Real Part:
|
||||
//
|
||||
template <class T, class Policy>
|
||||
T spherical_harmonic_r(unsigned n, int m, T theta, T phi, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions
|
||||
|
||||
bool sign = false;
|
||||
if(m < 0)
|
||||
{
|
||||
// Reflect and adjust sign if m < 0:
|
||||
sign = m&1;
|
||||
m = abs(m);
|
||||
}
|
||||
if(m&1)
|
||||
{
|
||||
// Check phase if theta is outside [0, PI]:
|
||||
T mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi<T>());
|
||||
if(mod < 0)
|
||||
mod += 2 * constants::pi<T>();
|
||||
if(mod > constants::pi<T>())
|
||||
sign = !sign;
|
||||
}
|
||||
// Get the value and adjust sign as required:
|
||||
T prefix = spherical_harmonic_prefix(n, m, theta, pol);
|
||||
prefix *= cos(m * phi);
|
||||
return sign ? -prefix : prefix;
|
||||
}
|
||||
|
||||
template <class T, class Policy>
|
||||
T spherical_harmonic_i(unsigned n, int m, T theta, T phi, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING // ADL of std functions
|
||||
|
||||
bool sign = false;
|
||||
if(m < 0)
|
||||
{
|
||||
// Reflect and adjust sign if m < 0:
|
||||
sign = !(m&1);
|
||||
m = abs(m);
|
||||
}
|
||||
if(m&1)
|
||||
{
|
||||
// Check phase if theta is outside [0, PI]:
|
||||
T mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi<T>());
|
||||
if(mod < 0)
|
||||
mod += 2 * constants::pi<T>();
|
||||
if(mod > constants::pi<T>())
|
||||
sign = !sign;
|
||||
}
|
||||
// Get the value and adjust sign as required:
|
||||
T prefix = spherical_harmonic_prefix(n, m, theta, pol);
|
||||
prefix *= sin(m * phi);
|
||||
return sign ? -prefix : prefix;
|
||||
}
|
||||
|
||||
template <class T, class U, class Policy>
|
||||
std::complex<T> spherical_harmonic(unsigned n, int m, U theta, U phi, const Policy& pol)
|
||||
{
|
||||
BOOST_MATH_STD_USING
|
||||
//
|
||||
// Sort out the signs:
|
||||
//
|
||||
bool r_sign = false;
|
||||
bool i_sign = false;
|
||||
if(m < 0)
|
||||
{
|
||||
// Reflect and adjust sign if m < 0:
|
||||
r_sign = m&1;
|
||||
i_sign = !(m&1);
|
||||
m = abs(m);
|
||||
}
|
||||
if(m&1)
|
||||
{
|
||||
// Check phase if theta is outside [0, PI]:
|
||||
U mod = boost::math::tools::fmod_workaround(theta, 2 * constants::pi<U>());
|
||||
if(mod < 0)
|
||||
mod += 2 * constants::pi<U>();
|
||||
if(mod > constants::pi<U>())
|
||||
{
|
||||
r_sign = !r_sign;
|
||||
i_sign = !i_sign;
|
||||
}
|
||||
}
|
||||
//
|
||||
// Calculate the value:
|
||||
//
|
||||
U prefix = spherical_harmonic_prefix(n, m, theta, pol);
|
||||
U r = prefix * cos(m * phi);
|
||||
U i = prefix * sin(m * phi);
|
||||
//
|
||||
// Add in the signs:
|
||||
//
|
||||
if(r_sign)
|
||||
r = -r;
|
||||
if(i_sign)
|
||||
i = -i;
|
||||
static const char* function = "boost::math::spherical_harmonic<%1%>(int, int, %1%, %1%)";
|
||||
return std::complex<T>(policies::checked_narrowing_cast<T, Policy>(r, function), policies::checked_narrowing_cast<T, Policy>(i, function));
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline std::complex<typename tools::promote_args<T1, T2>::type>
|
||||
spherical_harmonic(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return detail::spherical_harmonic<result_type, value_type>(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol);
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline std::complex<typename tools::promote_args<T1, T2>::type>
|
||||
spherical_harmonic(unsigned n, int m, T1 theta, T2 phi)
|
||||
{
|
||||
return boost::math::spherical_harmonic(n, m, theta, phi, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_r(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "bost::math::spherical_harmonic_r<%1%>(unsigned, int, %1%, %1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_r(unsigned n, int m, T1 theta, T2 phi)
|
||||
{
|
||||
return boost::math::spherical_harmonic_r(n, m, theta, phi, policies::policy<>());
|
||||
}
|
||||
|
||||
template <class T1, class T2, class Policy>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T1, T2>::type result_type;
|
||||
typedef typename policies::evaluation<result_type, Policy>::type value_type;
|
||||
return policies::checked_narrowing_cast<result_type, Policy>(detail::spherical_harmonic_i(n, m, static_cast<value_type>(theta), static_cast<value_type>(phi), pol), "boost::math::spherical_harmonic_i<%1%>(unsigned, int, %1%, %1%)");
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
inline typename tools::promote_args<T1, T2>::type
|
||||
spherical_harmonic_i(unsigned n, int m, T1 theta, T2 phi)
|
||||
{
|
||||
return boost::math::spherical_harmonic_i(n, m, theta, phi, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SPECIAL_SPHERICAL_HARMONIC_HPP
|
||||
|
||||
|
||||
43
include/boost/math/special_functions/sqrt1pm1.hpp
Normal file
43
include/boost/math/special_functions/sqrt1pm1.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
// (C) Copyright John Maddock 2006.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_SQRT1PM1
|
||||
#define BOOST_MATH_SQRT1PM1
|
||||
|
||||
#include <boost/math/special_functions/log1p.hpp>
|
||||
#include <boost/math/special_functions/expm1.hpp>
|
||||
#include <boost/math/special_functions/math_fwd.hpp>
|
||||
|
||||
//
|
||||
// This algorithm computes sqrt(1+x)-1 for small x:
|
||||
//
|
||||
|
||||
namespace boost{ namespace math{
|
||||
|
||||
template <class T, class Policy>
|
||||
inline typename tools::promote_args<T>::type sqrt1pm1(const T& val, const Policy& pol)
|
||||
{
|
||||
typedef typename tools::promote_args<T>::type result_type;
|
||||
BOOST_MATH_STD_USING
|
||||
|
||||
if(fabs(result_type(val)) > 0.75)
|
||||
return sqrt(1 + result_type(val)) - 1;
|
||||
return boost::math::expm1(boost::math::log1p(val, pol) / 2, pol);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline typename tools::promote_args<T>::type sqrt1pm1(const T& val)
|
||||
{
|
||||
return sqrt1pm1(val, policies::policy<>());
|
||||
}
|
||||
|
||||
} // namespace math
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_MATH_SQRT1PM1
|
||||
|
||||
|
||||
|
||||
|
||||
246
include/boost/math/tools/config.hpp
Normal file
246
include/boost/math/tools/config.hpp
Normal file
@@ -0,0 +1,246 @@
|
||||
// Copyright (c) 2006-7 John Maddock
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_MATH_TOOLS_CONFIG_HPP
|
||||
#define BOOST_MATH_TOOLS_CONFIG_HPP
|
||||
|
||||
#include <boost/cstdint.hpp> // for boost::uintmax_t
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <algorithm> // for min and max
|
||||
#include <cmath>
|
||||
#include <climits>
|
||||
#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__))
|
||||
# include <math.h>
|
||||
#endif
|
||||
|
||||
#include <boost/math/tools/user.hpp>
|
||||
|
||||
#if defined(__CYGWIN__) || defined(__FreeBSD__) || defined(__hppa)
|
||||
# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
#endif
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582))
|
||||
//
|
||||
// Borland post 5.8.2 uses Dinkumware's std C lib which
|
||||
// doesn't have true long double precision. Earlier
|
||||
// versions are problematic too:
|
||||
//
|
||||
# define BOOST_MATH_NO_REAL_CONCEPT_TESTS
|
||||
# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
# define BOOST_MATH_CONTROL_FP _control87(MCW_EM,MCW_EM)
|
||||
# include <float.h>
|
||||
#endif
|
||||
#if (defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)) && ((LDBL_MANT_DIG == 106) || (__LDBL_MANT_DIG__ == 106))
|
||||
//
|
||||
// Darwin's rather strange "double double" is rather hard to
|
||||
// support, it should be possible given enough effort though...
|
||||
//
|
||||
# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
#endif
|
||||
#if defined(unix) && defined(__INTEL_COMPILER) && (__INTEL_COMPILER <= 1000)
|
||||
//
|
||||
// Intel compiler prior to version 10 has sporadic problems
|
||||
// calling the long double overloads of the std lib math functions:
|
||||
// calling ::powl is OK, but std::pow(long double, long double)
|
||||
// may segfault depending upon the value of the arguments passed
|
||||
// and the specific Linux distribution.
|
||||
//
|
||||
// We'll be conservative and disable long double support for this compiler.
|
||||
//
|
||||
// Comment out this #define and try building the tests to determine whether
|
||||
// your Intel compiler version has this issue or not.
|
||||
//
|
||||
# define BOOST_MATH_NO_LONG_DOUBLE_MATH_FUNCTIONS
|
||||
#endif
|
||||
|
||||
#ifdef __IBMCPP__
|
||||
# define BOOST_MATH_NO_DEDUCED_FUNCTION_POINTERS
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS) || BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590)
|
||||
|
||||
# include "boost/type.hpp"
|
||||
# include "boost/non_type.hpp"
|
||||
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(t) boost::type<t>* = 0
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(t) boost::type<t>*
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE(t, v) boost::non_type<t, v>* = 0
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) boost::non_type<t, v>*
|
||||
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(t) \
|
||||
, BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(t)
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(t) \
|
||||
, BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(t)
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(t, v) \
|
||||
, BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE(t, v)
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v) \
|
||||
, BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v)
|
||||
|
||||
#else
|
||||
|
||||
// no workaround needed: expand to nothing
|
||||
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE(t)
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_TYPE_SPEC(t)
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE(t, v)
|
||||
# define BOOST_MATH_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v)
|
||||
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE(t)
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_TYPE_SPEC(t)
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE(t, v)
|
||||
# define BOOST_MATH_APPEND_EXPLICIT_TEMPLATE_NON_TYPE_SPEC(t, v)
|
||||
|
||||
|
||||
#endif // defined BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS
|
||||
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, <= 0x590) || defined(__hppa)
|
||||
// Sun's compiler emits a hard error if a constant underflows,
|
||||
// as does aCC on PA-RISC:
|
||||
# define BOOST_MATH_SMALL_CONSTANT(x) 0
|
||||
#else
|
||||
# define BOOST_MATH_SMALL_CONSTANT(x) x
|
||||
#endif
|
||||
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1400)
|
||||
//
|
||||
// Define if constants too large for a float cause "bad"
|
||||
// values to be stored in the data, rather than infinity
|
||||
// or a suitably large value.
|
||||
//
|
||||
# define BOOST_MATH_BUGGY_LARGE_FLOAT_CONSTANTS
|
||||
#endif
|
||||
//
|
||||
// Tune performance options for specific compilers:
|
||||
//
|
||||
#ifdef BOOST_MSVC
|
||||
# define BOOST_MATH_POLY_METHOD 3
|
||||
#elif defined(BOOST_INTEL)
|
||||
# define BOOST_MATH_POLY_METHOD 2
|
||||
# define BOOST_MATH_RATIONAL_METHOD 2
|
||||
#elif defined(__GNUC__)
|
||||
# define BOOST_MATH_POLY_METHOD 3
|
||||
# define BOOST_MATH_RATIONAL_METHOD 3
|
||||
# define BOOST_MATH_INT_TABLE_TYPE(RT, IT) RT
|
||||
#endif
|
||||
|
||||
//
|
||||
// The maximum order of polynomial that will be evaluated
|
||||
// via an unrolled specialisation:
|
||||
//
|
||||
#ifndef BOOST_MATH_MAX_POLY_ORDER
|
||||
# define BOOST_MATH_MAX_POLY_ORDER 17
|
||||
#endif
|
||||
//
|
||||
// Set the method used to evaluate polynomials and rationals:
|
||||
//
|
||||
#ifndef BOOST_MATH_POLY_METHOD
|
||||
# define BOOST_MATH_POLY_METHOD 1
|
||||
#endif
|
||||
#ifndef BOOST_MATH_RATIONAL_METHOD
|
||||
# define BOOST_MATH_RATIONAL_METHOD 0
|
||||
#endif
|
||||
//
|
||||
// decide whether to store constants as integers or reals:
|
||||
//
|
||||
#ifndef BOOST_MATH_INT_TABLE_TYPE
|
||||
# define BOOST_MATH_INT_TABLE_TYPE(RT, IT) IT
|
||||
#endif
|
||||
//
|
||||
// Helper macro for controlling the FP behaviour:
|
||||
//
|
||||
#ifndef BOOST_MATH_CONTROL_FP
|
||||
# define BOOST_MATH_CONTROL_FP
|
||||
#endif
|
||||
//
|
||||
// Helper macro for using statements:
|
||||
//
|
||||
#define BOOST_MATH_STD_USING \
|
||||
using std::abs;\
|
||||
using std::acos;\
|
||||
using std::cos;\
|
||||
using std::fmod;\
|
||||
using std::modf;\
|
||||
using std::tan;\
|
||||
using std::asin;\
|
||||
using std::cosh;\
|
||||
using std::frexp;\
|
||||
using std::pow;\
|
||||
using std::tanh;\
|
||||
using std::atan;\
|
||||
using std::exp;\
|
||||
using std::ldexp;\
|
||||
using std::sin;\
|
||||
using std::atan2;\
|
||||
using std::fabs;\
|
||||
using std::log;\
|
||||
using std::sinh;\
|
||||
using std::ceil;\
|
||||
using std::floor;\
|
||||
using std::log10;\
|
||||
using std::sqrt;
|
||||
|
||||
|
||||
namespace boost{ namespace math{
|
||||
namespace tools
|
||||
{
|
||||
|
||||
template <class T>
|
||||
inline T max BOOST_PREVENT_MACRO_SUBSTITUTION(T a, T b, T c)
|
||||
{
|
||||
return (std::max)((std::max)(a, b), c);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T max BOOST_PREVENT_MACRO_SUBSTITUTION(T a, T b, T c, T d)
|
||||
{
|
||||
return (std::max)((std::max)(a, b), (std::max)(c, d));
|
||||
}
|
||||
} // namespace tools
|
||||
}} // namespace boost namespace math
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <fenv.h>
|
||||
|
||||
namespace boost{ namespace math{
|
||||
namespace detail
|
||||
{
|
||||
struct fpu_guard
|
||||
{
|
||||
fpu_guard()
|
||||
{
|
||||
fegetexceptflag(&m_flags, FE_ALL_EXCEPT);
|
||||
feclearexcept(FE_ALL_EXCEPT);
|
||||
}
|
||||
~fpu_guard()
|
||||
{
|
||||
fesetexceptflag(&m_flags, FE_ALL_EXCEPT);
|
||||
}
|
||||
private:
|
||||
fexcept_t m_flags;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
}} // namespaces
|
||||
|
||||
#define BOOST_FPU_EXCEPTION_GUARD boost::math::detail::fpu_guard local_guard_object;
|
||||
#else // All other platforms.
|
||||
#define BOOST_FPU_EXCEPTION_GUARD
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_MATH_INSTRUMENT
|
||||
#define BOOST_MATH_INSTRUMENT_CODE(x) \
|
||||
std::cout << std::setprecision(35) << __FILE__ << ":" << __LINE__ << " " << x << std::endl;
|
||||
#define BOOST_MATH_INSTRUMENT_VARIABLE(name) BOOST_MATH_INSTRUMENT_CODE(BOOST_STRINGIZE(name) << " = " << name)
|
||||
#else
|
||||
#define BOOST_MATH_INSTRUMENT_CODE(x)
|
||||
#define BOOST_MATH_INSTRUMENT_VARIABLE(name)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_MATH_TOOLS_CONFIG_HPP
|
||||
|
||||
|
||||
|
||||
84
include/boost/math/tools/detail/polynomial_horner1_10.hpp
Normal file
84
include/boost/math/tools/detail/polynomial_horner1_10.hpp
Normal file
@@ -0,0 +1,84 @@
|
||||
// (C) 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)
|
||||
//
|
||||
// This file is machine generated, do not edit by hand
|
||||
|
||||
// Polynomial evaluation using Horners rule
|
||||
#ifndef BOOST_MATH_TOOLS_POLY_EVAL_10_HPP
|
||||
#define BOOST_MATH_TOOLS_POLY_EVAL_10_HPP
|
||||
|
||||
namespace boost{ namespace math{ namespace tools{ namespace detail{
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*)
|
||||
{
|
||||
return static_cast<V>(0);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*)
|
||||
{
|
||||
return static_cast<V>(a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*)
|
||||
{
|
||||
return static_cast<V>(a[1] * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*)
|
||||
{
|
||||
return static_cast<V>((a[2] * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*)
|
||||
{
|
||||
return static_cast<V>(((a[3] * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*)
|
||||
{
|
||||
return static_cast<V>((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*)
|
||||
{
|
||||
return static_cast<V>(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*)
|
||||
{
|
||||
return static_cast<V>((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*)
|
||||
{
|
||||
return static_cast<V>(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*)
|
||||
{
|
||||
return static_cast<V>((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*)
|
||||
{
|
||||
return static_cast<V>(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
#endif // include guard
|
||||
|
||||
90
include/boost/math/tools/detail/polynomial_horner1_11.hpp
Normal file
90
include/boost/math/tools/detail/polynomial_horner1_11.hpp
Normal file
@@ -0,0 +1,90 @@
|
||||
// (C) 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)
|
||||
//
|
||||
// This file is machine generated, do not edit by hand
|
||||
|
||||
// Polynomial evaluation using Horners rule
|
||||
#ifndef BOOST_MATH_TOOLS_POLY_EVAL_11_HPP
|
||||
#define BOOST_MATH_TOOLS_POLY_EVAL_11_HPP
|
||||
|
||||
namespace boost{ namespace math{ namespace tools{ namespace detail{
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<0>*)
|
||||
{
|
||||
return static_cast<V>(0);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V&, const mpl::int_<1>*)
|
||||
{
|
||||
return static_cast<V>(a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<2>*)
|
||||
{
|
||||
return static_cast<V>(a[1] * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<3>*)
|
||||
{
|
||||
return static_cast<V>((a[2] * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<4>*)
|
||||
{
|
||||
return static_cast<V>(((a[3] * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<5>*)
|
||||
{
|
||||
return static_cast<V>((((a[4] * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<6>*)
|
||||
{
|
||||
return static_cast<V>(((((a[5] * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<7>*)
|
||||
{
|
||||
return static_cast<V>((((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<8>*)
|
||||
{
|
||||
return static_cast<V>(((((((a[7] * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<9>*)
|
||||
{
|
||||
return static_cast<V>((((((((a[8] * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<10>*)
|
||||
{
|
||||
return static_cast<V>(((((((((a[9] * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
template <class T, class V>
|
||||
inline V evaluate_polynomial_c_imp(const T* a, const V& x, const mpl::int_<11>*)
|
||||
{
|
||||
return static_cast<V>((((((((((a[10] * x + a[9]) * x + a[8]) * x + a[7]) * x + a[6]) * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x + a[1]) * x + a[0]);
|
||||
}
|
||||
|
||||
|
||||
}}}} // namespaces
|
||||
|
||||
#endif // include guard
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user