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