Chris@16
|
1 // Copyright John Maddock 2006.
|
Chris@16
|
2 // Copyright Paul A. Bristow 2006, 2012.
|
Chris@16
|
3 // Copyright Thomas Mang 2012.
|
Chris@16
|
4
|
Chris@16
|
5 // Use, modification and distribution are subject to the
|
Chris@16
|
6 // Boost Software License, Version 1.0. (See accompanying file
|
Chris@16
|
7 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
8
|
Chris@16
|
9 #ifndef BOOST_STATS_STUDENTS_T_HPP
|
Chris@16
|
10 #define BOOST_STATS_STUDENTS_T_HPP
|
Chris@16
|
11
|
Chris@16
|
12 // http://en.wikipedia.org/wiki/Student%27s_t_distribution
|
Chris@16
|
13 // http://www.itl.nist.gov/div898/handbook/eda/section3/eda3664.htm
|
Chris@16
|
14
|
Chris@16
|
15 #include <boost/math/distributions/fwd.hpp>
|
Chris@16
|
16 #include <boost/math/special_functions/beta.hpp> // for ibeta(a, b, x).
|
Chris@16
|
17 #include <boost/math/distributions/complement.hpp>
|
Chris@16
|
18 #include <boost/math/distributions/detail/common_error_handling.hpp>
|
Chris@16
|
19 #include <boost/math/distributions/normal.hpp>
|
Chris@16
|
20
|
Chris@16
|
21 #include <utility>
|
Chris@16
|
22
|
Chris@16
|
23 #ifdef BOOST_MSVC
|
Chris@16
|
24 # pragma warning(push)
|
Chris@16
|
25 # pragma warning(disable: 4702) // unreachable code (return after domain_error throw).
|
Chris@16
|
26 #endif
|
Chris@16
|
27
|
Chris@16
|
28 namespace boost{ namespace math{
|
Chris@16
|
29
|
Chris@16
|
30 template <class RealType = double, class Policy = policies::policy<> >
|
Chris@16
|
31 class students_t_distribution
|
Chris@16
|
32 {
|
Chris@16
|
33 public:
|
Chris@16
|
34 typedef RealType value_type;
|
Chris@16
|
35 typedef Policy policy_type;
|
Chris@16
|
36
|
Chris@16
|
37 students_t_distribution(RealType df) : df_(df)
|
Chris@16
|
38 { // Constructor.
|
Chris@16
|
39 RealType result;
|
Chris@16
|
40 detail::check_df_gt0_to_inf( // Checks that df > 0 or df == inf.
|
Chris@16
|
41 "boost::math::students_t_distribution<%1%>::students_t_distribution", df_, &result, Policy());
|
Chris@16
|
42 } // students_t_distribution
|
Chris@16
|
43
|
Chris@16
|
44 RealType degrees_of_freedom()const
|
Chris@16
|
45 {
|
Chris@16
|
46 return df_;
|
Chris@16
|
47 }
|
Chris@16
|
48
|
Chris@16
|
49 // Parameter estimation:
|
Chris@16
|
50 static RealType find_degrees_of_freedom(
|
Chris@16
|
51 RealType difference_from_mean,
|
Chris@16
|
52 RealType alpha,
|
Chris@16
|
53 RealType beta,
|
Chris@16
|
54 RealType sd,
|
Chris@16
|
55 RealType hint = 100);
|
Chris@16
|
56
|
Chris@16
|
57 private:
|
Chris@16
|
58 // Data member:
|
Chris@16
|
59 RealType df_; // degrees of freedom is a real number or +infinity.
|
Chris@16
|
60 };
|
Chris@16
|
61
|
Chris@16
|
62 typedef students_t_distribution<double> students_t; // Convenience typedef for double version.
|
Chris@16
|
63
|
Chris@16
|
64 template <class RealType, class Policy>
|
Chris@16
|
65 inline const std::pair<RealType, RealType> range(const students_t_distribution<RealType, Policy>& /*dist*/)
|
Chris@16
|
66 { // Range of permissible values for random variable x.
|
Chris@16
|
67 // NOT including infinity.
|
Chris@16
|
68 using boost::math::tools::max_value;
|
Chris@16
|
69 return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
|
Chris@16
|
70 }
|
Chris@16
|
71
|
Chris@16
|
72 template <class RealType, class Policy>
|
Chris@16
|
73 inline const std::pair<RealType, RealType> support(const students_t_distribution<RealType, Policy>& /*dist*/)
|
Chris@16
|
74 { // Range of supported values for random variable x.
|
Chris@16
|
75 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
|
Chris@16
|
76 using boost::math::tools::max_value;
|
Chris@16
|
77 return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
|
Chris@16
|
78 }
|
Chris@16
|
79
|
Chris@16
|
80 template <class RealType, class Policy>
|
Chris@16
|
81 inline RealType pdf(const students_t_distribution<RealType, Policy>& dist, const RealType& x)
|
Chris@16
|
82 {
|
Chris@16
|
83 BOOST_FPU_EXCEPTION_GUARD
|
Chris@16
|
84 BOOST_MATH_STD_USING // for ADL of std functions.
|
Chris@16
|
85
|
Chris@16
|
86 RealType error_result;
|
Chris@16
|
87 if(false == detail::check_x(
|
Chris@16
|
88 "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", x, &error_result, Policy()))
|
Chris@16
|
89 return error_result;
|
Chris@16
|
90 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
91 if(false == detail::check_df_gt0_to_inf( // Check that df > 0 or == +infinity.
|
Chris@16
|
92 "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", df, &error_result, Policy()))
|
Chris@16
|
93 return error_result;
|
Chris@16
|
94
|
Chris@16
|
95 RealType result;
|
Chris@16
|
96 if ((boost::math::isinf)(x))
|
Chris@16
|
97 { // +infinity.
|
Chris@16
|
98 normal_distribution<RealType, Policy> n(0, 1);
|
Chris@16
|
99 result = pdf(n, x);
|
Chris@16
|
100 return result;
|
Chris@16
|
101 }
|
Chris@16
|
102 RealType limit = policies::get_epsilon<RealType, Policy>();
|
Chris@16
|
103 // Use policies so that if policy requests lower precision,
|
Chris@16
|
104 // then get the normal distribution approximation earlier.
|
Chris@16
|
105 limit = static_cast<RealType>(1) / limit; // 1/eps
|
Chris@16
|
106 // for 64-bit double 1/eps = 4503599627370496
|
Chris@16
|
107 if (df > limit)
|
Chris@16
|
108 { // Special case for really big degrees_of_freedom > 1 / eps
|
Chris@16
|
109 // - use normal distribution which is much faster and more accurate.
|
Chris@16
|
110 normal_distribution<RealType, Policy> n(0, 1);
|
Chris@16
|
111 result = pdf(n, x);
|
Chris@16
|
112 }
|
Chris@16
|
113 else
|
Chris@16
|
114 { //
|
Chris@16
|
115 RealType basem1 = x * x / df;
|
Chris@16
|
116 if(basem1 < 0.125)
|
Chris@16
|
117 {
|
Chris@16
|
118 result = exp(-boost::math::log1p(basem1, Policy()) * (1+df) / 2);
|
Chris@16
|
119 }
|
Chris@16
|
120 else
|
Chris@16
|
121 {
|
Chris@16
|
122 result = pow(1 / (1 + basem1), (df + 1) / 2);
|
Chris@16
|
123 }
|
Chris@16
|
124 result /= sqrt(df) * boost::math::beta(df / 2, RealType(0.5f), Policy());
|
Chris@16
|
125 }
|
Chris@16
|
126 return result;
|
Chris@16
|
127 } // pdf
|
Chris@16
|
128
|
Chris@16
|
129 template <class RealType, class Policy>
|
Chris@16
|
130 inline RealType cdf(const students_t_distribution<RealType, Policy>& dist, const RealType& x)
|
Chris@16
|
131 {
|
Chris@16
|
132 RealType error_result;
|
Chris@16
|
133 if(false == detail::check_x(
|
Chris@16
|
134 "boost::math::pdf(const students_t_distribution<%1%>&, %1%)", x, &error_result, Policy()))
|
Chris@16
|
135 return error_result;
|
Chris@16
|
136 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
137 // Error check:
|
Chris@16
|
138
|
Chris@16
|
139 if(false == detail::check_df_gt0_to_inf( // Check that df > 0 or == +infinity.
|
Chris@16
|
140 "boost::math::cdf(const students_t_distribution<%1%>&, %1%)", df, &error_result, Policy()))
|
Chris@16
|
141 return error_result;
|
Chris@16
|
142
|
Chris@16
|
143 if (x == 0)
|
Chris@16
|
144 { // Special case with exact result.
|
Chris@16
|
145 return static_cast<RealType>(0.5);
|
Chris@16
|
146 }
|
Chris@16
|
147 if ((boost::math::isinf)(x))
|
Chris@16
|
148 { // +infinity.
|
Chris@16
|
149 normal_distribution<RealType, Policy> n(0, 1);
|
Chris@16
|
150 RealType result = cdf(n, x);
|
Chris@16
|
151 return result;
|
Chris@16
|
152 }
|
Chris@16
|
153 RealType limit = policies::get_epsilon<RealType, Policy>();
|
Chris@16
|
154 // Use policies so that if policy requests lower precision,
|
Chris@16
|
155 // then get the normal distribution approximation earlier.
|
Chris@16
|
156 limit = static_cast<RealType>(1) / limit; // 1/eps
|
Chris@16
|
157 // for 64-bit double 1/eps = 4503599627370496
|
Chris@16
|
158 if (df > limit)
|
Chris@16
|
159 { // Special case for really big degrees_of_freedom > 1 / eps (perhaps infinite?)
|
Chris@16
|
160 // - use normal distribution which is much faster and more accurate.
|
Chris@16
|
161 normal_distribution<RealType, Policy> n(0, 1);
|
Chris@16
|
162 RealType result = cdf(n, x);
|
Chris@16
|
163 return result;
|
Chris@16
|
164 }
|
Chris@16
|
165 else
|
Chris@16
|
166 { // normal df case.
|
Chris@16
|
167 //
|
Chris@16
|
168 // Calculate probability of Student's t using the incomplete beta function.
|
Chris@16
|
169 // probability = ibeta(degrees_of_freedom / 2, 1/2, degrees_of_freedom / (degrees_of_freedom + t*t))
|
Chris@16
|
170 //
|
Chris@16
|
171 // However when t is small compared to the degrees of freedom, that formula
|
Chris@16
|
172 // suffers from rounding error, use the identity formula to work around
|
Chris@16
|
173 // the problem:
|
Chris@16
|
174 //
|
Chris@16
|
175 // I[x](a,b) = 1 - I[1-x](b,a)
|
Chris@16
|
176 //
|
Chris@16
|
177 // and:
|
Chris@16
|
178 //
|
Chris@16
|
179 // x = df / (df + t^2)
|
Chris@16
|
180 //
|
Chris@16
|
181 // so:
|
Chris@16
|
182 //
|
Chris@16
|
183 // 1 - x = t^2 / (df + t^2)
|
Chris@16
|
184 //
|
Chris@16
|
185 RealType x2 = x * x;
|
Chris@16
|
186 RealType probability;
|
Chris@16
|
187 if(df > 2 * x2)
|
Chris@16
|
188 {
|
Chris@16
|
189 RealType z = x2 / (df + x2);
|
Chris@16
|
190 probability = ibetac(static_cast<RealType>(0.5), df / 2, z, Policy()) / 2;
|
Chris@16
|
191 }
|
Chris@16
|
192 else
|
Chris@16
|
193 {
|
Chris@16
|
194 RealType z = df / (df + x2);
|
Chris@16
|
195 probability = ibeta(df / 2, static_cast<RealType>(0.5), z, Policy()) / 2;
|
Chris@16
|
196 }
|
Chris@16
|
197 return (x > 0 ? 1 - probability : probability);
|
Chris@16
|
198 }
|
Chris@16
|
199 } // cdf
|
Chris@16
|
200
|
Chris@16
|
201 template <class RealType, class Policy>
|
Chris@16
|
202 inline RealType quantile(const students_t_distribution<RealType, Policy>& dist, const RealType& p)
|
Chris@16
|
203 {
|
Chris@16
|
204 BOOST_MATH_STD_USING // for ADL of std functions
|
Chris@16
|
205 //
|
Chris@16
|
206 // Obtain parameters:
|
Chris@16
|
207 RealType probability = p;
|
Chris@16
|
208
|
Chris@16
|
209 // Check for domain errors:
|
Chris@16
|
210 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
211 static const char* function = "boost::math::quantile(const students_t_distribution<%1%>&, %1%)";
|
Chris@16
|
212 RealType error_result;
|
Chris@16
|
213 if(false == (detail::check_df_gt0_to_inf( // Check that df > 0 or == +infinity.
|
Chris@16
|
214 function, df, &error_result, Policy())
|
Chris@16
|
215 && detail::check_probability(function, probability, &error_result, Policy())))
|
Chris@16
|
216 return error_result;
|
Chris@16
|
217 // Special cases, regardless of degrees_of_freedom.
|
Chris@16
|
218 if (probability == 0)
|
Chris@16
|
219 return -policies::raise_overflow_error<RealType>(function, 0, Policy());
|
Chris@16
|
220 if (probability == 1)
|
Chris@16
|
221 return policies::raise_overflow_error<RealType>(function, 0, Policy());
|
Chris@16
|
222 if (probability == static_cast<RealType>(0.5))
|
Chris@16
|
223 return 0; //
|
Chris@16
|
224 //
|
Chris@16
|
225 #if 0
|
Chris@16
|
226 // This next block is disabled in favour of a faster method than
|
Chris@16
|
227 // incomplete beta inverse, but code retained for future reference:
|
Chris@16
|
228 //
|
Chris@16
|
229 // Calculate quantile of Student's t using the incomplete beta function inverse:
|
Chris@16
|
230 //
|
Chris@16
|
231 probability = (probability > 0.5) ? 1 - probability : probability;
|
Chris@16
|
232 RealType t, x, y;
|
Chris@16
|
233 x = ibeta_inv(degrees_of_freedom / 2, RealType(0.5), 2 * probability, &y);
|
Chris@16
|
234 if(degrees_of_freedom * y > tools::max_value<RealType>() * x)
|
Chris@16
|
235 t = tools::overflow_error<RealType>(function);
|
Chris@16
|
236 else
|
Chris@16
|
237 t = sqrt(degrees_of_freedom * y / x);
|
Chris@16
|
238 //
|
Chris@16
|
239 // Figure out sign based on the size of p:
|
Chris@16
|
240 //
|
Chris@16
|
241 if(p < 0.5)
|
Chris@16
|
242 t = -t;
|
Chris@16
|
243
|
Chris@16
|
244 return t;
|
Chris@16
|
245 #endif
|
Chris@16
|
246 //
|
Chris@16
|
247 // Depending on how many digits RealType has, this may forward
|
Chris@16
|
248 // to the incomplete beta inverse as above. Otherwise uses a
|
Chris@16
|
249 // faster method that is accurate to ~15 digits everywhere
|
Chris@16
|
250 // and a couple of epsilon at double precision and in the central
|
Chris@16
|
251 // region where most use cases will occur...
|
Chris@16
|
252 //
|
Chris@16
|
253 return boost::math::detail::fast_students_t_quantile(df, probability, Policy());
|
Chris@16
|
254 } // quantile
|
Chris@16
|
255
|
Chris@16
|
256 template <class RealType, class Policy>
|
Chris@16
|
257 inline RealType cdf(const complemented2_type<students_t_distribution<RealType, Policy>, RealType>& c)
|
Chris@16
|
258 {
|
Chris@16
|
259 return cdf(c.dist, -c.param);
|
Chris@16
|
260 }
|
Chris@16
|
261
|
Chris@16
|
262 template <class RealType, class Policy>
|
Chris@16
|
263 inline RealType quantile(const complemented2_type<students_t_distribution<RealType, Policy>, RealType>& c)
|
Chris@16
|
264 {
|
Chris@16
|
265 return -quantile(c.dist, c.param);
|
Chris@16
|
266 }
|
Chris@16
|
267
|
Chris@16
|
268 //
|
Chris@16
|
269 // Parameter estimation follows:
|
Chris@16
|
270 //
|
Chris@16
|
271 namespace detail{
|
Chris@16
|
272 //
|
Chris@16
|
273 // Functors for finding degrees of freedom:
|
Chris@16
|
274 //
|
Chris@16
|
275 template <class RealType, class Policy>
|
Chris@16
|
276 struct sample_size_func
|
Chris@16
|
277 {
|
Chris@16
|
278 sample_size_func(RealType a, RealType b, RealType s, RealType d)
|
Chris@16
|
279 : alpha(a), beta(b), ratio(s*s/(d*d)) {}
|
Chris@16
|
280
|
Chris@16
|
281 RealType operator()(const RealType& df)
|
Chris@16
|
282 {
|
Chris@16
|
283 if(df <= tools::min_value<RealType>())
|
Chris@16
|
284 { //
|
Chris@16
|
285 return 1;
|
Chris@16
|
286 }
|
Chris@16
|
287 students_t_distribution<RealType, Policy> t(df);
|
Chris@16
|
288 RealType qa = quantile(complement(t, alpha));
|
Chris@16
|
289 RealType qb = quantile(complement(t, beta));
|
Chris@16
|
290 qa += qb;
|
Chris@16
|
291 qa *= qa;
|
Chris@16
|
292 qa *= ratio;
|
Chris@16
|
293 qa -= (df + 1);
|
Chris@16
|
294 return qa;
|
Chris@16
|
295 }
|
Chris@16
|
296 RealType alpha, beta, ratio;
|
Chris@16
|
297 };
|
Chris@16
|
298
|
Chris@16
|
299 } // namespace detail
|
Chris@16
|
300
|
Chris@16
|
301 template <class RealType, class Policy>
|
Chris@16
|
302 RealType students_t_distribution<RealType, Policy>::find_degrees_of_freedom(
|
Chris@16
|
303 RealType difference_from_mean,
|
Chris@16
|
304 RealType alpha,
|
Chris@16
|
305 RealType beta,
|
Chris@16
|
306 RealType sd,
|
Chris@16
|
307 RealType hint)
|
Chris@16
|
308 {
|
Chris@16
|
309 static const char* function = "boost::math::students_t_distribution<%1%>::find_degrees_of_freedom";
|
Chris@16
|
310 //
|
Chris@16
|
311 // Check for domain errors:
|
Chris@16
|
312 //
|
Chris@16
|
313 RealType error_result;
|
Chris@16
|
314 if(false == detail::check_probability(
|
Chris@16
|
315 function, alpha, &error_result, Policy())
|
Chris@16
|
316 && detail::check_probability(function, beta, &error_result, Policy()))
|
Chris@16
|
317 return error_result;
|
Chris@16
|
318
|
Chris@16
|
319 if(hint <= 0)
|
Chris@16
|
320 hint = 1;
|
Chris@16
|
321
|
Chris@16
|
322 detail::sample_size_func<RealType, Policy> f(alpha, beta, sd, difference_from_mean);
|
Chris@16
|
323 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
|
Chris@16
|
324 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
Chris@16
|
325 std::pair<RealType, RealType> r = tools::bracket_and_solve_root(f, hint, RealType(2), false, tol, max_iter, Policy());
|
Chris@16
|
326 RealType result = r.first + (r.second - r.first) / 2;
|
Chris@16
|
327 if(max_iter >= policies::get_max_root_iterations<Policy>())
|
Chris@16
|
328 {
|
Chris@101
|
329 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
|
Chris@16
|
330 " either there is no answer to how many degrees of freedom are required"
|
Chris@16
|
331 " or the answer is infinite. Current best guess is %1%", result, Policy());
|
Chris@16
|
332 }
|
Chris@16
|
333 return result;
|
Chris@16
|
334 }
|
Chris@16
|
335
|
Chris@16
|
336 template <class RealType, class Policy>
|
Chris@16
|
337 inline RealType mode(const students_t_distribution<RealType, Policy>& /*dist*/)
|
Chris@16
|
338 {
|
Chris@16
|
339 // Assume no checks on degrees of freedom are useful (unlike mean).
|
Chris@16
|
340 return 0; // Always zero by definition.
|
Chris@16
|
341 }
|
Chris@16
|
342
|
Chris@16
|
343 template <class RealType, class Policy>
|
Chris@16
|
344 inline RealType median(const students_t_distribution<RealType, Policy>& /*dist*/)
|
Chris@16
|
345 {
|
Chris@16
|
346 // Assume no checks on degrees of freedom are useful (unlike mean).
|
Chris@16
|
347 return 0; // Always zero by definition.
|
Chris@16
|
348 }
|
Chris@16
|
349
|
Chris@16
|
350 // See section 5.1 on moments at http://en.wikipedia.org/wiki/Student%27s_t-distribution
|
Chris@16
|
351
|
Chris@16
|
352 template <class RealType, class Policy>
|
Chris@16
|
353 inline RealType mean(const students_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
354 { // Revised for https://svn.boost.org/trac/boost/ticket/7177
|
Chris@16
|
355 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
356 if(((boost::math::isnan)(df)) || (df <= 1) )
|
Chris@16
|
357 { // mean is undefined for moment <= 1!
|
Chris@101
|
358 return policies::raise_domain_error<RealType>(
|
Chris@16
|
359 "boost::math::mean(students_t_distribution<%1%> const&, %1%)",
|
Chris@16
|
360 "Mean is undefined for degrees of freedom < 1 but got %1%.", df, Policy());
|
Chris@16
|
361 return std::numeric_limits<RealType>::quiet_NaN();
|
Chris@16
|
362 }
|
Chris@16
|
363 return 0;
|
Chris@16
|
364 } // mean
|
Chris@16
|
365
|
Chris@16
|
366 template <class RealType, class Policy>
|
Chris@16
|
367 inline RealType variance(const students_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
368 { // http://en.wikipedia.org/wiki/Student%27s_t-distribution
|
Chris@16
|
369 // Revised for https://svn.boost.org/trac/boost/ticket/7177
|
Chris@16
|
370 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
371 if ((boost::math::isnan)(df) || (df <= 2))
|
Chris@16
|
372 { // NaN or undefined for <= 2.
|
Chris@101
|
373 return policies::raise_domain_error<RealType>(
|
Chris@16
|
374 "boost::math::variance(students_t_distribution<%1%> const&, %1%)",
|
Chris@16
|
375 "variance is undefined for degrees of freedom <= 2, but got %1%.",
|
Chris@16
|
376 df, Policy());
|
Chris@16
|
377 return std::numeric_limits<RealType>::quiet_NaN(); // Undefined.
|
Chris@16
|
378 }
|
Chris@16
|
379 if ((boost::math::isinf)(df))
|
Chris@16
|
380 { // +infinity.
|
Chris@16
|
381 return 1;
|
Chris@16
|
382 }
|
Chris@16
|
383 RealType limit = policies::get_epsilon<RealType, Policy>();
|
Chris@16
|
384 // Use policies so that if policy requests lower precision,
|
Chris@16
|
385 // then get the normal distribution approximation earlier.
|
Chris@16
|
386 limit = static_cast<RealType>(1) / limit; // 1/eps
|
Chris@16
|
387 // for 64-bit double 1/eps = 4503599627370496
|
Chris@16
|
388 if (df > limit)
|
Chris@16
|
389 { // Special case for really big degrees_of_freedom > 1 / eps.
|
Chris@16
|
390 return 1;
|
Chris@16
|
391 }
|
Chris@16
|
392 else
|
Chris@16
|
393 {
|
Chris@16
|
394 return df / (df - 2);
|
Chris@16
|
395 }
|
Chris@16
|
396 } // variance
|
Chris@16
|
397
|
Chris@16
|
398 template <class RealType, class Policy>
|
Chris@16
|
399 inline RealType skewness(const students_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
400 {
|
Chris@16
|
401 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
402 if( ((boost::math::isnan)(df)) || (dist.degrees_of_freedom() <= 3))
|
Chris@16
|
403 { // Undefined for moment k = 3.
|
Chris@101
|
404 return policies::raise_domain_error<RealType>(
|
Chris@16
|
405 "boost::math::skewness(students_t_distribution<%1%> const&, %1%)",
|
Chris@16
|
406 "Skewness is undefined for degrees of freedom <= 3, but got %1%.",
|
Chris@16
|
407 dist.degrees_of_freedom(), Policy());
|
Chris@16
|
408 return std::numeric_limits<RealType>::quiet_NaN();
|
Chris@16
|
409 }
|
Chris@16
|
410 return 0; // For all valid df, including infinity.
|
Chris@16
|
411 } // skewness
|
Chris@16
|
412
|
Chris@16
|
413 template <class RealType, class Policy>
|
Chris@16
|
414 inline RealType kurtosis(const students_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
415 {
|
Chris@16
|
416 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
417 if(((boost::math::isnan)(df)) || (df <= 4))
|
Chris@16
|
418 { // Undefined or infinity for moment k = 4.
|
Chris@101
|
419 return policies::raise_domain_error<RealType>(
|
Chris@16
|
420 "boost::math::kurtosis(students_t_distribution<%1%> const&, %1%)",
|
Chris@16
|
421 "Kurtosis is undefined for degrees of freedom <= 4, but got %1%.",
|
Chris@16
|
422 df, Policy());
|
Chris@16
|
423 return std::numeric_limits<RealType>::quiet_NaN(); // Undefined.
|
Chris@16
|
424 }
|
Chris@16
|
425 if ((boost::math::isinf)(df))
|
Chris@16
|
426 { // +infinity.
|
Chris@16
|
427 return 3;
|
Chris@16
|
428 }
|
Chris@16
|
429 RealType limit = policies::get_epsilon<RealType, Policy>();
|
Chris@16
|
430 // Use policies so that if policy requests lower precision,
|
Chris@16
|
431 // then get the normal distribution approximation earlier.
|
Chris@16
|
432 limit = static_cast<RealType>(1) / limit; // 1/eps
|
Chris@16
|
433 // for 64-bit double 1/eps = 4503599627370496
|
Chris@16
|
434 if (df > limit)
|
Chris@16
|
435 { // Special case for really big degrees_of_freedom > 1 / eps.
|
Chris@16
|
436 return 3;
|
Chris@16
|
437 }
|
Chris@16
|
438 else
|
Chris@16
|
439 {
|
Chris@16
|
440 //return 3 * (df - 2) / (df - 4); re-arranged to
|
Chris@16
|
441 return 6 / (df - 4) + 3;
|
Chris@16
|
442 }
|
Chris@16
|
443 } // kurtosis
|
Chris@16
|
444
|
Chris@16
|
445 template <class RealType, class Policy>
|
Chris@16
|
446 inline RealType kurtosis_excess(const students_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
447 {
|
Chris@16
|
448 // see http://mathworld.wolfram.com/Kurtosis.html
|
Chris@16
|
449
|
Chris@16
|
450 RealType df = dist.degrees_of_freedom();
|
Chris@16
|
451 if(((boost::math::isnan)(df)) || (df <= 4))
|
Chris@16
|
452 { // Undefined or infinity for moment k = 4.
|
Chris@101
|
453 return policies::raise_domain_error<RealType>(
|
Chris@16
|
454 "boost::math::kurtosis_excess(students_t_distribution<%1%> const&, %1%)",
|
Chris@16
|
455 "Kurtosis_excess is undefined for degrees of freedom <= 4, but got %1%.",
|
Chris@16
|
456 df, Policy());
|
Chris@16
|
457 return std::numeric_limits<RealType>::quiet_NaN(); // Undefined.
|
Chris@16
|
458 }
|
Chris@16
|
459 if ((boost::math::isinf)(df))
|
Chris@16
|
460 { // +infinity.
|
Chris@16
|
461 return 0;
|
Chris@16
|
462 }
|
Chris@16
|
463 RealType limit = policies::get_epsilon<RealType, Policy>();
|
Chris@16
|
464 // Use policies so that if policy requests lower precision,
|
Chris@16
|
465 // then get the normal distribution approximation earlier.
|
Chris@16
|
466 limit = static_cast<RealType>(1) / limit; // 1/eps
|
Chris@16
|
467 // for 64-bit double 1/eps = 4503599627370496
|
Chris@16
|
468 if (df > limit)
|
Chris@16
|
469 { // Special case for really big degrees_of_freedom > 1 / eps.
|
Chris@16
|
470 return 0;
|
Chris@16
|
471 }
|
Chris@16
|
472 else
|
Chris@16
|
473 {
|
Chris@16
|
474 return 6 / (df - 4);
|
Chris@16
|
475 }
|
Chris@16
|
476 }
|
Chris@16
|
477
|
Chris@16
|
478 } // namespace math
|
Chris@16
|
479 } // namespace boost
|
Chris@16
|
480
|
Chris@16
|
481 #ifdef BOOST_MSVC
|
Chris@16
|
482 # pragma warning(pop)
|
Chris@16
|
483 #endif
|
Chris@16
|
484
|
Chris@16
|
485 // This include must be at the end, *after* the accessors
|
Chris@16
|
486 // for this distribution have been defined, in order to
|
Chris@16
|
487 // keep compilers that support two-phase lookup happy.
|
Chris@16
|
488 #include <boost/math/distributions/detail/derived_accessors.hpp>
|
Chris@16
|
489
|
Chris@16
|
490 #endif // BOOST_STATS_STUDENTS_T_HPP
|