Blame cdf/tdist.c

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
}