3 * Copyright (C) 2002 Jason H. Stover.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
21 * Computes the Student's t cumulative distribution function using
22 * the method detailed in
24 * W.J. Kennedy and J.E. Gentle, "Statistical Computing." 1980.
25 * Marcel Dekker. ISBN 0-8247-6898-1.
27 * G.W. Hill and A.W. Davis. "Generalized asymptotic expansions
28 * of Cornish-Fisher type." Annals of Mathematical Statistics,
29 * vol. 39, 1264-1273. 1968.
31 * G.W. Hill. "Algorithm 395: Student's t-distribution," Communications
32 * of the ACM, volume 13, number 10, page 617. October 1970.
34 * G.W. Hill, "Remark on algorithm 395: Student's t-distribution,"
35 * Transactions on Mathematical Software, volume 7, number 2, page
40 #include <gsl/gsl_cdf.h>
41 #include <gsl/gsl_sf_gamma.h>
42 #include <gsl/gsl_math.h>
43 #include <gsl/gsl_errno.h>
48 poly_eval (const double c[], unsigned int n, double x)
53 for (i = 1; i < n; i++)
64 * Use the Cornish-Fisher asymptotic expansion to find a point u such
65 * that gsl_cdf_gauss(y) = tcdf(t).
70 cornish_fisher (double t, double n)
72 const double coeffs6[10] = {
73 0.265974025974025974026,
74 5.449696969696969696970,
75 122.20294372294372294372,
76 2354.7298701298701298701,
77 37625.00902597402597403,
78 486996.1392857142857143,
84 const double coeffs5[8] = {
85 0.2742857142857142857142,
86 4.499047619047619047619,
87 78.45142857142857142857,
88 1118.710714285714285714,
94 const double coeffs4[6] = {
95 0.3047619047619047619048,
96 3.752380952380952380952,
97 46.67142857142857142857,
102 const double coeffs3[4] = {
110 double b = 48.0 * a * a;
112 double z2 = a * log1p (t * t / n);
113 double z = sqrt (z2);
115 double p5 = z * poly_eval (coeffs6, 9, z2);
116 double p4 = -z * poly_eval (coeffs5, 7, z2);
117 double p3 = z * poly_eval (coeffs4, 5, z2);
118 double p2 = -z * poly_eval (coeffs3, 3, z2);
119 double p1 = z * (z2 + 3.0);
137 * Series approximation for t > 4.0. This needs to be fixed;
138 * it shouldn't subtract the result from 1.0. A better way is
139 * to use two different series expansions. Figuring this out
140 * means rummaging through Fisher's paper in Metron, v5, 1926,
141 * "Expansion of Student's integral in powers of n^{-1}."
147 normal_approx (const double x, const double nu)
156 y = 1 / sqrt (1 + x * x / nu);
159 diff = 2 * GSL_DBL_EPSILON;
160 for (i = 2; (i < MAXI) && (diff > GSL_DBL_EPSILON); i += 2)
163 num *= y * y * (i - 1) / i;
168 lg1 = gsl_sf_lngamma (nu / 2.0);
169 lg2 = gsl_sf_lngamma ((nu + 1.0) / 2.0);
172 q *= pow (y, nu) * exp (diff) / sqrt (M_PI);
179 gsl_cdf_tdist_P (const double x, const double nu)
185 if (nu > 30 && x2 < 10 * nu)
187 double u = cornish_fisher (x, nu);
188 P = gsl_cdf_ugaussian_P (u);
196 double eps = u / (1 + u);
200 P = beta_inc_AXPY (0.5, 0.5, 0.5, nu / 2.0, eps);
204 P = beta_inc_AXPY (-0.5, 0.5, 0.5, nu / 2.0, eps);
209 double v = nu / (x * x);
210 double eps = v / (1 + v);
214 P = beta_inc_AXPY (-0.5, 1.0, nu / 2.0, 0.5, eps);
218 P = beta_inc_AXPY (0.5, 0.0, nu / 2.0, 0.5, eps);
227 gsl_cdf_tdist_Q (const double x, const double nu)
233 if (nu > 30 && x2 < 10 * nu)
235 double u = cornish_fisher (x, nu);
236 Q = gsl_cdf_ugaussian_Q (u);
244 double eps = u / (1 + u);
248 Q = beta_inc_AXPY (-0.5, 0.5, 0.5, nu / 2.0, eps);
252 Q = beta_inc_AXPY (0.5, 0.5, 0.5, nu / 2.0, eps);
257 double v = nu / (x * x);
258 double eps = v / (1 + v);
262 Q = beta_inc_AXPY (0.5, 0.0, nu / 2.0, 0.5, eps);
266 Q = beta_inc_AXPY (-0.5, 1.0, nu / 2.0, 0.5, eps);