File indexing completed on 2025-11-03 09:27:49
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 #ifndef BOOST_STATS_STUDENTS_T_HPP
0010 #define BOOST_STATS_STUDENTS_T_HPP
0011 
0012 
0013 
0014 
0015 #include <boost/math/tools/config.hpp>
0016 #include <boost/math/tools/tuple.hpp>
0017 #include <boost/math/tools/cstdint.hpp>
0018 #include <boost/math/tools/numeric_limits.hpp>
0019 #include <boost/math/distributions/fwd.hpp>
0020 #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x).
0021 #include <boost/math/special_functions/digamma.hpp>
0022 #include <boost/math/distributions/complement.hpp>
0023 #include <boost/math/distributions/detail/common_error_handling.hpp>
0024 #include <boost/math/distributions/normal.hpp> 
0025 #include <boost/math/policies/policy.hpp>
0026 
0027 #ifdef _MSC_VER
0028 # pragma warning(push)
0029 # pragma warning(disable: 4702) 
0030 #endif
0031 
0032 namespace boost { namespace math {
0033 
0034 template <class RealType = double, class Policy = policies::policy<> >
0035 class students_t_distribution
0036 {
0037 public:
0038    typedef RealType value_type;
0039    typedef Policy policy_type;
0040 
0041    BOOST_MATH_GPU_ENABLED students_t_distribution(RealType df) : df_(df)
0042    { 
0043       RealType result;
0044       detail::check_df_gt0_to_inf( 
0045          "boost::math::students_t_distribution<%1%>::students_t_distribution", df_, &result, Policy());
0046    } 
0047 
0048    BOOST_MATH_GPU_ENABLED RealType degrees_of_freedom()const
0049    {
0050       return df_;
0051    }
0052 
0053    
0054    BOOST_MATH_GPU_ENABLED static RealType find_degrees_of_freedom(
0055       RealType difference_from_mean,
0056       RealType alpha,
0057       RealType beta,
0058       RealType sd,
0059       RealType hint = 100);
0060 
0061 private:
0062    
0063    RealType df_;  
0064 };
0065 
0066 typedef students_t_distribution<double> students_t; 
0067 
0068 #ifdef __cpp_deduction_guides
0069 template <class RealType>
0070 students_t_distribution(RealType)->students_t_distribution<typename boost::math::tools::promote_args<RealType>::type>;
0071 #endif
0072 
0073 template <class RealType, class Policy>
0074 BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> range(const students_t_distribution<RealType, Policy>& )
0075 { 
0076   
0077    using boost::math::tools::max_value;
0078    
0079    return boost::math::pair<RealType, RealType>(((::boost::math::numeric_limits<RealType>::is_specialized & ::boost::math::numeric_limits<RealType>::has_infinity) ? -boost::math::numeric_limits<RealType>::infinity() : -max_value<RealType>()), ((::boost::math::numeric_limits<RealType>::is_specialized & ::boost::math::numeric_limits<RealType>::has_infinity) ? +boost::math::numeric_limits<RealType>::infinity() : +max_value<RealType>()));
0080 }
0081 
0082 template <class RealType, class Policy>
0083 BOOST_MATH_GPU_ENABLED inline const boost::math::pair<RealType, RealType> support(const students_t_distribution<RealType, Policy>& )
0084 { 
0085   
0086    
0087    using boost::math::tools::max_value;
0088    
0089    return boost::math::pair<RealType, RealType>(((::boost::math::numeric_limits<RealType>::is_specialized & ::boost::math::numeric_limits<RealType>::has_infinity) ? -boost::math::numeric_limits<RealType>::infinity() : -max_value<RealType>()), ((::boost::math::numeric_limits<RealType>::is_specialized & ::boost::math::numeric_limits<RealType>::has_infinity) ? +boost::math::numeric_limits<RealType>::infinity() : +max_value<RealType>()));
0090 }
0091 
0092 template <class RealType, class Policy>
0093 BOOST_MATH_GPU_ENABLED inline RealType pdf(const students_t_distribution<RealType, Policy>& dist, const RealType& x)
0094 {
0095    BOOST_FPU_EXCEPTION_GUARD
0096    BOOST_MATH_STD_USING  
0097 
0098    RealType error_result;
0099    if(false == detail::check_x_not_NaN(
0100       "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", x, &error_result, Policy()))
0101       return error_result;
0102    RealType df = dist.degrees_of_freedom();
0103    if(false == detail::check_df_gt0_to_inf( 
0104       "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", df, &error_result, Policy()))
0105       return error_result;
0106 
0107    RealType result;
0108    if ((boost::math::isinf)(x))
0109    { 
0110      result = static_cast<RealType>(0);
0111      return result;
0112    }
0113    RealType limit = policies::get_epsilon<RealType, Policy>();
0114    
0115    
0116    limit = static_cast<RealType>(1) / limit; 
0117    
0118    if (df > limit)
0119    { 
0120      
0121      normal_distribution<RealType, Policy> n(0, 1); 
0122      result = pdf(n, x);
0123    }
0124    else
0125    { 
0126      RealType basem1 = x * x / df;
0127      if(basem1 < 0.125)
0128      {
0129         result = exp(-boost::math::log1p(basem1, Policy()) * (1+df) / 2);
0130      }
0131      else
0132      {
0133         result = pow(1 / (1 + basem1), (df + 1) / 2);
0134      }
0135      result /= sqrt(df) * boost::math::beta(df / 2, RealType(0.5f), Policy());
0136    }
0137    return result;
0138 } 
0139 
0140 template <class RealType, class Policy>
0141 BOOST_MATH_GPU_ENABLED inline RealType cdf(const students_t_distribution<RealType, Policy>& dist, const RealType& x)
0142 {
0143    RealType error_result;
0144    
0145    RealType df = dist.degrees_of_freedom();
0146    if (false == detail::check_df_gt0_to_inf(  
0147      "boost::math::cdf(const students_t_distribution<%1%>&, %1%)", df, &error_result, Policy()))
0148    {
0149      return error_result;
0150    }
0151    
0152    if(false == detail::check_x_not_NaN(
0153       "boost::math::cdf(const students_t_distribution<%1%>&, %1%)", x, &error_result, Policy()))
0154    { 
0155       return error_result;
0156    }
0157    if (x == 0)
0158    { 
0159      return static_cast<RealType>(0.5);
0160    }
0161    if ((boost::math::isinf)(x))
0162    { 
0163      return ((x < 0) ? static_cast<RealType>(0) : static_cast<RealType>(1));
0164    }
0165 
0166    RealType limit = policies::get_epsilon<RealType, Policy>();
0167    
0168    
0169    limit = static_cast<RealType>(1) / limit; 
0170    
0171    if (df > limit)
0172    { 
0173      
0174      normal_distribution<RealType, Policy> n(0, 1); 
0175      RealType result = cdf(n, x);
0176      return result;
0177    }
0178    else
0179    { 
0180      
0181      
0182      
0183      
0184      
0185      
0186      
0187      
0188      
0189      
0190      
0191      
0192      
0193      
0194      
0195      
0196      
0197      
0198      RealType x2 = x * x;
0199      RealType probability;
0200      if(df > 2 * x2)
0201      {
0202         RealType z = x2 / (df + x2);
0203         probability = ibetac(static_cast<RealType>(0.5), df / 2, z, Policy()) / 2;
0204      }
0205      else
0206      {
0207         RealType z = df / (df + x2);
0208         probability = ibeta(df / 2, static_cast<RealType>(0.5), z, Policy()) / 2;
0209      }
0210      return (x > 0 ? 1   - probability : probability);
0211   }
0212 } 
0213 
0214 template <class RealType, class Policy>
0215 BOOST_MATH_GPU_ENABLED inline RealType quantile(const students_t_distribution<RealType, Policy>& dist, const RealType& p)
0216 {
0217    BOOST_MATH_STD_USING 
0218    
0219    
0220    RealType probability = p;
0221  
0222    
0223    RealType df = dist.degrees_of_freedom();
0224    constexpr auto function = "boost::math::quantile(const students_t_distribution<%1%>&, %1%)";
0225    RealType error_result;
0226    if(false == (detail::check_df_gt0_to_inf( 
0227       function, df, &error_result, Policy())
0228          && detail::check_probability(function, probability, &error_result, Policy())))
0229       return error_result;
0230    
0231    if (probability == 0)
0232       return -policies::raise_overflow_error<RealType>(function, 0, Policy());
0233    if (probability == 1)
0234      return policies::raise_overflow_error<RealType>(function, 0, Policy());
0235    if (probability == static_cast<RealType>(0.5))
0236      return 0;  
0237    
0238 #if 0
0239    
0240    
0241    
0242    
0243    probability = (probability > 0.5) ? 1 - probability : probability;
0244    RealType t, x, y;
0245    x = ibeta_inv(degrees_of_freedom / 2, RealType(0.5), 2 * probability, &y);
0246    if(degrees_of_freedom * y > tools::max_value<RealType>() * x)
0247       t = tools::overflow_error<RealType>(function);
0248    else
0249       t = sqrt(degrees_of_freedom * y / x);
0250    
0251    
0252    
0253    if(p < 0.5)
0254       t = -t;
0255 
0256    return t;
0257 #endif
0258    
0259    
0260    
0261    
0262    
0263    
0264    
0265    return boost::math::detail::fast_students_t_quantile(df, probability, Policy());
0266 } 
0267 
0268 template <class RealType, class Policy>
0269 BOOST_MATH_GPU_ENABLED inline RealType cdf(const complemented2_type<students_t_distribution<RealType, Policy>, RealType>& c)
0270 {
0271    return cdf(c.dist, -c.param);
0272 }
0273 
0274 template <class RealType, class Policy>
0275 BOOST_MATH_GPU_ENABLED inline RealType quantile(const complemented2_type<students_t_distribution<RealType, Policy>, RealType>& c)
0276 {
0277    return -quantile(c.dist, c.param);
0278 }
0279 
0280 
0281 
0282 
0283 namespace detail{
0284 
0285 
0286 
0287 template <class RealType, class Policy>
0288 struct sample_size_func
0289 {
0290    BOOST_MATH_GPU_ENABLED sample_size_func(RealType a, RealType b, RealType s, RealType d)
0291       : alpha(a), beta(b), ratio(s*s/(d*d)) {}
0292 
0293    BOOST_MATH_GPU_ENABLED RealType operator()(const RealType& df)
0294    {
0295       if(df <= tools::min_value<RealType>())
0296       { 
0297          return 1;
0298       }
0299       students_t_distribution<RealType, Policy> t(df);
0300       RealType qa = quantile(complement(t, alpha));
0301       RealType qb = quantile(complement(t, beta));
0302       qa += qb;
0303       qa *= qa;
0304       qa *= ratio;
0305       qa -= (df + 1);
0306       return qa;
0307    }
0308    RealType alpha, beta, ratio;
0309 };
0310 
0311 }  
0312 
0313 template <class RealType, class Policy>
0314 BOOST_MATH_GPU_ENABLED RealType students_t_distribution<RealType, Policy>::find_degrees_of_freedom(
0315       RealType difference_from_mean,
0316       RealType alpha,
0317       RealType beta,
0318       RealType sd,
0319       RealType hint)
0320 {
0321    constexpr auto function = "boost::math::students_t_distribution<%1%>::find_degrees_of_freedom";
0322    
0323    
0324    
0325    RealType error_result;
0326    if(false == detail::check_probability(
0327       function, alpha, &error_result, Policy())
0328          && detail::check_probability(function, beta, &error_result, Policy()))
0329       return error_result;
0330 
0331    if(hint <= 0)
0332       hint = 1;
0333 
0334    detail::sample_size_func<RealType, Policy> f(alpha, beta, sd, difference_from_mean);
0335    tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
0336    boost::math::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
0337    boost::math::pair<RealType, RealType> r = tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy());
0338    RealType result = r.first + (r.second - r.first) / 2;
0339    if(max_iter >= policies::get_max_root_iterations<Policy>())
0340    {
0341       return 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" 
0342          " or the answer is infinite.  Current best guess is %1%", result, Policy()); 
0343    }
0344    return result;
0345 }
0346 
0347 template <class RealType, class Policy>
0348 BOOST_MATH_GPU_ENABLED inline RealType mode(const students_t_distribution<RealType, Policy>& )
0349 {
0350   
0351    return 0; 
0352 }
0353 
0354 template <class RealType, class Policy>
0355 BOOST_MATH_GPU_ENABLED inline RealType median(const students_t_distribution<RealType, Policy>& )
0356 {
0357    
0358    return 0; 
0359 }
0360 
0361 
0362 
0363 template <class RealType, class Policy>
0364 BOOST_MATH_GPU_ENABLED inline RealType mean(const students_t_distribution<RealType, Policy>& dist)
0365 {  
0366    RealType df = dist.degrees_of_freedom();
0367    if(((boost::math::isnan)(df)) || (df <= 1) ) 
0368    { 
0369       return policies::raise_domain_error<RealType>(
0370       "boost::math::mean(students_t_distribution<%1%> const&, %1%)",
0371       "Mean is undefined for degrees of freedom < 1 but got %1%.", df, Policy());
0372       return boost::math::numeric_limits<RealType>::quiet_NaN();
0373    }
0374    return 0;
0375 } 
0376 
0377 template <class RealType, class Policy>
0378 BOOST_MATH_GPU_ENABLED inline RealType variance(const students_t_distribution<RealType, Policy>& dist)
0379 { 
0380   
0381   RealType df = dist.degrees_of_freedom();
0382   if ((boost::math::isnan)(df) || (df <= 2))
0383   { 
0384      return policies::raise_domain_error<RealType>(
0385       "boost::math::variance(students_t_distribution<%1%> const&, %1%)",
0386       "variance is undefined for degrees of freedom <= 2, but got %1%.",
0387       df, Policy());
0388     return boost::math::numeric_limits<RealType>::quiet_NaN(); 
0389   }
0390   if ((boost::math::isinf)(df))
0391   { 
0392     return 1;
0393   }
0394   RealType limit = policies::get_epsilon<RealType, Policy>();
0395   
0396   
0397   limit = static_cast<RealType>(1) / limit; 
0398   
0399   if (df > limit)
0400   { 
0401     return 1;
0402   }
0403   else
0404   {
0405     return df / (df - 2);
0406   }
0407 } 
0408 
0409 template <class RealType, class Policy>
0410 BOOST_MATH_GPU_ENABLED inline RealType skewness(const students_t_distribution<RealType, Policy>& dist)
0411 {
0412     RealType df = dist.degrees_of_freedom();
0413    if( ((boost::math::isnan)(df)) || (dist.degrees_of_freedom() <= 3))
0414    { 
0415       return policies::raise_domain_error<RealType>(
0416          "boost::math::skewness(students_t_distribution<%1%> const&, %1%)",
0417          "Skewness is undefined for degrees of freedom <= 3, but got %1%.",
0418          dist.degrees_of_freedom(), Policy());
0419       return boost::math::numeric_limits<RealType>::quiet_NaN();
0420    }
0421    return 0; 
0422 } 
0423 
0424 template <class RealType, class Policy>
0425 BOOST_MATH_GPU_ENABLED inline RealType kurtosis(const students_t_distribution<RealType, Policy>& dist)
0426 {
0427    RealType df = dist.degrees_of_freedom();
0428    if(((boost::math::isnan)(df)) || (df <= 4))
0429    { 
0430       return policies::raise_domain_error<RealType>(
0431        "boost::math::kurtosis(students_t_distribution<%1%> const&, %1%)",
0432        "Kurtosis is undefined for degrees of freedom <= 4, but got %1%.",
0433         df, Policy());
0434         return boost::math::numeric_limits<RealType>::quiet_NaN(); 
0435    }
0436    if ((boost::math::isinf)(df))
0437    { 
0438      return 3;
0439    }
0440    RealType limit = policies::get_epsilon<RealType, Policy>();
0441    
0442    
0443    limit = static_cast<RealType>(1) / limit; 
0444    
0445    if (df > limit)
0446    { 
0447      return 3;
0448    }
0449    else
0450    {
0451      
0452      return 6 / (df - 4) + 3;
0453    }
0454 } 
0455 
0456 template <class RealType, class Policy>
0457 BOOST_MATH_GPU_ENABLED inline RealType kurtosis_excess(const students_t_distribution<RealType, Policy>& dist)
0458 {
0459    
0460 
0461    RealType df = dist.degrees_of_freedom();
0462    if(((boost::math::isnan)(df)) || (df <= 4))
0463    { 
0464      return policies::raise_domain_error<RealType>(
0465        "boost::math::kurtosis_excess(students_t_distribution<%1%> const&, %1%)",
0466        "Kurtosis_excess is undefined for degrees of freedom <= 4, but got %1%.",
0467       df, Policy());
0468      return boost::math::numeric_limits<RealType>::quiet_NaN(); 
0469    }
0470    if ((boost::math::isinf)(df))
0471    { 
0472      return 0;
0473    }
0474    RealType limit = policies::get_epsilon<RealType, Policy>();
0475    
0476    
0477    limit = static_cast<RealType>(1) / limit; 
0478    
0479    if (df > limit)
0480    { 
0481      return 0;
0482    }
0483    else
0484    {
0485      return 6 / (df - 4);
0486    }
0487 }
0488 
0489 template <class RealType, class Policy>
0490 BOOST_MATH_GPU_ENABLED inline RealType entropy(const students_t_distribution<RealType, Policy>& dist)
0491 {
0492    BOOST_MATH_STD_USING
0493    RealType v = dist.degrees_of_freedom();
0494    RealType vp1 = (v+1)/2;
0495    RealType vd2 = v/2;
0496 
0497    return vp1*(digamma(vp1) - digamma(vd2)) + log(sqrt(v)*beta(vd2, RealType(1)/RealType(2)));
0498 }
0499 
0500 } 
0501 } 
0502 
0503 #ifdef _MSC_VER
0504 # pragma warning(pop)
0505 #endif
0506 
0507 
0508 
0509 
0510 #include <boost/math/distributions/detail/derived_accessors.hpp>
0511 
0512 #endif