Chris@16
|
1 // boost\math\distributions\non_central_t.hpp
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright John Maddock 2008.
|
Chris@16
|
4
|
Chris@16
|
5 // Use, modification and distribution are subject to the
|
Chris@16
|
6 // Boost Software License, Version 1.0.
|
Chris@16
|
7 // (See accompanying file LICENSE_1_0.txt
|
Chris@16
|
8 // or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9
|
Chris@16
|
10 #ifndef BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP
|
Chris@16
|
11 #define BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP
|
Chris@16
|
12
|
Chris@16
|
13 #include <boost/math/distributions/fwd.hpp>
|
Chris@16
|
14 #include <boost/math/distributions/non_central_beta.hpp> // for nc beta
|
Chris@16
|
15 #include <boost/math/distributions/normal.hpp> // for normal CDF and quantile
|
Chris@16
|
16 #include <boost/math/distributions/students_t.hpp>
|
Chris@16
|
17 #include <boost/math/distributions/detail/generic_quantile.hpp> // quantile
|
Chris@16
|
18
|
Chris@16
|
19 namespace boost
|
Chris@16
|
20 {
|
Chris@16
|
21 namespace math
|
Chris@16
|
22 {
|
Chris@16
|
23
|
Chris@16
|
24 template <class RealType, class Policy>
|
Chris@16
|
25 class non_central_t_distribution;
|
Chris@16
|
26
|
Chris@16
|
27 namespace detail{
|
Chris@16
|
28
|
Chris@16
|
29 template <class T, class Policy>
|
Chris@16
|
30 T non_central_t2_p(T v, T delta, T x, T y, const Policy& pol, T init_val)
|
Chris@16
|
31 {
|
Chris@16
|
32 BOOST_MATH_STD_USING
|
Chris@16
|
33 //
|
Chris@16
|
34 // Variables come first:
|
Chris@16
|
35 //
|
Chris@16
|
36 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
37 T errtol = policies::get_epsilon<T, Policy>();
|
Chris@16
|
38 T d2 = delta * delta / 2;
|
Chris@16
|
39 //
|
Chris@16
|
40 // k is the starting point for iteration, and is the
|
Chris@16
|
41 // maximum of the poisson weighting term, we don't
|
Chris@16
|
42 // ever allow k == 0 as this can lead to catastrophic
|
Chris@16
|
43 // cancellation errors later (test case is v = 1621286869049072.3
|
Chris@16
|
44 // delta = 0.16212868690490723, x = 0.86987415482475994).
|
Chris@16
|
45 //
|
Chris@16
|
46 int k = itrunc(d2);
|
Chris@16
|
47 T pois;
|
Chris@16
|
48 if(k == 0) k = 1;
|
Chris@16
|
49 // Starting Poisson weight:
|
Chris@16
|
50 pois = gamma_p_derivative(T(k+1), d2, pol)
|
Chris@16
|
51 * tgamma_delta_ratio(T(k + 1), T(0.5f))
|
Chris@16
|
52 * delta / constants::root_two<T>();
|
Chris@16
|
53 if(pois == 0)
|
Chris@16
|
54 return init_val;
|
Chris@16
|
55 T xterm, beta;
|
Chris@16
|
56 // Recurrance & starting beta terms:
|
Chris@16
|
57 beta = x < y
|
Chris@16
|
58 ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, false, true, &xterm)
|
Chris@16
|
59 : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, true, true, &xterm);
|
Chris@16
|
60 xterm *= y / (v / 2 + k);
|
Chris@16
|
61 T poisf(pois), betaf(beta), xtermf(xterm);
|
Chris@16
|
62 T sum = init_val;
|
Chris@16
|
63 if((xterm == 0) && (beta == 0))
|
Chris@16
|
64 return init_val;
|
Chris@16
|
65
|
Chris@16
|
66 //
|
Chris@16
|
67 // Backwards recursion first, this is the stable
|
Chris@16
|
68 // direction for recursion:
|
Chris@16
|
69 //
|
Chris@16
|
70 boost::uintmax_t count = 0;
|
Chris@16
|
71 T last_term = 0;
|
Chris@16
|
72 for(int i = k; i >= 0; --i)
|
Chris@16
|
73 {
|
Chris@16
|
74 T term = beta * pois;
|
Chris@16
|
75 sum += term;
|
Chris@16
|
76 // Don't terminate on first term in case we "fixed" k above:
|
Chris@16
|
77 if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol)
|
Chris@16
|
78 break;
|
Chris@16
|
79 last_term = term;
|
Chris@16
|
80 pois *= (i + 0.5f) / d2;
|
Chris@16
|
81 beta += xterm;
|
Chris@16
|
82 xterm *= (i) / (x * (v / 2 + i - 1));
|
Chris@16
|
83 ++count;
|
Chris@16
|
84 }
|
Chris@16
|
85 last_term = 0;
|
Chris@16
|
86 for(int i = k + 1; ; ++i)
|
Chris@16
|
87 {
|
Chris@16
|
88 poisf *= d2 / (i + 0.5f);
|
Chris@16
|
89 xtermf *= (x * (v / 2 + i - 1)) / (i);
|
Chris@16
|
90 betaf -= xtermf;
|
Chris@16
|
91 T term = poisf * betaf;
|
Chris@16
|
92 sum += term;
|
Chris@16
|
93 if((fabs(last_term) > fabs(term)) && (fabs(term/sum) < errtol))
|
Chris@16
|
94 break;
|
Chris@16
|
95 last_term = term;
|
Chris@16
|
96 ++count;
|
Chris@16
|
97 if(count > max_iter)
|
Chris@16
|
98 {
|
Chris@16
|
99 return policies::raise_evaluation_error(
|
Chris@16
|
100 "cdf(non_central_t_distribution<%1%>, %1%)",
|
Chris@16
|
101 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
102 }
|
Chris@16
|
103 }
|
Chris@16
|
104 return sum;
|
Chris@16
|
105 }
|
Chris@16
|
106
|
Chris@16
|
107 template <class T, class Policy>
|
Chris@16
|
108 T non_central_t2_q(T v, T delta, T x, T y, const Policy& pol, T init_val)
|
Chris@16
|
109 {
|
Chris@16
|
110 BOOST_MATH_STD_USING
|
Chris@16
|
111 //
|
Chris@16
|
112 // Variables come first:
|
Chris@16
|
113 //
|
Chris@16
|
114 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
115 T errtol = boost::math::policies::get_epsilon<T, Policy>();
|
Chris@16
|
116 T d2 = delta * delta / 2;
|
Chris@16
|
117 //
|
Chris@16
|
118 // k is the starting point for iteration, and is the
|
Chris@16
|
119 // maximum of the poisson weighting term, we don't allow
|
Chris@16
|
120 // k == 0 as this can cause catastrophic cancellation errors
|
Chris@16
|
121 // (test case is v = 561908036470413.25, delta = 0.056190803647041321,
|
Chris@16
|
122 // x = 1.6155232703966216):
|
Chris@16
|
123 //
|
Chris@16
|
124 int k = itrunc(d2);
|
Chris@16
|
125 if(k == 0) k = 1;
|
Chris@16
|
126 // Starting Poisson weight:
|
Chris@16
|
127 T pois;
|
Chris@16
|
128 if((k < (int)(max_factorial<T>::value)) && (d2 < tools::log_max_value<T>()) && (log(d2) * k < tools::log_max_value<T>()))
|
Chris@16
|
129 {
|
Chris@16
|
130 //
|
Chris@16
|
131 // For small k we can optimise this calculation by using
|
Chris@16
|
132 // a simpler reduced formula:
|
Chris@16
|
133 //
|
Chris@16
|
134 pois = exp(-d2);
|
Chris@16
|
135 pois *= pow(d2, static_cast<T>(k));
|
Chris@16
|
136 pois /= boost::math::tgamma(T(k + 1 + 0.5), pol);
|
Chris@16
|
137 pois *= delta / constants::root_two<T>();
|
Chris@16
|
138 }
|
Chris@16
|
139 else
|
Chris@16
|
140 {
|
Chris@16
|
141 pois = gamma_p_derivative(T(k+1), d2, pol)
|
Chris@16
|
142 * tgamma_delta_ratio(T(k + 1), T(0.5f))
|
Chris@16
|
143 * delta / constants::root_two<T>();
|
Chris@16
|
144 }
|
Chris@16
|
145 if(pois == 0)
|
Chris@16
|
146 return init_val;
|
Chris@16
|
147 // Recurance term:
|
Chris@16
|
148 T xterm;
|
Chris@16
|
149 T beta;
|
Chris@16
|
150 // Starting beta term:
|
Chris@16
|
151 if(k != 0)
|
Chris@16
|
152 {
|
Chris@16
|
153 beta = x < y
|
Chris@16
|
154 ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, true, true, &xterm)
|
Chris@16
|
155 : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, false, true, &xterm);
|
Chris@16
|
156
|
Chris@16
|
157 xterm *= y / (v / 2 + k);
|
Chris@16
|
158 }
|
Chris@16
|
159 else
|
Chris@16
|
160 {
|
Chris@16
|
161 beta = pow(y, v / 2);
|
Chris@16
|
162 xterm = beta;
|
Chris@16
|
163 }
|
Chris@16
|
164 T poisf(pois), betaf(beta), xtermf(xterm);
|
Chris@16
|
165 T sum = init_val;
|
Chris@16
|
166 if((xterm == 0) && (beta == 0))
|
Chris@16
|
167 return init_val;
|
Chris@16
|
168
|
Chris@16
|
169 //
|
Chris@16
|
170 // Fused forward and backwards recursion:
|
Chris@16
|
171 //
|
Chris@16
|
172 boost::uintmax_t count = 0;
|
Chris@16
|
173 T last_term = 0;
|
Chris@16
|
174 for(int i = k + 1, j = k; ; ++i, --j)
|
Chris@16
|
175 {
|
Chris@16
|
176 poisf *= d2 / (i + 0.5f);
|
Chris@16
|
177 xtermf *= (x * (v / 2 + i - 1)) / (i);
|
Chris@16
|
178 betaf += xtermf;
|
Chris@16
|
179 T term = poisf * betaf;
|
Chris@16
|
180
|
Chris@16
|
181 if(j >= 0)
|
Chris@16
|
182 {
|
Chris@16
|
183 term += beta * pois;
|
Chris@16
|
184 pois *= (j + 0.5f) / d2;
|
Chris@16
|
185 beta -= xterm;
|
Chris@16
|
186 xterm *= (j) / (x * (v / 2 + j - 1));
|
Chris@16
|
187 }
|
Chris@16
|
188
|
Chris@16
|
189 sum += term;
|
Chris@16
|
190 // Don't terminate on first term in case we "fixed" the value of k above:
|
Chris@16
|
191 if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol)
|
Chris@16
|
192 break;
|
Chris@16
|
193 last_term = term;
|
Chris@16
|
194 if(count > max_iter)
|
Chris@16
|
195 {
|
Chris@16
|
196 return policies::raise_evaluation_error(
|
Chris@16
|
197 "cdf(non_central_t_distribution<%1%>, %1%)",
|
Chris@16
|
198 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
199 }
|
Chris@16
|
200 ++count;
|
Chris@16
|
201 }
|
Chris@16
|
202 return sum;
|
Chris@16
|
203 }
|
Chris@16
|
204
|
Chris@16
|
205 template <class T, class Policy>
|
Chris@16
|
206 T non_central_t_cdf(T v, T delta, T t, bool invert, const Policy& pol)
|
Chris@16
|
207 {
|
Chris@16
|
208 BOOST_MATH_STD_USING
|
Chris@16
|
209 if ((boost::math::isinf)(v))
|
Chris@16
|
210 { // Infinite degrees of freedom, so use normal distribution located at delta.
|
Chris@16
|
211 normal_distribution<T, Policy> n(delta, 1);
|
Chris@16
|
212 return cdf(n, t);
|
Chris@16
|
213 }
|
Chris@16
|
214 //
|
Chris@16
|
215 // Otherwise, for t < 0 we have to use the reflection formula:
|
Chris@16
|
216 if(t < 0)
|
Chris@16
|
217 {
|
Chris@16
|
218 t = -t;
|
Chris@16
|
219 delta = -delta;
|
Chris@16
|
220 invert = !invert;
|
Chris@16
|
221 }
|
Chris@16
|
222 if(fabs(delta / (4 * v)) < policies::get_epsilon<T, Policy>())
|
Chris@16
|
223 {
|
Chris@16
|
224 // Approximate with a Student's T centred on delta,
|
Chris@16
|
225 // the crossover point is based on eq 2.6 from
|
Chris@16
|
226 // "A Comparison of Approximations To Percentiles of the
|
Chris@16
|
227 // Noncentral t-Distribution". H. Sahai and M. M. Ojeda,
|
Chris@16
|
228 // Revista Investigacion Operacional Vol 21, No 2, 2000.
|
Chris@16
|
229 // Original sources referenced in the above are:
|
Chris@16
|
230 // "Some Approximations to the Percentage Points of the Noncentral
|
Chris@16
|
231 // t-Distribution". C. van Eeden. International Statistical Review, 29, 4-31.
|
Chris@16
|
232 // "Continuous Univariate Distributions". N.L. Johnson, S. Kotz and
|
Chris@16
|
233 // N. Balkrishnan. 1995. John Wiley and Sons New York.
|
Chris@16
|
234 T result = cdf(students_t_distribution<T, Policy>(v), t - delta);
|
Chris@16
|
235 return invert ? 1 - result : result;
|
Chris@16
|
236 }
|
Chris@16
|
237 //
|
Chris@16
|
238 // x and y are the corresponding random
|
Chris@16
|
239 // variables for the noncentral beta distribution,
|
Chris@16
|
240 // with y = 1 - x:
|
Chris@16
|
241 //
|
Chris@16
|
242 T x = t * t / (v + t * t);
|
Chris@16
|
243 T y = v / (v + t * t);
|
Chris@16
|
244 T d2 = delta * delta;
|
Chris@16
|
245 T a = 0.5f;
|
Chris@16
|
246 T b = v / 2;
|
Chris@16
|
247 T c = a + b + d2 / 2;
|
Chris@16
|
248 //
|
Chris@16
|
249 // Crossover point for calculating p or q is the same
|
Chris@16
|
250 // as for the noncentral beta:
|
Chris@16
|
251 //
|
Chris@16
|
252 T cross = 1 - (b / c) * (1 + d2 / (2 * c * c));
|
Chris@16
|
253 T result;
|
Chris@16
|
254 if(x < cross)
|
Chris@16
|
255 {
|
Chris@16
|
256 //
|
Chris@16
|
257 // Calculate p:
|
Chris@16
|
258 //
|
Chris@16
|
259 if(x != 0)
|
Chris@16
|
260 {
|
Chris@16
|
261 result = non_central_beta_p(a, b, d2, x, y, pol);
|
Chris@16
|
262 result = non_central_t2_p(v, delta, x, y, pol, result);
|
Chris@16
|
263 result /= 2;
|
Chris@16
|
264 }
|
Chris@16
|
265 else
|
Chris@16
|
266 result = 0;
|
Chris@16
|
267 result += cdf(boost::math::normal_distribution<T, Policy>(), -delta);
|
Chris@16
|
268 }
|
Chris@16
|
269 else
|
Chris@16
|
270 {
|
Chris@16
|
271 //
|
Chris@16
|
272 // Calculate q:
|
Chris@16
|
273 //
|
Chris@16
|
274 invert = !invert;
|
Chris@16
|
275 if(x != 0)
|
Chris@16
|
276 {
|
Chris@16
|
277 result = non_central_beta_q(a, b, d2, x, y, pol);
|
Chris@16
|
278 result = non_central_t2_q(v, delta, x, y, pol, result);
|
Chris@16
|
279 result /= 2;
|
Chris@16
|
280 }
|
Chris@16
|
281 else // x == 0
|
Chris@16
|
282 result = cdf(complement(boost::math::normal_distribution<T, Policy>(), -delta));
|
Chris@16
|
283 }
|
Chris@16
|
284 if(invert)
|
Chris@16
|
285 result = 1 - result;
|
Chris@16
|
286 return result;
|
Chris@16
|
287 }
|
Chris@16
|
288
|
Chris@16
|
289 template <class T, class Policy>
|
Chris@16
|
290 T non_central_t_quantile(const char* function, T v, T delta, T p, T q, const Policy&)
|
Chris@16
|
291 {
|
Chris@16
|
292 BOOST_MATH_STD_USING
|
Chris@16
|
293 // static const char* function = "quantile(non_central_t_distribution<%1%>, %1%)";
|
Chris@16
|
294 // now passed as function
|
Chris@16
|
295 typedef typename policies::evaluation<T, Policy>::type value_type;
|
Chris@16
|
296 typedef typename policies::normalise<
|
Chris@16
|
297 Policy,
|
Chris@16
|
298 policies::promote_float<false>,
|
Chris@16
|
299 policies::promote_double<false>,
|
Chris@16
|
300 policies::discrete_quantile<>,
|
Chris@16
|
301 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
302
|
Chris@16
|
303 T r;
|
Chris@16
|
304 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
305 function,
|
Chris@16
|
306 v, &r, Policy())
|
Chris@16
|
307 ||
|
Chris@16
|
308 !detail::check_finite(
|
Chris@16
|
309 function,
|
Chris@16
|
310 delta,
|
Chris@16
|
311 &r,
|
Chris@16
|
312 Policy())
|
Chris@16
|
313 ||
|
Chris@16
|
314 !detail::check_probability(
|
Chris@16
|
315 function,
|
Chris@16
|
316 p,
|
Chris@16
|
317 &r,
|
Chris@16
|
318 Policy()))
|
Chris@16
|
319 return r;
|
Chris@16
|
320
|
Chris@16
|
321
|
Chris@16
|
322 value_type guess = 0;
|
Chris@16
|
323 if ( ((boost::math::isinf)(v)) || (v > 1 / boost::math::tools::epsilon<T>()) )
|
Chris@16
|
324 { // Infinite or very large degrees of freedom, so use normal distribution located at delta.
|
Chris@16
|
325 normal_distribution<T, Policy> n(delta, 1);
|
Chris@16
|
326 if (p < q)
|
Chris@16
|
327 {
|
Chris@16
|
328 return quantile(n, p);
|
Chris@16
|
329 }
|
Chris@16
|
330 else
|
Chris@16
|
331 {
|
Chris@16
|
332 return quantile(complement(n, q));
|
Chris@16
|
333 }
|
Chris@16
|
334 }
|
Chris@16
|
335 else if(v > 3)
|
Chris@16
|
336 { // Use normal distribution to calculate guess.
|
Chris@16
|
337 value_type mean = (v > 1 / policies::get_epsilon<T, Policy>()) ? delta : delta * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, T(0.5f));
|
Chris@16
|
338 value_type var = (v > 1 / policies::get_epsilon<T, Policy>()) ? value_type(1) : (((delta * delta + 1) * v) / (v - 2) - mean * mean);
|
Chris@16
|
339 if(p < q)
|
Chris@16
|
340 guess = quantile(normal_distribution<value_type, forwarding_policy>(mean, var), p);
|
Chris@16
|
341 else
|
Chris@16
|
342 guess = quantile(complement(normal_distribution<value_type, forwarding_policy>(mean, var), q));
|
Chris@16
|
343 }
|
Chris@16
|
344 //
|
Chris@16
|
345 // We *must* get the sign of the initial guess correct,
|
Chris@16
|
346 // or our root-finder will fail, so double check it now:
|
Chris@16
|
347 //
|
Chris@16
|
348 value_type pzero = non_central_t_cdf(
|
Chris@16
|
349 static_cast<value_type>(v),
|
Chris@16
|
350 static_cast<value_type>(delta),
|
Chris@16
|
351 static_cast<value_type>(0),
|
Chris@16
|
352 !(p < q),
|
Chris@16
|
353 forwarding_policy());
|
Chris@16
|
354 int s;
|
Chris@16
|
355 if(p < q)
|
Chris@16
|
356 s = boost::math::sign(p - pzero);
|
Chris@16
|
357 else
|
Chris@16
|
358 s = boost::math::sign(pzero - q);
|
Chris@16
|
359 if(s != boost::math::sign(guess))
|
Chris@16
|
360 {
|
Chris@16
|
361 guess = s;
|
Chris@16
|
362 }
|
Chris@16
|
363
|
Chris@16
|
364 value_type result = detail::generic_quantile(
|
Chris@16
|
365 non_central_t_distribution<value_type, forwarding_policy>(v, delta),
|
Chris@16
|
366 (p < q ? p : q),
|
Chris@16
|
367 guess,
|
Chris@16
|
368 (p >= q),
|
Chris@16
|
369 function);
|
Chris@16
|
370 return policies::checked_narrowing_cast<T, forwarding_policy>(
|
Chris@16
|
371 result,
|
Chris@16
|
372 function);
|
Chris@16
|
373 }
|
Chris@16
|
374
|
Chris@16
|
375 template <class T, class Policy>
|
Chris@16
|
376 T non_central_t2_pdf(T n, T delta, T x, T y, const Policy& pol, T init_val)
|
Chris@16
|
377 {
|
Chris@16
|
378 BOOST_MATH_STD_USING
|
Chris@16
|
379 //
|
Chris@16
|
380 // Variables come first:
|
Chris@16
|
381 //
|
Chris@16
|
382 boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
|
Chris@16
|
383 T errtol = boost::math::policies::get_epsilon<T, Policy>();
|
Chris@16
|
384 T d2 = delta * delta / 2;
|
Chris@16
|
385 //
|
Chris@16
|
386 // k is the starting point for iteration, and is the
|
Chris@16
|
387 // maximum of the poisson weighting term:
|
Chris@16
|
388 //
|
Chris@16
|
389 int k = itrunc(d2);
|
Chris@16
|
390 T pois, xterm;
|
Chris@16
|
391 if(k == 0)
|
Chris@16
|
392 k = 1;
|
Chris@16
|
393 // Starting Poisson weight:
|
Chris@16
|
394 pois = gamma_p_derivative(T(k+1), d2, pol)
|
Chris@16
|
395 * tgamma_delta_ratio(T(k + 1), T(0.5f))
|
Chris@16
|
396 * delta / constants::root_two<T>();
|
Chris@16
|
397 // Starting beta term:
|
Chris@16
|
398 xterm = x < y
|
Chris@16
|
399 ? ibeta_derivative(T(k + 1), n / 2, x, pol)
|
Chris@16
|
400 : ibeta_derivative(n / 2, T(k + 1), y, pol);
|
Chris@16
|
401 T poisf(pois), xtermf(xterm);
|
Chris@16
|
402 T sum = init_val;
|
Chris@16
|
403 if((pois == 0) || (xterm == 0))
|
Chris@16
|
404 return init_val;
|
Chris@16
|
405
|
Chris@16
|
406 //
|
Chris@16
|
407 // Backwards recursion first, this is the stable
|
Chris@16
|
408 // direction for recursion:
|
Chris@16
|
409 //
|
Chris@16
|
410 boost::uintmax_t count = 0;
|
Chris@16
|
411 for(int i = k; i >= 0; --i)
|
Chris@16
|
412 {
|
Chris@16
|
413 T term = xterm * pois;
|
Chris@16
|
414 sum += term;
|
Chris@16
|
415 if(((fabs(term/sum) < errtol) && (i != k)) || (term == 0))
|
Chris@16
|
416 break;
|
Chris@16
|
417 pois *= (i + 0.5f) / d2;
|
Chris@16
|
418 xterm *= (i) / (x * (n / 2 + i));
|
Chris@16
|
419 ++count;
|
Chris@16
|
420 if(count > max_iter)
|
Chris@16
|
421 {
|
Chris@16
|
422 return policies::raise_evaluation_error(
|
Chris@16
|
423 "pdf(non_central_t_distribution<%1%>, %1%)",
|
Chris@16
|
424 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
425 }
|
Chris@16
|
426 }
|
Chris@16
|
427 for(int i = k + 1; ; ++i)
|
Chris@16
|
428 {
|
Chris@16
|
429 poisf *= d2 / (i + 0.5f);
|
Chris@16
|
430 xtermf *= (x * (n / 2 + i)) / (i);
|
Chris@16
|
431 T term = poisf * xtermf;
|
Chris@16
|
432 sum += term;
|
Chris@16
|
433 if((fabs(term/sum) < errtol) || (term == 0))
|
Chris@16
|
434 break;
|
Chris@16
|
435 ++count;
|
Chris@16
|
436 if(count > max_iter)
|
Chris@16
|
437 {
|
Chris@16
|
438 return policies::raise_evaluation_error(
|
Chris@16
|
439 "pdf(non_central_t_distribution<%1%>, %1%)",
|
Chris@16
|
440 "Series did not converge, closest value was %1%", sum, pol);
|
Chris@16
|
441 }
|
Chris@16
|
442 }
|
Chris@16
|
443 return sum;
|
Chris@16
|
444 }
|
Chris@16
|
445
|
Chris@16
|
446 template <class T, class Policy>
|
Chris@16
|
447 T non_central_t_pdf(T n, T delta, T t, const Policy& pol)
|
Chris@16
|
448 {
|
Chris@16
|
449 BOOST_MATH_STD_USING
|
Chris@16
|
450 if ((boost::math::isinf)(n))
|
Chris@16
|
451 { // Infinite degrees of freedom, so use normal distribution located at delta.
|
Chris@16
|
452 normal_distribution<T, Policy> norm(delta, 1);
|
Chris@16
|
453 return pdf(norm, t);
|
Chris@16
|
454 }
|
Chris@16
|
455 //
|
Chris@16
|
456 // Otherwise, for t < 0 we have to use the reflection formula:
|
Chris@16
|
457 if(t < 0)
|
Chris@16
|
458 {
|
Chris@16
|
459 t = -t;
|
Chris@16
|
460 delta = -delta;
|
Chris@16
|
461 }
|
Chris@16
|
462 if(t == 0)
|
Chris@16
|
463 {
|
Chris@16
|
464 //
|
Chris@16
|
465 // Handle this as a special case, using the formula
|
Chris@16
|
466 // from Weisstein, Eric W.
|
Chris@16
|
467 // "Noncentral Student's t-Distribution."
|
Chris@16
|
468 // From MathWorld--A Wolfram Web Resource.
|
Chris@16
|
469 // http://mathworld.wolfram.com/NoncentralStudentst-Distribution.html
|
Chris@16
|
470 //
|
Chris@16
|
471 // The formula is simplified thanks to the relation
|
Chris@16
|
472 // 1F1(a,b,0) = 1.
|
Chris@16
|
473 //
|
Chris@16
|
474 return tgamma_delta_ratio(n / 2 + 0.5f, T(0.5f))
|
Chris@16
|
475 * sqrt(n / constants::pi<T>())
|
Chris@16
|
476 * exp(-delta * delta / 2) / 2;
|
Chris@16
|
477 }
|
Chris@16
|
478 if(fabs(delta / (4 * n)) < policies::get_epsilon<T, Policy>())
|
Chris@16
|
479 {
|
Chris@16
|
480 // Approximate with a Student's T centred on delta,
|
Chris@16
|
481 // the crossover point is based on eq 2.6 from
|
Chris@16
|
482 // "A Comparison of Approximations To Percentiles of the
|
Chris@16
|
483 // Noncentral t-Distribution". H. Sahai and M. M. Ojeda,
|
Chris@16
|
484 // Revista Investigacion Operacional Vol 21, No 2, 2000.
|
Chris@16
|
485 // Original sources referenced in the above are:
|
Chris@16
|
486 // "Some Approximations to the Percentage Points of the Noncentral
|
Chris@16
|
487 // t-Distribution". C. van Eeden. International Statistical Review, 29, 4-31.
|
Chris@16
|
488 // "Continuous Univariate Distributions". N.L. Johnson, S. Kotz and
|
Chris@16
|
489 // N. Balkrishnan. 1995. John Wiley and Sons New York.
|
Chris@16
|
490 return pdf(students_t_distribution<T, Policy>(n), t - delta);
|
Chris@16
|
491 }
|
Chris@16
|
492 //
|
Chris@16
|
493 // x and y are the corresponding random
|
Chris@16
|
494 // variables for the noncentral beta distribution,
|
Chris@16
|
495 // with y = 1 - x:
|
Chris@16
|
496 //
|
Chris@16
|
497 T x = t * t / (n + t * t);
|
Chris@16
|
498 T y = n / (n + t * t);
|
Chris@16
|
499 T a = 0.5f;
|
Chris@16
|
500 T b = n / 2;
|
Chris@16
|
501 T d2 = delta * delta;
|
Chris@16
|
502 //
|
Chris@16
|
503 // Calculate pdf:
|
Chris@16
|
504 //
|
Chris@16
|
505 T dt = n * t / (n * n + 2 * n * t * t + t * t * t * t);
|
Chris@16
|
506 T result = non_central_beta_pdf(a, b, d2, x, y, pol);
|
Chris@16
|
507 T tol = tools::epsilon<T>() * result * 500;
|
Chris@16
|
508 result = non_central_t2_pdf(n, delta, x, y, pol, result);
|
Chris@16
|
509 if(result <= tol)
|
Chris@16
|
510 result = 0;
|
Chris@16
|
511 result *= dt;
|
Chris@16
|
512 return result;
|
Chris@16
|
513 }
|
Chris@16
|
514
|
Chris@16
|
515 template <class T, class Policy>
|
Chris@16
|
516 T mean(T v, T delta, const Policy& pol)
|
Chris@16
|
517 {
|
Chris@16
|
518 if ((boost::math::isinf)(v))
|
Chris@16
|
519 {
|
Chris@16
|
520 return delta;
|
Chris@16
|
521 }
|
Chris@16
|
522 BOOST_MATH_STD_USING
|
Chris@16
|
523 if (v > 1 / boost::math::tools::epsilon<T>() )
|
Chris@16
|
524 {
|
Chris@16
|
525 //normal_distribution<T, Policy> n(delta, 1);
|
Chris@16
|
526 //return boost::math::mean(n);
|
Chris@16
|
527 return delta;
|
Chris@16
|
528 }
|
Chris@16
|
529 else
|
Chris@16
|
530 {
|
Chris@16
|
531 return delta * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, T(0.5f), pol);
|
Chris@16
|
532 }
|
Chris@16
|
533 // Other moments use mean so using normal distribution is propagated.
|
Chris@16
|
534 }
|
Chris@16
|
535
|
Chris@16
|
536 template <class T, class Policy>
|
Chris@16
|
537 T variance(T v, T delta, const Policy& pol)
|
Chris@16
|
538 {
|
Chris@16
|
539 if ((boost::math::isinf)(v))
|
Chris@16
|
540 {
|
Chris@16
|
541 return 1;
|
Chris@16
|
542 }
|
Chris@16
|
543 if (delta == 0)
|
Chris@16
|
544 { // == Student's t
|
Chris@16
|
545 return v / (v - 2);
|
Chris@16
|
546 }
|
Chris@16
|
547 T result = ((delta * delta + 1) * v) / (v - 2);
|
Chris@16
|
548 T m = mean(v, delta, pol);
|
Chris@16
|
549 result -= m * m;
|
Chris@16
|
550 return result;
|
Chris@16
|
551 }
|
Chris@16
|
552
|
Chris@16
|
553 template <class T, class Policy>
|
Chris@16
|
554 T skewness(T v, T delta, const Policy& pol)
|
Chris@16
|
555 {
|
Chris@16
|
556 BOOST_MATH_STD_USING
|
Chris@16
|
557 if ((boost::math::isinf)(v))
|
Chris@16
|
558 {
|
Chris@16
|
559 return 0;
|
Chris@16
|
560 }
|
Chris@16
|
561 if(delta == 0)
|
Chris@16
|
562 { // == Student's t
|
Chris@16
|
563 return 0;
|
Chris@16
|
564 }
|
Chris@16
|
565 T mean = boost::math::detail::mean(v, delta, pol);
|
Chris@16
|
566 T l2 = delta * delta;
|
Chris@16
|
567 T var = ((l2 + 1) * v) / (v - 2) - mean * mean;
|
Chris@16
|
568 T result = -2 * var;
|
Chris@16
|
569 result += v * (l2 + 2 * v - 3) / ((v - 3) * (v - 2));
|
Chris@16
|
570 result *= mean;
|
Chris@16
|
571 result /= pow(var, T(1.5f));
|
Chris@16
|
572 return result;
|
Chris@16
|
573 }
|
Chris@16
|
574
|
Chris@16
|
575 template <class T, class Policy>
|
Chris@16
|
576 T kurtosis_excess(T v, T delta, const Policy& pol)
|
Chris@16
|
577 {
|
Chris@16
|
578 BOOST_MATH_STD_USING
|
Chris@16
|
579 if ((boost::math::isinf)(v))
|
Chris@16
|
580 {
|
Chris@16
|
581 return 3;
|
Chris@16
|
582 }
|
Chris@16
|
583 if (delta == 0)
|
Chris@16
|
584 { // == Student's t
|
Chris@16
|
585 return 3;
|
Chris@16
|
586 }
|
Chris@16
|
587 T mean = boost::math::detail::mean(v, delta, pol);
|
Chris@16
|
588 T l2 = delta * delta;
|
Chris@16
|
589 T var = ((l2 + 1) * v) / (v - 2) - mean * mean;
|
Chris@16
|
590 T result = -3 * var;
|
Chris@16
|
591 result += v * (l2 * (v + 1) + 3 * (3 * v - 5)) / ((v - 3) * (v - 2));
|
Chris@16
|
592 result *= -mean * mean;
|
Chris@16
|
593 result += v * v * (l2 * l2 + 6 * l2 + 3) / ((v - 4) * (v - 2));
|
Chris@16
|
594 result /= var * var;
|
Chris@16
|
595 return result;
|
Chris@16
|
596 }
|
Chris@16
|
597
|
Chris@16
|
598 #if 0
|
Chris@16
|
599 //
|
Chris@16
|
600 // This code is disabled, since there can be multiple answers to the
|
Chris@16
|
601 // question, and it's not clear how to find the "right" one.
|
Chris@16
|
602 //
|
Chris@16
|
603 template <class RealType, class Policy>
|
Chris@16
|
604 struct t_degrees_of_freedom_finder
|
Chris@16
|
605 {
|
Chris@16
|
606 t_degrees_of_freedom_finder(
|
Chris@16
|
607 RealType delta_, RealType x_, RealType p_, bool c)
|
Chris@16
|
608 : delta(delta_), x(x_), p(p_), comp(c) {}
|
Chris@16
|
609
|
Chris@16
|
610 RealType operator()(const RealType& v)
|
Chris@16
|
611 {
|
Chris@16
|
612 non_central_t_distribution<RealType, Policy> d(v, delta);
|
Chris@16
|
613 return comp ?
|
Chris@16
|
614 p - cdf(complement(d, x))
|
Chris@16
|
615 : cdf(d, x) - p;
|
Chris@16
|
616 }
|
Chris@16
|
617 private:
|
Chris@16
|
618 RealType delta;
|
Chris@16
|
619 RealType x;
|
Chris@16
|
620 RealType p;
|
Chris@16
|
621 bool comp;
|
Chris@16
|
622 };
|
Chris@16
|
623
|
Chris@16
|
624 template <class RealType, class Policy>
|
Chris@16
|
625 inline RealType find_t_degrees_of_freedom(
|
Chris@16
|
626 RealType delta, RealType x, RealType p, RealType q, const Policy& pol)
|
Chris@16
|
627 {
|
Chris@16
|
628 const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
|
Chris@16
|
629 if((p == 0) || (q == 0))
|
Chris@16
|
630 {
|
Chris@16
|
631 //
|
Chris@16
|
632 // Can't a thing if one of p and q is zero:
|
Chris@16
|
633 //
|
Chris@16
|
634 return policies::raise_evaluation_error<RealType>(function,
|
Chris@16
|
635 "Can't find degrees of freedom when the probability is 0 or 1, only possible answer is %1%",
|
Chris@16
|
636 RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy());
|
Chris@16
|
637 }
|
Chris@16
|
638 t_degrees_of_freedom_finder<RealType, Policy> f(delta, x, p < q ? p : q, p < q ? false : true);
|
Chris@16
|
639 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
|
Chris@16
|
640 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
Chris@16
|
641 //
|
Chris@16
|
642 // Pick an initial guess:
|
Chris@16
|
643 //
|
Chris@16
|
644 RealType guess = 200;
|
Chris@16
|
645 std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
|
Chris@16
|
646 f, guess, RealType(2), false, tol, max_iter, pol);
|
Chris@16
|
647 RealType result = ir.first + (ir.second - ir.first) / 2;
|
Chris@16
|
648 if(max_iter >= policies::get_max_root_iterations<Policy>())
|
Chris@16
|
649 {
|
Chris@101
|
650 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
|
Chris@16
|
651 " or there is no answer to problem. Current best guess is %1%", result, Policy());
|
Chris@16
|
652 }
|
Chris@16
|
653 return result;
|
Chris@16
|
654 }
|
Chris@16
|
655
|
Chris@16
|
656 template <class RealType, class Policy>
|
Chris@16
|
657 struct t_non_centrality_finder
|
Chris@16
|
658 {
|
Chris@16
|
659 t_non_centrality_finder(
|
Chris@16
|
660 RealType v_, RealType x_, RealType p_, bool c)
|
Chris@16
|
661 : v(v_), x(x_), p(p_), comp(c) {}
|
Chris@16
|
662
|
Chris@16
|
663 RealType operator()(const RealType& delta)
|
Chris@16
|
664 {
|
Chris@16
|
665 non_central_t_distribution<RealType, Policy> d(v, delta);
|
Chris@16
|
666 return comp ?
|
Chris@16
|
667 p - cdf(complement(d, x))
|
Chris@16
|
668 : cdf(d, x) - p;
|
Chris@16
|
669 }
|
Chris@16
|
670 private:
|
Chris@16
|
671 RealType v;
|
Chris@16
|
672 RealType x;
|
Chris@16
|
673 RealType p;
|
Chris@16
|
674 bool comp;
|
Chris@16
|
675 };
|
Chris@16
|
676
|
Chris@16
|
677 template <class RealType, class Policy>
|
Chris@16
|
678 inline RealType find_t_non_centrality(
|
Chris@16
|
679 RealType v, RealType x, RealType p, RealType q, const Policy& pol)
|
Chris@16
|
680 {
|
Chris@16
|
681 const char* function = "non_central_t<%1%>::find_t_non_centrality";
|
Chris@16
|
682 if((p == 0) || (q == 0))
|
Chris@16
|
683 {
|
Chris@16
|
684 //
|
Chris@16
|
685 // Can't do a thing if one of p and q is zero:
|
Chris@16
|
686 //
|
Chris@16
|
687 return policies::raise_evaluation_error<RealType>(function,
|
Chris@16
|
688 "Can't find non-centrality parameter when the probability is 0 or 1, only possible answer is %1%",
|
Chris@16
|
689 RealType(std::numeric_limits<RealType>::quiet_NaN()), Policy());
|
Chris@16
|
690 }
|
Chris@16
|
691 t_non_centrality_finder<RealType, Policy> f(v, x, p < q ? p : q, p < q ? false : true);
|
Chris@16
|
692 tools::eps_tolerance<RealType> tol(policies::digits<RealType, Policy>());
|
Chris@16
|
693 boost::uintmax_t max_iter = policies::get_max_root_iterations<Policy>();
|
Chris@16
|
694 //
|
Chris@16
|
695 // Pick an initial guess that we know is the right side of
|
Chris@16
|
696 // zero:
|
Chris@16
|
697 //
|
Chris@16
|
698 RealType guess;
|
Chris@16
|
699 if(f(0) < 0)
|
Chris@16
|
700 guess = 1;
|
Chris@16
|
701 else
|
Chris@16
|
702 guess = -1;
|
Chris@16
|
703 std::pair<RealType, RealType> ir = tools::bracket_and_solve_root(
|
Chris@16
|
704 f, guess, RealType(2), false, tol, max_iter, pol);
|
Chris@16
|
705 RealType result = ir.first + (ir.second - ir.first) / 2;
|
Chris@16
|
706 if(max_iter >= policies::get_max_root_iterations<Policy>())
|
Chris@16
|
707 {
|
Chris@101
|
708 return policies::raise_evaluation_error<RealType>(function, "Unable to locate solution in a reasonable time:"
|
Chris@16
|
709 " or there is no answer to problem. Current best guess is %1%", result, Policy());
|
Chris@16
|
710 }
|
Chris@16
|
711 return result;
|
Chris@16
|
712 }
|
Chris@16
|
713 #endif
|
Chris@16
|
714 } // namespace detail ======================================================================
|
Chris@16
|
715
|
Chris@16
|
716 template <class RealType = double, class Policy = policies::policy<> >
|
Chris@16
|
717 class non_central_t_distribution
|
Chris@16
|
718 {
|
Chris@16
|
719 public:
|
Chris@16
|
720 typedef RealType value_type;
|
Chris@16
|
721 typedef Policy policy_type;
|
Chris@16
|
722
|
Chris@16
|
723 non_central_t_distribution(RealType v_, RealType lambda) : v(v_), ncp(lambda)
|
Chris@16
|
724 {
|
Chris@16
|
725 const char* function = "boost::math::non_central_t_distribution<%1%>::non_central_t_distribution(%1%,%1%)";
|
Chris@16
|
726 RealType r;
|
Chris@16
|
727 detail::check_df_gt0_to_inf(
|
Chris@16
|
728 function,
|
Chris@16
|
729 v, &r, Policy());
|
Chris@16
|
730 detail::check_finite(
|
Chris@16
|
731 function,
|
Chris@16
|
732 lambda,
|
Chris@16
|
733 &r,
|
Chris@16
|
734 Policy());
|
Chris@16
|
735 } // non_central_t_distribution constructor.
|
Chris@16
|
736
|
Chris@16
|
737 RealType degrees_of_freedom() const
|
Chris@16
|
738 { // Private data getter function.
|
Chris@16
|
739 return v;
|
Chris@16
|
740 }
|
Chris@16
|
741 RealType non_centrality() const
|
Chris@16
|
742 { // Private data getter function.
|
Chris@16
|
743 return ncp;
|
Chris@16
|
744 }
|
Chris@16
|
745 #if 0
|
Chris@16
|
746 //
|
Chris@16
|
747 // This code is disabled, since there can be multiple answers to the
|
Chris@16
|
748 // question, and it's not clear how to find the "right" one.
|
Chris@16
|
749 //
|
Chris@16
|
750 static RealType find_degrees_of_freedom(RealType delta, RealType x, RealType p)
|
Chris@16
|
751 {
|
Chris@16
|
752 const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
|
Chris@16
|
753 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
754 typedef typename policies::normalise<
|
Chris@16
|
755 Policy,
|
Chris@16
|
756 policies::promote_float<false>,
|
Chris@16
|
757 policies::promote_double<false>,
|
Chris@16
|
758 policies::discrete_quantile<>,
|
Chris@16
|
759 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
760 value_type result = detail::find_t_degrees_of_freedom(
|
Chris@16
|
761 static_cast<value_type>(delta),
|
Chris@16
|
762 static_cast<value_type>(x),
|
Chris@16
|
763 static_cast<value_type>(p),
|
Chris@16
|
764 static_cast<value_type>(1-p),
|
Chris@16
|
765 forwarding_policy());
|
Chris@16
|
766 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
767 result,
|
Chris@16
|
768 function);
|
Chris@16
|
769 }
|
Chris@16
|
770 template <class A, class B, class C>
|
Chris@16
|
771 static RealType find_degrees_of_freedom(const complemented3_type<A,B,C>& c)
|
Chris@16
|
772 {
|
Chris@16
|
773 const char* function = "non_central_t<%1%>::find_degrees_of_freedom";
|
Chris@16
|
774 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
775 typedef typename policies::normalise<
|
Chris@16
|
776 Policy,
|
Chris@16
|
777 policies::promote_float<false>,
|
Chris@16
|
778 policies::promote_double<false>,
|
Chris@16
|
779 policies::discrete_quantile<>,
|
Chris@16
|
780 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
781 value_type result = detail::find_t_degrees_of_freedom(
|
Chris@16
|
782 static_cast<value_type>(c.dist),
|
Chris@16
|
783 static_cast<value_type>(c.param1),
|
Chris@16
|
784 static_cast<value_type>(1-c.param2),
|
Chris@16
|
785 static_cast<value_type>(c.param2),
|
Chris@16
|
786 forwarding_policy());
|
Chris@16
|
787 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
788 result,
|
Chris@16
|
789 function);
|
Chris@16
|
790 }
|
Chris@16
|
791 static RealType find_non_centrality(RealType v, RealType x, RealType p)
|
Chris@16
|
792 {
|
Chris@16
|
793 const char* function = "non_central_t<%1%>::find_t_non_centrality";
|
Chris@16
|
794 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
795 typedef typename policies::normalise<
|
Chris@16
|
796 Policy,
|
Chris@16
|
797 policies::promote_float<false>,
|
Chris@16
|
798 policies::promote_double<false>,
|
Chris@16
|
799 policies::discrete_quantile<>,
|
Chris@16
|
800 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
801 value_type result = detail::find_t_non_centrality(
|
Chris@16
|
802 static_cast<value_type>(v),
|
Chris@16
|
803 static_cast<value_type>(x),
|
Chris@16
|
804 static_cast<value_type>(p),
|
Chris@16
|
805 static_cast<value_type>(1-p),
|
Chris@16
|
806 forwarding_policy());
|
Chris@16
|
807 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
808 result,
|
Chris@16
|
809 function);
|
Chris@16
|
810 }
|
Chris@16
|
811 template <class A, class B, class C>
|
Chris@16
|
812 static RealType find_non_centrality(const complemented3_type<A,B,C>& c)
|
Chris@16
|
813 {
|
Chris@16
|
814 const char* function = "non_central_t<%1%>::find_t_non_centrality";
|
Chris@16
|
815 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
816 typedef typename policies::normalise<
|
Chris@16
|
817 Policy,
|
Chris@16
|
818 policies::promote_float<false>,
|
Chris@16
|
819 policies::promote_double<false>,
|
Chris@16
|
820 policies::discrete_quantile<>,
|
Chris@16
|
821 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
822 value_type result = detail::find_t_non_centrality(
|
Chris@16
|
823 static_cast<value_type>(c.dist),
|
Chris@16
|
824 static_cast<value_type>(c.param1),
|
Chris@16
|
825 static_cast<value_type>(1-c.param2),
|
Chris@16
|
826 static_cast<value_type>(c.param2),
|
Chris@16
|
827 forwarding_policy());
|
Chris@16
|
828 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
829 result,
|
Chris@16
|
830 function);
|
Chris@16
|
831 }
|
Chris@16
|
832 #endif
|
Chris@16
|
833 private:
|
Chris@16
|
834 // Data member, initialized by constructor.
|
Chris@16
|
835 RealType v; // degrees of freedom
|
Chris@16
|
836 RealType ncp; // non-centrality parameter
|
Chris@16
|
837 }; // template <class RealType, class Policy> class non_central_t_distribution
|
Chris@16
|
838
|
Chris@16
|
839 typedef non_central_t_distribution<double> non_central_t; // Reserved name of type double.
|
Chris@16
|
840
|
Chris@16
|
841 // Non-member functions to give properties of the distribution.
|
Chris@16
|
842
|
Chris@16
|
843 template <class RealType, class Policy>
|
Chris@16
|
844 inline const std::pair<RealType, RealType> range(const non_central_t_distribution<RealType, Policy>& /* dist */)
|
Chris@16
|
845 { // Range of permissible values for random variable k.
|
Chris@16
|
846 using boost::math::tools::max_value;
|
Chris@16
|
847 return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
|
Chris@16
|
848 }
|
Chris@16
|
849
|
Chris@16
|
850 template <class RealType, class Policy>
|
Chris@16
|
851 inline const std::pair<RealType, RealType> support(const non_central_t_distribution<RealType, Policy>& /* dist */)
|
Chris@16
|
852 { // Range of supported values for random variable k.
|
Chris@16
|
853 // This is range where cdf rises from 0 to 1, and outside it, the pdf is zero.
|
Chris@16
|
854 using boost::math::tools::max_value;
|
Chris@16
|
855 return std::pair<RealType, RealType>(-max_value<RealType>(), max_value<RealType>());
|
Chris@16
|
856 }
|
Chris@16
|
857
|
Chris@16
|
858 template <class RealType, class Policy>
|
Chris@16
|
859 inline RealType mode(const non_central_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
860 { // mode.
|
Chris@16
|
861 static const char* function = "mode(non_central_t_distribution<%1%> const&)";
|
Chris@16
|
862 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
863 RealType l = dist.non_centrality();
|
Chris@16
|
864 RealType r;
|
Chris@16
|
865 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
866 function,
|
Chris@16
|
867 v, &r, Policy())
|
Chris@16
|
868 ||
|
Chris@16
|
869 !detail::check_finite(
|
Chris@16
|
870 function,
|
Chris@16
|
871 l,
|
Chris@16
|
872 &r,
|
Chris@16
|
873 Policy()))
|
Chris@16
|
874 return (RealType)r;
|
Chris@16
|
875
|
Chris@16
|
876 BOOST_MATH_STD_USING
|
Chris@16
|
877
|
Chris@16
|
878 RealType m = v < 3 ? 0 : detail::mean(v, l, Policy());
|
Chris@16
|
879 RealType var = v < 4 ? 1 : detail::variance(v, l, Policy());
|
Chris@16
|
880
|
Chris@16
|
881 return detail::generic_find_mode(
|
Chris@16
|
882 dist,
|
Chris@16
|
883 m,
|
Chris@16
|
884 function,
|
Chris@16
|
885 sqrt(var));
|
Chris@16
|
886 }
|
Chris@16
|
887
|
Chris@16
|
888 template <class RealType, class Policy>
|
Chris@16
|
889 inline RealType mean(const non_central_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
890 {
|
Chris@16
|
891 BOOST_MATH_STD_USING
|
Chris@16
|
892 const char* function = "mean(const non_central_t_distribution<%1%>&)";
|
Chris@16
|
893 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
894 typedef typename policies::normalise<
|
Chris@16
|
895 Policy,
|
Chris@16
|
896 policies::promote_float<false>,
|
Chris@16
|
897 policies::promote_double<false>,
|
Chris@16
|
898 policies::discrete_quantile<>,
|
Chris@16
|
899 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
900 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
901 RealType l = dist.non_centrality();
|
Chris@16
|
902 RealType r;
|
Chris@16
|
903 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
904 function,
|
Chris@16
|
905 v, &r, Policy())
|
Chris@16
|
906 ||
|
Chris@16
|
907 !detail::check_finite(
|
Chris@16
|
908 function,
|
Chris@16
|
909 l,
|
Chris@16
|
910 &r,
|
Chris@16
|
911 Policy()))
|
Chris@16
|
912 return (RealType)r;
|
Chris@16
|
913 if(v <= 1)
|
Chris@16
|
914 return policies::raise_domain_error<RealType>(
|
Chris@16
|
915 function,
|
Chris@16
|
916 "The non-central t distribution has no defined mean for degrees of freedom <= 1: got v=%1%.", v, Policy());
|
Chris@16
|
917 // return l * sqrt(v / 2) * tgamma_delta_ratio((v - 1) * 0.5f, RealType(0.5f));
|
Chris@16
|
918 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
919 detail::mean(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
|
Chris@16
|
920
|
Chris@16
|
921 } // mean
|
Chris@16
|
922
|
Chris@16
|
923 template <class RealType, class Policy>
|
Chris@16
|
924 inline RealType variance(const non_central_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
925 { // variance.
|
Chris@16
|
926 const char* function = "variance(const non_central_t_distribution<%1%>&)";
|
Chris@16
|
927 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
928 typedef typename policies::normalise<
|
Chris@16
|
929 Policy,
|
Chris@16
|
930 policies::promote_float<false>,
|
Chris@16
|
931 policies::promote_double<false>,
|
Chris@16
|
932 policies::discrete_quantile<>,
|
Chris@16
|
933 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
934 BOOST_MATH_STD_USING
|
Chris@16
|
935 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
936 RealType l = dist.non_centrality();
|
Chris@16
|
937 RealType r;
|
Chris@16
|
938 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
939 function,
|
Chris@16
|
940 v, &r, Policy())
|
Chris@16
|
941 ||
|
Chris@16
|
942 !detail::check_finite(
|
Chris@16
|
943 function,
|
Chris@16
|
944 l,
|
Chris@16
|
945 &r,
|
Chris@16
|
946 Policy()))
|
Chris@16
|
947 return (RealType)r;
|
Chris@16
|
948 if(v <= 2)
|
Chris@16
|
949 return policies::raise_domain_error<RealType>(
|
Chris@16
|
950 function,
|
Chris@16
|
951 "The non-central t distribution has no defined variance for degrees of freedom <= 2: got v=%1%.", v, Policy());
|
Chris@16
|
952 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
953 detail::variance(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
|
Chris@16
|
954 }
|
Chris@16
|
955
|
Chris@16
|
956 // RealType standard_deviation(const non_central_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
957 // standard_deviation provided by derived accessors.
|
Chris@16
|
958
|
Chris@16
|
959 template <class RealType, class Policy>
|
Chris@16
|
960 inline RealType skewness(const non_central_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
961 { // skewness = sqrt(l).
|
Chris@16
|
962 const char* function = "skewness(const non_central_t_distribution<%1%>&)";
|
Chris@16
|
963 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
964 typedef typename policies::normalise<
|
Chris@16
|
965 Policy,
|
Chris@16
|
966 policies::promote_float<false>,
|
Chris@16
|
967 policies::promote_double<false>,
|
Chris@16
|
968 policies::discrete_quantile<>,
|
Chris@16
|
969 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
970 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
971 RealType l = dist.non_centrality();
|
Chris@16
|
972 RealType r;
|
Chris@16
|
973 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
974 function,
|
Chris@16
|
975 v, &r, Policy())
|
Chris@16
|
976 ||
|
Chris@16
|
977 !detail::check_finite(
|
Chris@16
|
978 function,
|
Chris@16
|
979 l,
|
Chris@16
|
980 &r,
|
Chris@16
|
981 Policy()))
|
Chris@16
|
982 return (RealType)r;
|
Chris@16
|
983 if(v <= 3)
|
Chris@16
|
984 return policies::raise_domain_error<RealType>(
|
Chris@16
|
985 function,
|
Chris@16
|
986 "The non-central t distribution has no defined skewness for degrees of freedom <= 3: got v=%1%.", v, Policy());;
|
Chris@16
|
987 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
988 detail::skewness(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
|
Chris@16
|
989 }
|
Chris@16
|
990
|
Chris@16
|
991 template <class RealType, class Policy>
|
Chris@16
|
992 inline RealType kurtosis_excess(const non_central_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
993 {
|
Chris@16
|
994 const char* function = "kurtosis_excess(const non_central_t_distribution<%1%>&)";
|
Chris@16
|
995 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
996 typedef typename policies::normalise<
|
Chris@16
|
997 Policy,
|
Chris@16
|
998 policies::promote_float<false>,
|
Chris@16
|
999 policies::promote_double<false>,
|
Chris@16
|
1000 policies::discrete_quantile<>,
|
Chris@16
|
1001 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
1002 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
1003 RealType l = dist.non_centrality();
|
Chris@16
|
1004 RealType r;
|
Chris@16
|
1005 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
1006 function,
|
Chris@16
|
1007 v, &r, Policy())
|
Chris@16
|
1008 ||
|
Chris@16
|
1009 !detail::check_finite(
|
Chris@16
|
1010 function,
|
Chris@16
|
1011 l,
|
Chris@16
|
1012 &r,
|
Chris@16
|
1013 Policy()))
|
Chris@16
|
1014 return (RealType)r;
|
Chris@16
|
1015 if(v <= 4)
|
Chris@16
|
1016 return policies::raise_domain_error<RealType>(
|
Chris@16
|
1017 function,
|
Chris@16
|
1018 "The non-central t distribution has no defined kurtosis for degrees of freedom <= 4: got v=%1%.", v, Policy());;
|
Chris@16
|
1019 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
1020 detail::kurtosis_excess(static_cast<value_type>(v), static_cast<value_type>(l), forwarding_policy()), function);
|
Chris@16
|
1021 } // kurtosis_excess
|
Chris@16
|
1022
|
Chris@16
|
1023 template <class RealType, class Policy>
|
Chris@16
|
1024 inline RealType kurtosis(const non_central_t_distribution<RealType, Policy>& dist)
|
Chris@16
|
1025 {
|
Chris@16
|
1026 return kurtosis_excess(dist) + 3;
|
Chris@16
|
1027 }
|
Chris@16
|
1028
|
Chris@16
|
1029 template <class RealType, class Policy>
|
Chris@16
|
1030 inline RealType pdf(const non_central_t_distribution<RealType, Policy>& dist, const RealType& t)
|
Chris@16
|
1031 { // Probability Density/Mass Function.
|
Chris@16
|
1032 const char* function = "pdf(non_central_t_distribution<%1%>, %1%)";
|
Chris@16
|
1033 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
1034 typedef typename policies::normalise<
|
Chris@16
|
1035 Policy,
|
Chris@16
|
1036 policies::promote_float<false>,
|
Chris@16
|
1037 policies::promote_double<false>,
|
Chris@16
|
1038 policies::discrete_quantile<>,
|
Chris@16
|
1039 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
1040
|
Chris@16
|
1041 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
1042 RealType l = dist.non_centrality();
|
Chris@16
|
1043 RealType r;
|
Chris@16
|
1044 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
1045 function,
|
Chris@16
|
1046 v, &r, Policy())
|
Chris@16
|
1047 ||
|
Chris@16
|
1048 !detail::check_finite(
|
Chris@16
|
1049 function,
|
Chris@16
|
1050 l,
|
Chris@16
|
1051 &r,
|
Chris@16
|
1052 Policy())
|
Chris@16
|
1053 ||
|
Chris@16
|
1054 !detail::check_x(
|
Chris@16
|
1055 function,
|
Chris@16
|
1056 t,
|
Chris@16
|
1057 &r,
|
Chris@16
|
1058 Policy()))
|
Chris@16
|
1059 return (RealType)r;
|
Chris@16
|
1060 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
1061 detail::non_central_t_pdf(static_cast<value_type>(v),
|
Chris@16
|
1062 static_cast<value_type>(l),
|
Chris@16
|
1063 static_cast<value_type>(t),
|
Chris@16
|
1064 Policy()),
|
Chris@16
|
1065 function);
|
Chris@16
|
1066 } // pdf
|
Chris@16
|
1067
|
Chris@16
|
1068 template <class RealType, class Policy>
|
Chris@16
|
1069 RealType cdf(const non_central_t_distribution<RealType, Policy>& dist, const RealType& x)
|
Chris@16
|
1070 {
|
Chris@16
|
1071 const char* function = "boost::math::cdf(non_central_t_distribution<%1%>&, %1%)";
|
Chris@16
|
1072 // was const char* function = "boost::math::non_central_t_distribution<%1%>::cdf(%1%)";
|
Chris@16
|
1073 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
1074 typedef typename policies::normalise<
|
Chris@16
|
1075 Policy,
|
Chris@16
|
1076 policies::promote_float<false>,
|
Chris@16
|
1077 policies::promote_double<false>,
|
Chris@16
|
1078 policies::discrete_quantile<>,
|
Chris@16
|
1079 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
1080
|
Chris@16
|
1081 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
1082 RealType l = dist.non_centrality();
|
Chris@16
|
1083 RealType r;
|
Chris@16
|
1084 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
1085 function,
|
Chris@16
|
1086 v, &r, Policy())
|
Chris@16
|
1087 ||
|
Chris@16
|
1088 !detail::check_finite(
|
Chris@16
|
1089 function,
|
Chris@16
|
1090 l,
|
Chris@16
|
1091 &r,
|
Chris@16
|
1092 Policy())
|
Chris@16
|
1093 ||
|
Chris@16
|
1094 !detail::check_x(
|
Chris@16
|
1095 function,
|
Chris@16
|
1096 x,
|
Chris@16
|
1097 &r,
|
Chris@16
|
1098 Policy()))
|
Chris@16
|
1099 return (RealType)r;
|
Chris@16
|
1100 if ((boost::math::isinf)(v))
|
Chris@16
|
1101 { // Infinite degrees of freedom, so use normal distribution located at delta.
|
Chris@16
|
1102 normal_distribution<RealType, Policy> n(l, 1);
|
Chris@16
|
1103 cdf(n, x);
|
Chris@16
|
1104 //return cdf(normal_distribution<RealType, Policy>(l, 1), x);
|
Chris@16
|
1105 }
|
Chris@16
|
1106
|
Chris@16
|
1107 if(l == 0)
|
Chris@16
|
1108 { // NO non-centrality, so use Student's t instead.
|
Chris@16
|
1109 return cdf(students_t_distribution<RealType, Policy>(v), x);
|
Chris@16
|
1110 }
|
Chris@16
|
1111 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
1112 detail::non_central_t_cdf(
|
Chris@16
|
1113 static_cast<value_type>(v),
|
Chris@16
|
1114 static_cast<value_type>(l),
|
Chris@16
|
1115 static_cast<value_type>(x),
|
Chris@16
|
1116 false, Policy()),
|
Chris@16
|
1117 function);
|
Chris@16
|
1118 } // cdf
|
Chris@16
|
1119
|
Chris@16
|
1120 template <class RealType, class Policy>
|
Chris@16
|
1121 RealType cdf(const complemented2_type<non_central_t_distribution<RealType, Policy>, RealType>& c)
|
Chris@16
|
1122 { // Complemented Cumulative Distribution Function
|
Chris@16
|
1123 // was const char* function = "boost::math::non_central_t_distribution<%1%>::cdf(%1%)";
|
Chris@16
|
1124 const char* function = "boost::math::cdf(const complement(non_central_t_distribution<%1%>&), %1%)";
|
Chris@16
|
1125 typedef typename policies::evaluation<RealType, Policy>::type value_type;
|
Chris@16
|
1126 typedef typename policies::normalise<
|
Chris@16
|
1127 Policy,
|
Chris@16
|
1128 policies::promote_float<false>,
|
Chris@16
|
1129 policies::promote_double<false>,
|
Chris@16
|
1130 policies::discrete_quantile<>,
|
Chris@16
|
1131 policies::assert_undefined<> >::type forwarding_policy;
|
Chris@16
|
1132
|
Chris@16
|
1133 non_central_t_distribution<RealType, Policy> const& dist = c.dist;
|
Chris@16
|
1134 RealType x = c.param;
|
Chris@16
|
1135 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
1136 RealType l = dist.non_centrality(); // aka delta
|
Chris@16
|
1137 RealType r;
|
Chris@16
|
1138 if(!detail::check_df_gt0_to_inf(
|
Chris@16
|
1139 function,
|
Chris@16
|
1140 v, &r, Policy())
|
Chris@16
|
1141 ||
|
Chris@16
|
1142 !detail::check_finite(
|
Chris@16
|
1143 function,
|
Chris@16
|
1144 l,
|
Chris@16
|
1145 &r,
|
Chris@16
|
1146 Policy())
|
Chris@16
|
1147 ||
|
Chris@16
|
1148 !detail::check_x(
|
Chris@16
|
1149 function,
|
Chris@16
|
1150 x,
|
Chris@16
|
1151 &r,
|
Chris@16
|
1152 Policy()))
|
Chris@16
|
1153 return (RealType)r;
|
Chris@16
|
1154
|
Chris@16
|
1155 if ((boost::math::isinf)(v))
|
Chris@16
|
1156 { // Infinite degrees of freedom, so use normal distribution located at delta.
|
Chris@16
|
1157 normal_distribution<RealType, Policy> n(l, 1);
|
Chris@16
|
1158 return cdf(complement(n, x));
|
Chris@16
|
1159 }
|
Chris@16
|
1160 if(l == 0)
|
Chris@16
|
1161 { // zero non-centrality so use Student's t distribution.
|
Chris@16
|
1162 return cdf(complement(students_t_distribution<RealType, Policy>(v), x));
|
Chris@16
|
1163 }
|
Chris@16
|
1164 return policies::checked_narrowing_cast<RealType, forwarding_policy>(
|
Chris@16
|
1165 detail::non_central_t_cdf(
|
Chris@16
|
1166 static_cast<value_type>(v),
|
Chris@16
|
1167 static_cast<value_type>(l),
|
Chris@16
|
1168 static_cast<value_type>(x),
|
Chris@16
|
1169 true, Policy()),
|
Chris@16
|
1170 function);
|
Chris@16
|
1171 } // ccdf
|
Chris@16
|
1172
|
Chris@16
|
1173 template <class RealType, class Policy>
|
Chris@16
|
1174 inline RealType quantile(const non_central_t_distribution<RealType, Policy>& dist, const RealType& p)
|
Chris@16
|
1175 { // Quantile (or Percent Point) function.
|
Chris@16
|
1176 static const char* function = "quantile(const non_central_t_distribution<%1%>, %1%)";
|
Chris@16
|
1177 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
1178 RealType l = dist.non_centrality();
|
Chris@16
|
1179 return detail::non_central_t_quantile(function, v, l, p, RealType(1-p), Policy());
|
Chris@16
|
1180 } // quantile
|
Chris@16
|
1181
|
Chris@16
|
1182 template <class RealType, class Policy>
|
Chris@16
|
1183 inline RealType quantile(const complemented2_type<non_central_t_distribution<RealType, Policy>, RealType>& c)
|
Chris@16
|
1184 { // Quantile (or Percent Point) function.
|
Chris@16
|
1185 static const char* function = "quantile(const complement(non_central_t_distribution<%1%>, %1%))";
|
Chris@16
|
1186 non_central_t_distribution<RealType, Policy> const& dist = c.dist;
|
Chris@16
|
1187 RealType q = c.param;
|
Chris@16
|
1188 RealType v = dist.degrees_of_freedom();
|
Chris@16
|
1189 RealType l = dist.non_centrality();
|
Chris@16
|
1190 return detail::non_central_t_quantile(function, v, l, RealType(1-q), q, Policy());
|
Chris@16
|
1191 } // quantile complement.
|
Chris@16
|
1192
|
Chris@16
|
1193 } // namespace math
|
Chris@16
|
1194 } // namespace boost
|
Chris@16
|
1195
|
Chris@16
|
1196 // This include must be at the end, *after* the accessors
|
Chris@16
|
1197 // for this distribution have been defined, in order to
|
Chris@16
|
1198 // keep compilers that support two-phase lookup happy.
|
Chris@16
|
1199 #include <boost/math/distributions/detail/derived_accessors.hpp>
|
Chris@16
|
1200
|
Chris@16
|
1201 #endif // BOOST_MATH_SPECIAL_NON_CENTRAL_T_HPP
|
Chris@16
|
1202
|