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