home *** CD-ROM | disk | FTP | other *** search
- /*--------------------------------------------------------------------
- * The GMT-system: @(#)gmt_stat.c 2.3 2/4/95
- *
- * Copyright (c) 1991-1995 by P. Wessel and W. H. F. Smith
- * See README file for copying and redistribution conditions.
- *--------------------------------------------------------------------*/
- /* stat_functions.c
- some stuff for significance tests.
- */
-
- #include "gmt.h"
-
- int inc_beta(a,b,x,ibeta)
- double a, b, x, *ibeta;
- {
- double bt, gama, gamb, gamab, cf_beta ();
-
- if (a <= 0.0) {
- fprintf(stderr,"Inc Beta: Bad a (a <= 0).\n");
- return(-1);
- }
- if (b <= 0.0) {
- fprintf(stderr,"Inc Beta: Bad b (b <= 0).\n");
- return(-1);
- }
- if (x > 0.0 && x < 1.0) {
- ln_gamma_r(a, &gama);
- ln_gamma_r(b, &gamb);
- ln_gamma_r( (a+b), &gamab);
- bt = exp(gamab - gama - gamb
- + a * d_log(x) + b * d_log(1.0 - x) );
-
- /* Here there is disagreement on the range of x which
- converges efficiently. Abramowitz and Stegun
- say to use x < (a - 1) / (a + b - 2). Editions
- of Numerical Recipes thru mid 1987 say
- x < ( (a + 1) / (a + b + 1), but the code has
- x < ( (a + 1) / (a + b + 2). Editions printed
- late 1987 and after say x < ( (a + 1) / (a + b + 2)
- in text as well as code. What to do ? */
-
- if (x < ( (a + 1) / (a + b + 2) ) ) {
- *ibeta = bt * cf_beta(a, b, x) / a;
- }
- else {
- *ibeta = 1.0 - bt * cf_beta(b, a, (1.0 - x) ) / b;
- }
- return(0);
- }
- else if (x == 0.0) {
- *ibeta = 0.0;
- return(0);
- }
- else if (x == 1.0) {
- *ibeta = 1.0;
- return(0);
- }
- else if (x < 0.0) {
- fprintf(stderr,"Inc Beta: Bad x (x < 0).\n");
- *ibeta = 0.0;
- }
- else if (x > 1.0) {
- fprintf(stderr,"Inc Beta: Bad x (x > 1).\n");
- *ibeta = 1.0;
- }
- return(-1);
- }
-
- int ln_gamma_r(x, lngam)
- double x, *lngam;
- {
- /* Get natural logrithm of Gamma(x), x > 0.
- To maintain full accuracy, this
- routine uses Gamma(1 + x) / x when
- x < 1. This routine in turn calls
- ln_gamma(x), which computes the
- actual function value. ln_gamma
- assumes it is being called in a
- smart way, and does not check the
- range of x. */
-
- if (x > 1.0) {
- *lngam = ln_gamma(x);
- return(0);
- }
- if (x > 0.0 && x < 1.0) {
- *lngam = ln_gamma(1.0 + x) - d_log(x);
- return(0);
- }
- if (x == 1.0) {
- *lngam = 0.0;
- return(0);
- }
- fprintf(stderr,"Ln Gamma: Bad x (x <= 0).\n");
- return(-1);
- }
-
- double ln_gamma(xx)
- double xx;
- {
- /* Routine to compute natural log of Gamma(x)
- by Lanczos approximation. Most accurate
- for x > 1; fails for x <= 0. No error
- checking is done here; it is assumed
- that this is called by ln_gamma_r() */
-
- static double cof[6] = {
- 76.18009173,
- -86.50532033,
- 24.01409822,
- -1.231739516,
- 0.120858003e-2,
- -0.536382e-5
- };
-
- static double stp = 2.50662827465, half = 0.5, one = 1.0, fpf = 5.5;
- double x, tmp, ser;
-
- int i;
-
- x = xx - one;
- tmp = x + fpf;
- tmp = (x + half) * d_log(tmp) - tmp;
- ser = one;
- for (i = 0; i < 6; i++) {
- x += one;
- ser += (cof[i]/x);
- }
- return(tmp + d_log(stp*ser) );
- }
-
- double cf_beta(a,b,x)
- double a,b,x;
- {
- /* Continued fraction method called by inc_beta. */
-
- static int itmax = 100;
- static double eps = 3.0e-7;
-
- double am = 1.0, bm = 1.0, az = 1.0;
- double qab, qap, qam, bz, em, tem, d;
- double ap, bp, app, bpp, aold;
-
- int m = 0;
-
- qab = a + b;
- qap = a + 1.0;
- qam = a - 1.0;
- bz = 1.0 - qab * x / qap;
-
- do {
- m++;
- em = m;
- tem = em + em;
- d = em*(b-m)*x/((qam+tem)*(a+tem));
- ap = az+d*am;
- bp = bz+d*bm;
- d = -(a+m)*(qab+em)*x/((a+tem)*(qap+tem));
- app = ap+d*az;
- bpp = bp+d*bz;
- aold = az;
- am = ap/bpp;
- bm = bp/bpp;
- az = app/bpp;
- bz = 1.0;
- } while ( ( (fabs(az-aold) ) >= (eps * fabs(az) ) ) && (m < itmax) );
-
- if (m == itmax)
- fprintf(stderr,"BetaCF: A or B too big, or ITMAX too small.\n");
-
- return(az);
- }
-
- int f_test(chisq1, nu1, chisq2, nu2, prob)
- double chisq1, chisq2, *prob;
- int nu1, nu2;
- {
- /* Routine to compute the probability that
- two variances are the same.
- chisq1 is distributed as chisq with
- nu1 degrees of freedom; ditto for
- chisq2 and nu2. If these are independent
- and we form the ratio
- F = max(chisq1,chisq2)/min(chisq1,chisq2)
- then we can ask what is the probability
- that an F greater than this would occur
- by chance. It is this probability that
- is returned in prob. When prob is small,
- it is likely that the two chisq represent
- two different populations; the confidence
- that the two do not represent the same pop
- is 1.0 - prob. This is a two-sided test.
- This follows some ideas in Numerical Recipes, CRC Handbook,
- and Abramowitz and Stegun. */
-
- double f, df1, df2, p1, p2;
-
- if ( chisq1 <= 0.0) {
- fprintf(stderr,"f_test: Chi-Square One <= 0.0\n");
- return(-1);
- }
- if ( chisq2 <= 0.0) {
- fprintf(stderr,"f_test: Chi-Square Two <= 0.0\n");
- return(-1);
- }
- if (chisq1 > chisq2) {
- f = chisq1/chisq2;
- df1 = nu1;
- df2 = nu2;
- }
- else {
- f = chisq2/chisq1;
- df1 = nu2;
- df2 = nu1;
- }
- if (inc_beta(0.5*df2, 0.5*df1, df2/(df2+df1*f), &p1) ) {
- fprintf(stderr,"f_test: Trouble on 1st inc_beta call.\n");
- return(-1);
- }
- if (inc_beta(0.5*df1, 0.5*df2, df1/(df1+df2/f), &p2) ) {
- fprintf(stderr,"f_test: Trouble on 2nd inc_beta call.\n");
- return(-1);
- }
- *prob = p1 + (1.0 - p2);
- return(0);
- }
-
- int sig_f(chi1, n1, chi2, n2, level, prob)
- double chi1, chi2, level, *prob;
- int n1, n2;
- {
- /* Returns TRUE if chi1 significantly less than chi2
- at the level level. Returns FALSE if:
- chi1 > chi2;
- error occurs in f_test();
- chi1 < chi2 but not significant at level. */
-
- int trouble;
- double p;
-
- trouble = f_test(chi1, n1, chi2, n2, &p);
- *prob = (1.0 - 0.5*p); /* Make it one-sided */
- if (trouble) return(0);
- if (chi1 > chi2) return (0);
- return((*prob) >= level);
- }
-
-