|
Packit |
67cb25 |
/* cdf/tdist.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2002 Jason H. Stover.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
67cb25 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
67cb25 |
* the Free Software Foundation; either version 3 of the License, or (at
|
|
Packit |
67cb25 |
* your option) any later version.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
67cb25 |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
67cb25 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
67cb25 |
* General Public License for more details.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
67cb25 |
* along with this program; if not, write to the Free Software Foundation,
|
|
Packit |
67cb25 |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Computes the Student's t cumulative distribution function using
|
|
Packit |
67cb25 |
* the method detailed in
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* W.J. Kennedy and J.E. Gentle, "Statistical Computing." 1980.
|
|
Packit |
67cb25 |
* Marcel Dekker. ISBN 0-8247-6898-1.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* G.W. Hill and A.W. Davis. "Generalized asymptotic expansions
|
|
Packit |
67cb25 |
* of Cornish-Fisher type." Annals of Mathematical Statistics,
|
|
Packit |
67cb25 |
* vol. 39, 1264-1273. 1968.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* G.W. Hill. "Algorithm 395: Student's t-distribution," Communications
|
|
Packit |
67cb25 |
* of the ACM, volume 13, number 10, page 617. October 1970.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* G.W. Hill, "Remark on algorithm 395: Student's t-distribution,"
|
|
Packit |
67cb25 |
* Transactions on Mathematical Software, volume 7, number 2, page
|
|
Packit |
67cb25 |
* 247. June 1982.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include <config.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_cdf.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_sf_gamma.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_math.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_errno.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#include "beta_inc.c"
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
poly_eval (const double c[], unsigned int n, double x)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
unsigned int i;
|
|
Packit |
67cb25 |
double y = c[0] * x;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 1; i < n; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
y = x * (y + c[i]);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
y += c[n];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Use the Cornish-Fisher asymptotic expansion to find a point u such
|
|
Packit |
67cb25 |
* that gsl_cdf_gauss(y) = tcdf(t).
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
cornish_fisher (double t, double n)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const double coeffs6[10] = {
|
|
Packit |
67cb25 |
0.265974025974025974026,
|
|
Packit |
67cb25 |
5.449696969696969696970,
|
|
Packit |
67cb25 |
122.20294372294372294372,
|
|
Packit |
67cb25 |
2354.7298701298701298701,
|
|
Packit |
67cb25 |
37625.00902597402597403,
|
|
Packit |
67cb25 |
486996.1392857142857143,
|
|
Packit |
67cb25 |
4960870.65,
|
|
Packit |
67cb25 |
37978595.55,
|
|
Packit |
67cb25 |
201505390.875,
|
|
Packit |
67cb25 |
622437908.625
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
const double coeffs5[8] = {
|
|
Packit |
67cb25 |
0.2742857142857142857142,
|
|
Packit |
67cb25 |
4.499047619047619047619,
|
|
Packit |
67cb25 |
78.45142857142857142857,
|
|
Packit |
67cb25 |
1118.710714285714285714,
|
|
Packit |
67cb25 |
12387.6,
|
|
Packit |
67cb25 |
101024.55,
|
|
Packit |
67cb25 |
559494.0,
|
|
Packit |
67cb25 |
1764959.625
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
const double coeffs4[6] = {
|
|
Packit |
67cb25 |
0.3047619047619047619048,
|
|
Packit |
67cb25 |
3.752380952380952380952,
|
|
Packit |
67cb25 |
46.67142857142857142857,
|
|
Packit |
67cb25 |
427.5,
|
|
Packit |
67cb25 |
2587.5,
|
|
Packit |
67cb25 |
8518.5
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
const double coeffs3[4] = {
|
|
Packit |
67cb25 |
0.4,
|
|
Packit |
67cb25 |
3.3,
|
|
Packit |
67cb25 |
24.0,
|
|
Packit |
67cb25 |
85.5
|
|
Packit |
67cb25 |
};
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double a = n - 0.5;
|
|
Packit |
67cb25 |
double b = 48.0 * a * a;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double z2 = a * log1p (t * t / n);
|
|
Packit |
67cb25 |
double z = sqrt (z2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double p5 = z * poly_eval (coeffs6, 9, z2);
|
|
Packit |
67cb25 |
double p4 = -z * poly_eval (coeffs5, 7, z2);
|
|
Packit |
67cb25 |
double p3 = z * poly_eval (coeffs4, 5, z2);
|
|
Packit |
67cb25 |
double p2 = -z * poly_eval (coeffs3, 3, z2);
|
|
Packit |
67cb25 |
double p1 = z * (z2 + 3.0);
|
|
Packit |
67cb25 |
double p0 = z;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double y = p5;
|
|
Packit |
67cb25 |
y = (y / b) + p4;
|
|
Packit |
67cb25 |
y = (y / b) + p3;
|
|
Packit |
67cb25 |
y = (y / b) + p2;
|
|
Packit |
67cb25 |
y = (y / b) + p1;
|
|
Packit |
67cb25 |
y = (y / b) + p0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (t < 0)
|
|
Packit |
67cb25 |
y *= -1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return y;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#if 0
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Series approximation for t > 4.0. This needs to be fixed;
|
|
Packit |
67cb25 |
* it shouldn't subtract the result from 1.0. A better way is
|
|
Packit |
67cb25 |
* to use two different series expansions. Figuring this out
|
|
Packit |
67cb25 |
* means rummaging through Fisher's paper in Metron, v5, 1926,
|
|
Packit |
67cb25 |
* "Expansion of Student's integral in powers of n^{-1}."
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
#define MAXI 40
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static double
|
|
Packit |
67cb25 |
normal_approx (const double x, const double nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double y;
|
|
Packit |
67cb25 |
double num;
|
|
Packit |
67cb25 |
double diff;
|
|
Packit |
67cb25 |
double q;
|
|
Packit |
67cb25 |
int i;
|
|
Packit |
67cb25 |
double lg1, lg2;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
y = 1 / sqrt (1 + x * x / nu);
|
|
Packit |
67cb25 |
num = 1.0;
|
|
Packit |
67cb25 |
q = 0.0;
|
|
Packit |
67cb25 |
diff = 2 * GSL_DBL_EPSILON;
|
|
Packit |
67cb25 |
for (i = 2; (i < MAXI) && (diff > GSL_DBL_EPSILON); i += 2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
diff = q;
|
|
Packit |
67cb25 |
num *= y * y * (i - 1) / i;
|
|
Packit |
67cb25 |
q += num / (nu + i);
|
|
Packit |
67cb25 |
diff = q - diff;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
q += 1 / nu;
|
|
Packit |
67cb25 |
lg1 = gsl_sf_lngamma (nu / 2.0);
|
|
Packit |
67cb25 |
lg2 = gsl_sf_lngamma ((nu + 1.0) / 2.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
diff = lg2 - lg1;
|
|
Packit |
67cb25 |
q *= pow (y, nu) * exp (diff) / sqrt (M_PI);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return q;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
#endif
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double
|
|
Packit |
67cb25 |
gsl_cdf_tdist_P (const double x, const double nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double P;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double x2 = x * x;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (nu > 30 && x2 < 10 * nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double u = cornish_fisher (x, nu);
|
|
Packit |
67cb25 |
P = gsl_cdf_ugaussian_P (u);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return P;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x2 < nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double u = x2 / nu;
|
|
Packit |
67cb25 |
double eps = u / (1 + u);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x >= 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
P = beta_inc_AXPY (0.5, 0.5, 0.5, nu / 2.0, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
P = beta_inc_AXPY (-0.5, 0.5, 0.5, nu / 2.0, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double v = nu / (x * x);
|
|
Packit |
67cb25 |
double eps = v / (1 + v);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x >= 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
P = beta_inc_AXPY (-0.5, 1.0, nu / 2.0, 0.5, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
P = beta_inc_AXPY (0.5, 0.0, nu / 2.0, 0.5, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return P;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double
|
|
Packit |
67cb25 |
gsl_cdf_tdist_Q (const double x, const double nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double Q;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
double x2 = x * x;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (nu > 30 && x2 < 10 * nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double u = cornish_fisher (x, nu);
|
|
Packit |
67cb25 |
Q = gsl_cdf_ugaussian_Q (u);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return Q;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x2 < nu)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double u = x2 / nu;
|
|
Packit |
67cb25 |
double eps = u / (1 + u);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x >= 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
Q = beta_inc_AXPY (-0.5, 0.5, 0.5, nu / 2.0, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
Q = beta_inc_AXPY (0.5, 0.5, 0.5, nu / 2.0, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double v = nu / (x * x);
|
|
Packit |
67cb25 |
double eps = v / (1 + v);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (x >= 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
Q = beta_inc_AXPY (0.5, 0.0, nu / 2.0, 0.5, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
Q = beta_inc_AXPY (-0.5, 1.0, nu / 2.0, 0.5, eps);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return Q;
|
|
Packit |
67cb25 |
}
|