The R Project SVN R

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

/*
 *  R : A Computer Langage for Statistical Data Analysis
 *  Copyright (C) 1995, 1996  Robert Gentleman and Ross Ihaka
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Reference:
 *  Algorithm 396: Student's t-quantiles by G.W. Hill
 *  Comm. A.C.M., vol.13(10), 619-620, October 1970
 */

#include "Mathlib.h"

static double eps = 1.e-12;

double qt(double p, double ndf)
{
    double a, b, c, d, prob, P, q, x, y;
    int neg;

    if (ndf < 1 || p >= 1 || p <= 0)
        DOMAIN_ERROR;

    if (ndf > 1e20) return qnorm(p, 0.0, 1.0);

    if(p > 0.5) {
        neg = 0; P = 2 * (1 - p);
    } else {
        neg = 1; P = 2 * p;
    }

    if (fabs(ndf - 2) < eps) { /* df ~= 2 */
        q = sqrt(2 / (P * (2 - P)) - 2);
    } else if (ndf < 1 + eps) { /* df ~= 1 */
        prob = P * M_PI_half;
        q = cos(prob) / sin(prob);
    } else { /*-- normal case;  including, e.g.,  df = 1.1 */
        a = 1 / (ndf - 0.5);
        b = 48 / (a * a);
        c = ((20700 * a / b - 98) * a - 16) * a + 96.36;
        d = ((94.5 / (b + c) - 3) / b + 1) * sqrt(a * M_PI_half) * ndf;
        y = pow(d * P, 2 / ndf);

        if (y > 0.05 + a) {
            /* Asymptotic inverse expansion about normal */

            x = qnorm(0.5 * P, 0.0, 1.0);
            y = x * x;
            if (ndf < 5)
                c = c + 0.3 * (ndf - 4.5) * (x + 0.6);
            c = (((0.05 * d * x - 5) * x - 7) * x - 2) * x + b + c;
            y = (((((0.4 * y + 6.3) * y + 36) * y + 94.5) / c - y - 3) / b + 1) * x;
            y = a * y * y;
            if (y > 0.002)
                y = exp(y) - 1;
            else /* Taylor of  e^y -1 : */
                y = 0.5 * y * y + y;
        } else {
            y = ((1 / (((ndf + 6) / (ndf * y) - 0.089 * d - 0.822)
                   * (ndf + 2) * 3) + 0.5 / (ndf + 4))
                 * y - 1) * (ndf + 1) / (ndf + 2) + 1 / y;
        }
        q = sqrt(ndf * y);
    }
    if(neg) q = -q;
    return q;
}