/***************************************************************************** Major portions of this software are copyrighted by the Medical College of Wisconsin, 1994-2000, and are released under the Gnu General Public License, Version 2. See the file README.Copyright for details. ******************************************************************************/ #include "mrilib.h" #undef USE_OLD_METHOD #ifdef USE_OLD_METHOD double stas4( double , double ) ; double stinv( double , double ) ; #else double lnbeta( double , double ) ; double incbeta( double,double,double,double ) ; double incbeta_inverse( double,double,double,double ) ; #endif double qginv( double ) ; /* prototype */ int main( int argc , char * argv[] ) { double pp , dof , tt , bb , binv ; double nn,ll,mm ; int quiet = 0 ; if( argc < 2 || strncmp(argv[1],"-help",5) == 0 ){ printf("\n*** NOTE: This program has been superseded by program 'cdf' ***\n\n") ; printf("Usage #1: p2t p dof\n" " where p = double sided tail probability for t-distribution\n" " dof = number of degrees of freedom to use\n" " OUTPUT = t value that matches the input p\n" "\n" "Usage #2: p2t p N L M\n" " where p = double sided tail probability of beta distribution\n" " N = number of measured data points\n" " L = number of nuisance parameters (orts)\n" " M = number of fit parameters\n" " OUTPUT = threshold for correlation coefficient\n" "\n" "Usage #3: p2t p\n" " where p = one sided tail probability of Gaussian distribution\n" " OUTPUT = z value for which P(x>z) = p\n" "\n" "Usage #4: p2t p dof N\n" " where p = double sided tail probability for distribution of\n" " the mean of N iid zero-mean t-variables\n" " dof = number of degrees of freedom of each t-variable\n" " N = number of t variables averaged\n" " OUTPUT = threshold for the t average statistic\n" " N.B.: The method used for this calculation is the Cornish-\n" " Fisher expansion in N, and is only an approximation.\n" " This also requires dof > 6, and the results will be\n" " less accurate as dof approaches 6 from above!\n" ) ; exit(0) ; } if( strcmp(argv[1],"-q") == 0 ){ argv++ ; argc-- ; quiet = 1 ; if( argc < 2 ) exit(0) ; } /** Gaussian statistic **/ if( argc == 2 ){ pp = strtod( argv[1] , NULL ) ; if( !quiet && (pp < 1.e-20 || pp >= 0.9999999) ){ fprintf(stderr,"command line p value is illegal!\a\n") ; exit(-1) ; } tt = qginv(pp) ; if( quiet ) printf("%g\n",tt) ; else printf("p = %g z = %g\n",pp,tt) ; } /** t statistic **/ else if( argc == 3 ){ pp = strtod( argv[1] , NULL ) ; dof = strtod( argv[2] , NULL ) ; if( !quiet && (pp <= 1.e-10 || pp >= 0.9999999) ){ fprintf(stderr,"command line p value is illegal!\a\n") ; exit(-1) ; } if( dof <= 1.0 ){ fprintf(stderr,"command line dof value is illegal!\a\n") ; exit(-1) ; } #ifdef USE_OLD_METHOD tt = stinv( pp , dof ) ; #else bb = lnbeta( 0.5*dof , 0.5 ) ; binv = incbeta_inverse( pp, 0.5*dof , 0.5 , bb ) ; tt = sqrt( dof*(1.0/binv-1.0) ) ; #endif if( quiet ) printf("%g\n",tt) ; else printf("p = %g dof = %g t = %g\n",pp,dof,tt) ; /** beta statistic **/ } else if( argc == 5 ){ pp = strtod( argv[1] , NULL ) ; nn = strtod( argv[2] , NULL ) ; ll = strtod( argv[3] , NULL ) ; mm = strtod( argv[4] , NULL ) ; if( !quiet && (pp <= 1.e-20 || pp >= 0.9999999) ){ fprintf(stderr,"command line p value is illegal!\a\n") ; exit(-1) ; } if( mm < 1.0 || ll < 0.0 || nn-ll-mm < 1.0 ){ fprintf(stderr,"command line N,L,M values are illegal!\a\n");exit(1) ; } bb = lnbeta( 0.5*mm , 0.5*(nn-ll-mm) ) ; binv = incbeta_inverse( pp, 0.5*(nn-ll-mm) , 0.5*mm , bb ) ; tt = sqrt(1.0-binv) ; if( quiet ) printf("%g\n",tt) ; else printf("p = %g N = %g L = %g M = %g rho = %g\n", pp,nn,ll,mm,tt) ; /** averaged t statistic **/ } else if( argc == 4 ){ double ww , xx , gam2,gam4 ; pp = strtod( argv[1] , NULL ) ; dof = strtod( argv[2] , NULL ) ; nn = strtod( argv[3] , NULL ) ; if( !quiet && (pp <= 1.e-10 || pp >= 0.9999999) ){ fprintf(stderr,"command line p value is illegal!\a\n") ; exit(-1) ; } if( dof <= 6.01 || nn < 1.0 ){ fprintf(stderr,"command line dof or N value is illegal!\a\n");exit(-1); } /* 4th and 6th order moments */ gam2 = 6.0 / ( (dof-4.0) * nn ) ; gam4 = 240.0 / ( (dof-6.0) * (dof-4.0) * nn * nn ) ; /* Cornish-Fisher expansion */ xx = qginv( 0.5 * pp ) ; /* Gaussian approx */ ww = xx + gam2 * xx * ( xx*xx - 3.0) / 24.0 + gam4 * xx * ( xx*xx*xx*xx - 10.0*xx*xx + 15.0) / 720.0 - gam2 * gam2 * xx * (3.0*xx*xx*xx*xx - 24.0*xx*xx + 29.0) / 384.0 ; tt = sqrt( dof/(dof-2.0)/nn ) * ww ; if( quiet ) printf("%g\n",tt) ; else{ printf("p = %g dof = %g N = %g 4-term t = %g",pp,dof,nn,tt) ; ww = xx + gam2 * xx * ( xx*xx - 3.0) / 24.0 ; tt = sqrt( dof/(dof-2.0)/nn ) * ww ; printf(" [2-term=%g",tt) ; ww = xx ; tt = sqrt( dof/(dof-2.0)/nn ) * ww ; printf(" 1-term=%g]\n",tt) ; } } exit(0) ; } #ifdef USE_OLD_METHOD /*---------------------------------------------------------------------- code for inverse of central t distribution Inputs: p = double sided tail probability nu = degrees of freedom Output: T such that P( |t| > T ) = p This version is only good for nu >= 5, since it uses the approximations in Abramowitz and Stegun, Eq. 26.7.5 (p. 949). ------------------------------------------------------------------------*/ double stinv( double p , double nu ) { double xg , t4 ; xg = qginv(0.5*p) ; t4 = stas4( xg , nu ) ; return t4 ; } double stas4( double x , double nu) /* this code generated by Maple */ { double t1,t2,t8,t9,t14,t17,t26,t34,t37 ; t1 = x*x; t2 = t1*x; t8 = t1*t1; t9 = t8*x; t14 = nu*nu; t17 = t8*t2; t26 = t8*t8; t34 = t14*t14; t37 = x+(t2/4+x/4)/nu +(5.0/96.0*t9+t2/6+x/32)/t14 +(t17/128+19.0/384.0*t9 +17.0/384.0*t2-5.0/128.0*x)/t14/nu +(79.0/92160.0*t26*x+97.0/11520.0*t17+247.0/15360.0*t9 -t2/48-21.0/2048.0*x)/t34; return t37 ; } #endif /* USE_OLD_METHOD */ #ifndef USE_OLD_METHOD /*--------------------------------------------------------------- compute log of complete beta function, using the Unix math library's log gamma function. If this is not available, tough luck. -----------------------------------------------------------------*/ double lnbeta( double p , double q ) { return (lgamma(p) + lgamma(q) - lgamma(p+q)) ; } /*--------------------------------------------------------------- TRANSLATED FROM THE ORIGINAL FORTRAN: algorithm as 63 appl. statist. (1973), vol.22, no.3 computes incomplete beta function ratio for arguments x between zero and one, p and q positive. log of complete beta function, beta, is assumed to be known -----------------------------------------------------------------*/ #define ZERO 0.0 #define ONE 1.0 #define ACU 1.0e-15 double incbeta( double x , double p , double q , double beta ) { double betain , psq , cx , xx,pp,qq , term,ai , temp , rx ; int indx , ns ; if( p <= ZERO || q <= ZERO || x < ZERO || x > ONE ) return -1.0 ; if( x == ZERO ) return ZERO ; if( x == ONE ) return ONE ; /** change tail if necessary and determine s **/ psq = p+q ; cx = ONE-x ; if( p < psq*x ){ xx = cx ; cx = x ; pp = q ; qq = p ; indx = 1 ; } else { xx = x ; pp = p ; qq = q ; indx = 0 ; } term = ONE ; ai = ONE ; betain = ONE ; ns = qq + cx*psq ; /** use soper's reduction formulae **/ rx = xx/cx ; lab3: temp = qq-ai ; if(ns == 0) rx = xx ; lab4: term = term*temp*rx/(pp+ai) ; betain = betain+term ; temp = fabs(term) ; if(temp <= ACU && temp <= ACU*betain) goto lab5 ; ai = ai+ONE ; ns = ns-1 ; if(ns >= 0) goto lab3 ; temp = psq ; psq = psq+ONE ; goto lab4 ; lab5: betain = betain*exp(pp*log(xx)+(qq-ONE)*log(cx)-beta)/pp ; if(indx) betain=ONE-betain ; return betain ; } /*---------------------------------------------------------------- algorithm as 109 appl. statist. (1977), vol.26, no.1 (replacing algorithm as 64 appl. statist. (1973), vol.22, no.3) Remark AS R83 and the correction in vol40(1) p.236 have been incorporated in this version. Computes inverse of the incomplete beta function ratio for given positive values of the arguments p and q, alpha between zero and one. log of complete beta function, beta, is assumed to be known. ------------------------------------------------------------------*/ #define SAE -15.0 #define TWO 2.0 #define THREE 3.0 #define FOUR 4.0 #define FIVE 5.0 #define SIX 6.0 #ifndef MAX # define MAX(a,b) (((a)<(b)) ? (b) : (a)) # define MIN(a,b) (((a)>(b)) ? (b) : (a)) #endif double incbeta_inverse( double alpha , double p , double q , double beta ) { int indx , iex ; double fpu , xinbta , a,pp,qq, r,y,t,s,h,w , acu , yprev,prev,sq , g,adj,tx,xin ; fpu = pow(10.0,SAE) ; if( p <= ZERO || q <= ZERO || alpha < ZERO || alpha > ONE ) return -1.0 ; if( alpha == ZERO ) return ZERO ; if( alpha == ONE ) return ONE ; /** change tail if necessary **/ if( alpha > 0.5 ){ a = ONE-alpha ; pp = q ; qq = p ; indx = 1 ; } else { a = alpha ; pp = p ; qq = q ; indx = 0 ; } /** calculate the initial approximation **/ lab2: r = sqrt(-log(a*a)) ; y = r - (2.30753 + 0.27061*r) / (ONE+(0.99229+0.04481*r)*r) ; if(pp > ONE && qq > ONE) goto lab5 ; r = qq+qq ; t = ONE/(9.0*qq) ; t = r * pow( (ONE-t+y*sqrt(t)) , 3.0 ) ; if( t <= ZERO ) goto lab3 ; t = (FOUR*pp+r-TWO)/t ; if( t <= ONE ) goto lab4 ; xinbta = ONE-TWO/(t+ONE) ; goto lab6 ; lab3: xinbta = ONE-exp((log((ONE-a)*qq)+beta)/qq) ; goto lab6 ; lab4: xinbta = exp((log(a*pp)+beta)/pp) ; goto lab6 ; lab5: r = (y*y-THREE)/SIX ; s = ONE/(pp+pp-ONE) ; t = ONE/(qq+qq-ONE) ; h = TWO/(s+t) ; w = y*sqrt(h+r)/h-(t-s)*(r+FIVE/SIX-TWO/(THREE*h)) ; xinbta = pp/(pp+qq*exp(w+w)) ; /** solve for x by a modified newton-raphson method **/ lab6: r = ONE-pp ; t = ONE-qq ; yprev = ZERO ; sq = ONE ; prev = ONE ; if(xinbta < 0.0001) xinbta = 0.0001 ; if(xinbta > 0.9999) xinbta = 0.9999 ; #if 0 iex = -5.0 / (pp*pp) - 1.0/(a*a) - 13.0 ; if( iex < SAE ) iex = SAE ; acu = pow(10.0,iex) ; #else acu = fpu ; #endif lab7: y = incbeta( xinbta , pp,qq,beta ) ; if( y < ZERO ) return -1.0 ; xin = xinbta ; y = (y-a)*exp(beta+r*log(xin)+t*log(ONE-xin)) ; if(y*yprev <= ZERO) prev = MAX(sq, fpu) ; g = ONE ; lab9: adj = g*y ; sq = adj*adj ; if(sq >= prev) goto lab10 ; tx = xinbta-adj ; if(tx >= ZERO && tx <= ONE) goto lab11 ; lab10: g = g/THREE ; goto lab9 ; lab11: if(tx == ZERO || tx == ONE ) goto lab10 ; if(prev <= acu || y*y <= acu || fabs(xinbta-tx) < fpu) goto lab12 ; xinbta = tx ; yprev = y ; goto lab7 ; lab12: xinbta = tx ; if (indx) xinbta = ONE-xinbta ; #if 0 printf("alpha = %g incbeta = %g\n",alpha, incbeta(xinbta,p,q,beta) ); #endif return xinbta ; } #endif /* USE_OLD_METHOD */ /*** given p, return x such that Q(x)=p, for 0 < p < 1 ***/ double qginv( double p ) { double dp , dx , dt , ddq , dq ; int newt ; dp = (p <= 0.5) ? (p) : (1.0-p) ; /* make between 0 and 0.5 */ if( dp <= 0.0 ){ dx = 13.0 ; return ( (p <= 0.5) ? (dx) : (-dx) ) ; } /** Step 1: use 26.2.23 from Abramowitz and Stegun **/ dt = sqrt( -2.0 * log(dp) ) ; dx = dt - ((.010328e+0*dt + .802853e+0)*dt + 2.525517e+0) /(((.001308e+0*dt + .189269e+0)*dt + 1.432788e+0)*dt + 1.e+0) ; /** Step 2: do 3 Newton steps to improve this **/ for( newt=0 ; newt < 3 ; newt++ ){ dq = 0.5e+0 * erfc( dx / 1.414213562373095e+0 ) - dp ; ddq = exp( -0.5e+0 * dx * dx ) / 2.506628274631000e+0 ; dx = dx + dq / ddq ; } return ( (p <= 0.5) ? (dx) : (-dx) ) ; /* return with correct sign */ }