# include # include # include # include "asa239.h" /******************************************************************************/ double alnorm ( double x, int upper ) /******************************************************************************/ /* Purpose: alnorm() computes the cumulative density of the standard normal distribution. Licensing: This code is distributed under the MIT license. Modified: 13 November 2010 Author: Original FORTRAN77 version by David Hill. C version by John Burkardt. Reference: David Hill, Algorithm AS 66: The Normal Integral, Applied Statistics, Volume 22, Number 3, 1973, pages 424-427. Parameters: Input, double X, is one endpoint of the semi-infinite interval over which the integration takes place. Input, int UPPER, determines whether the upper or lower interval is to be integrated: 1 => integrate from X to + Infinity; 0 => integrate from - Infinity to X. Output, double ALNORM, the integral of the standard normal distribution over the desired interval. */ { double a1 = 5.75885480458; double a2 = 2.62433121679; double a3 = 5.92885724438; double b1 = -29.8213557807; double b2 = 48.6959930692; double c1 = -0.000000038052; double c2 = 0.000398064794; double c3 = -0.151679116635; double c4 = 4.8385912808; double c5 = 0.742380924027; double c6 = 3.99019417011; double con = 1.28; double d1 = 1.00000615302; double d2 = 1.98615381364; double d3 = 5.29330324926; double d4 = -15.1508972451; double d5 = 30.789933034; double ltone = 7.0; double p = 0.398942280444; double q = 0.39990348504; double r = 0.398942280385; int up; double utzero = 18.66; double value; double y; double z; up = upper; z = x; if ( z < 0.0 ) { up = !up; z = - z; } if ( ltone < z && ( ( !up ) || utzero < z ) ) { if ( up ) { value = 0.0; } else { value = 1.0; } return value; } y = 0.5 * z * z; if ( z <= con ) { value = 0.5 - z * ( p - q * y / ( y + a1 + b1 / ( y + a2 + b2 / ( y + a3 )))); } else { value = r * exp ( - y ) / ( z + c1 + d1 / ( z + c2 + d2 / ( z + c3 + d3 / ( z + c4 + d4 / ( z + c5 + d5 / ( z + c6 )))))); } if ( !up ) { value = 1.0 - value; } return value; } /******************************************************************************/ void gamma_inc_values ( int *n_data, double *a, double *x, double *fx ) /******************************************************************************/ /* Purpose: gamma_inc_values() returns some values of the incomplete Gamma function. Discussion: The (normalized) incomplete Gamma function P(A,X) is defined as: PN(A,X) = 1/Gamma(A) * Integral ( 0 <= T <= X ) T**(A-1) * exp(-T) dT. With this definition, for all A and X, 0 <= PN(A,X) <= 1 and PN(A,INFINITY) = 1.0 In Mathematica, the function can be evaluated by: 1 - GammaRegularized[A,X] Licensing: This code is distributed under the MIT license. Modified: 20 November 2004 Author: John Burkardt Reference: Milton Abramowitz, Irene Stegun, Handbook of Mathematical Functions, National Bureau of Standards, 1964, ISBN: 0-486-61272-4, LC: QA47.A34. Stephen Wolfram, The Mathematica Book, Fourth Edition, Cambridge University Press, 1999, ISBN: 0-521-64314-7, LC: QA76.95.W65. Parameters: Input/output, int *N_DATA. The user sets N_DATA to 0 before the first call. On each call, the routine increments N_DATA by 1, and returns the corresponding data; when there is no more data, the output value of N_DATA will be 0 again. Output, double *A, the parameter of the function. Output, double *X, the argument of the function. Output, double *FX, the value of the function. */ { # define N_MAX 20 double a_vec[N_MAX] = { 0.10E+00, 0.10E+00, 0.10E+00, 0.50E+00, 0.50E+00, 0.50E+00, 0.10E+01, 0.10E+01, 0.10E+01, 0.11E+01, 0.11E+01, 0.11E+01, 0.20E+01, 0.20E+01, 0.20E+01, 0.60E+01, 0.60E+01, 0.11E+02, 0.26E+02, 0.41E+02 }; double fx_vec[N_MAX] = { 0.7382350532339351E+00, 0.9083579897300343E+00, 0.9886559833621947E+00, 0.3014646416966613E+00, 0.7793286380801532E+00, 0.9918490284064973E+00, 0.9516258196404043E-01, 0.6321205588285577E+00, 0.9932620530009145E+00, 0.7205974576054322E-01, 0.5891809618706485E+00, 0.9915368159845525E+00, 0.1018582711118352E-01, 0.4421745996289254E+00, 0.9927049442755639E+00, 0.4202103819530612E-01, 0.9796589705830716E+00, 0.9226039842296429E+00, 0.4470785799755852E+00, 0.7444549220718699E+00 }; double x_vec[N_MAX] = { 0.30E-01, 0.30E+00, 0.15E+01, 0.75E-01, 0.75E+00, 0.35E+01, 0.10E+00, 0.10E+01, 0.50E+01, 0.10E+00, 0.10E+01, 0.50E+01, 0.15E+00, 0.15E+01, 0.70E+01, 0.25E+01, 0.12E+02, 0.16E+02, 0.25E+02, 0.45E+02 }; if ( *n_data < 0 ) { *n_data = 0; } *n_data = *n_data + 1; if ( N_MAX < *n_data ) { *n_data = 0; *a = 0.0; *x = 0.0; *fx = 0.0; } else { *a = a_vec[*n_data-1]; *x = x_vec[*n_data-1]; *fx = fx_vec[*n_data-1]; } return; # undef N_MAX } /******************************************************************************/ double gammad ( double x, double p, int *ifault ) /******************************************************************************/ /* Purpose: gammad() computes the Incomplete Gamma Integral Licensing: This code is distributed under the MIT license. Modified: 13 November 2010 Author: Original FORTRAN77 version by B Shea. C version by John Burkardt. Reference: B Shea, Algorithm AS 239: Chi-squared and Incomplete Gamma Integral, Applied Statistics, Volume 37, Number 3, 1988, pages 466-473. Parameters: Input, double X, P, the parameters of the incomplete gamma ratio. 0 <= X, and 0 < P. Output, int IFAULT, error flag. 0, no error. 1, X < 0 or P <= 0. Output, double GAMMAD, the value of the incomplete Gamma integral. */ { double a; double an; double arg; double b; double c; double elimit = - 88.0; double oflo = 1.0E+37; double plimit = 1000.0; double pn1; double pn2; double pn3; double pn4; double pn5; double pn6; double rn; double tol = 1.0E-14; int upper; double value; double xbig = 1.0E+08; value = 0.0; /* Check the input. */ if ( x < 0.0 ) { *ifault = 1; return value; } if ( p <= 0.0 ) { *ifault = 1; return value; } *ifault = 0; if ( x == 0.0 ) { value = 0.0; return value; } /* If P is large, use a normal approximation. */ if ( plimit < p ) { pn1 = 3.0 * sqrt ( p ) * ( pow ( x / p, 1.0 / 3.0 ) + 1.0 / ( 9.0 * p ) - 1.0 ); upper = 0; value = alnorm ( pn1, upper ); return value; } /* If X is large set value = 1. */ if ( xbig < x ) { value = 1.0; return value; } /* Use Pearson's series expansion. */ if ( x <= 1.0 || x < p ) { arg = p * log ( x ) - x - lgamma ( p + 1.0 ); c = 1.0; value = 1.0; a = p; for ( ; ; ) { a = a + 1.0; c = c * x / a; value = value + c; if ( c <= tol ) { break; } } arg = arg + log ( value ); if ( elimit <= arg ) { value = exp ( arg ); } else { value = 0.0; } } /* Use a continued fraction expansion. */ else { arg = p * log ( x ) - x - lgamma ( p ); a = 1.0 - p; b = a + x + 1.0; c = 0.0; pn1 = 1.0; pn2 = x; pn3 = x + 1.0; pn4 = x * b; value = pn3 / pn4; for ( ; ; ) { a = a + 1.0; b = b + 2.0; c = c + 1.0; an = a * c; pn5 = b * pn3 - an * pn1; pn6 = b * pn4 - an * pn2; if ( pn6 != 0.0 ) { rn = pn5 / pn6; if ( fabs ( value - rn ) <= r8_min ( tol, tol * rn ) ) { break; } value = rn; } pn1 = pn3; pn2 = pn4; pn3 = pn5; pn4 = pn6; /* Re-scale terms in continued fraction if terms are large. */ if ( oflo <= abs ( pn5 ) ) { pn1 = pn1 / oflo; pn2 = pn2 / oflo; pn3 = pn3 / oflo; pn4 = pn4 / oflo; } } arg = arg + log ( value ); if ( elimit <= arg ) { value = 1.0 - exp ( arg ); } else { value = 1.0; } } return value; } /******************************************************************************/ double r8_min ( double x, double y ) /******************************************************************************/ /* Purpose: r8_min() returns the minimum of two R8's. Licensing: This code is distributed under the MIT license. Modified: 31 August 2004 Author: John Burkardt Parameters: Input, double X, Y, the quantities to compare. Output, double R8_MIN, the minimum of X and Y. */ { double value; if ( y < x ) { value = y; } else { value = x; } return value; }