double gsl_cdf_binomial_Q (const unsigned int k, const double p, const unsigned int n) { double Q; double a; double b; if (p > 1.0 || p < 0.0) { CDF_ERROR ("p < 0 or p > 1", GSL_EDOM); } if (k >= n) { Q = 0.0; } else { a = (double) k + 1.0; b = (double) n - k; Q = gsl_cdf_beta_P (p, a, b); } return Q; }
static double bisect (double x, double P, double a, double b, double xtol, double Ptol) { double x0 = 0, x1 = 1, Px; while (fabs(x1 - x0) > xtol) { Px = gsl_cdf_beta_P (x, a, b); if (fabs(Px - P) < Ptol) { /* return as soon as approximation is good enough, including on the first iteration */ return x; } else if (Px < P) { x0 = x; } else if (Px > P) { x1 = x; } x = 0.5 * (x0 + x1); } return x; }
double gsl_cdf_negative_binomial_P (const unsigned int k, const double p, const double n) { double P; double a; double b; if (p > 1.0 || p < 0.0) { CDF_ERROR ("p < 0 or p > 1", GSL_EDOM); } if (n < 0) { CDF_ERROR ("n < 0", GSL_EDOM); } a = (double) n; b = (double) k + 1.0; P = gsl_cdf_beta_P (p, a, b); return P; }
double gsl_cdf_beta_Pinv (const double P, const double a, const double b) { double x, mean; if (P < 0.0 || P > 1.0) { CDF_ERROR ("P must be in range 0 < P < 1", GSL_EDOM); } if (a < 0.0) { CDF_ERROR ("a < 0", GSL_EDOM); } if (b < 0.0) { CDF_ERROR ("b < 0", GSL_EDOM); } if (P == 0.0) { return 0.0; } if (P == 1.0) { return 1.0; } if (P > 0.5) { return gsl_cdf_beta_Qinv (1 - P, a, b); } mean = a / (a + b); if (P < 0.1) { /* small x */ double lg_ab = gsl_sf_lngamma (a + b); double lg_a = gsl_sf_lngamma (a); double lg_b = gsl_sf_lngamma (b); double lx = (log (a) + lg_a + lg_b - lg_ab + log (P)) / a; if (lx <= 0) { x = exp (lx); /* first approximation */ x *= pow (1 - x, -(b - 1) / a); /* second approximation */ } else { x = mean; } if (x > mean) x = mean; } else { /* Use expected value as first guess */ x = mean; } { double lambda, dP, phi; unsigned int n = 0; start: dP = P - gsl_cdf_beta_P (x, a, b); phi = gsl_ran_beta_pdf (x, a, b); if (dP == 0.0 || n++ > 64) goto end; lambda = dP / GSL_MAX (2 * fabs (dP / x), phi); { double step0 = lambda; double step1 = -((a - 1) / x - (b - 1) / (1 - x)) * lambda * lambda / 2; double step = step0; if (fabs (step1) < fabs (step0)) { step += step1; } else { /* scale back step to a reasonable size when too large */ step *= 2 * fabs (step0 / step1); }; if (x + step > 0 && x + step < 1) { x += step; } else { x = sqrt (x) * sqrt (mean); /* try a new starting point */ } if (fabs (step0) > 1e-10 * x) goto start; } end: return x; } }
int main(int argc, char **argv){ distlist distribution = Normal; char msg[10000], c; int pval = 0, qval = 0; double param1 = GSL_NAN, param2 =GSL_NAN, findme = GSL_NAN; char number[1000]; sprintf(msg, "%s [opts] number_to_lookup\n\n" "Look up a probability or p-value for a given standard distribution.\n" "[This is still loosely written and counts as beta. Notably, negative numbers are hard to parse.]\n" "E.g.:\n" "%s -dbin 100 .5 34\n" "sets the distribution to a Binomial(100, .5), and find the odds of 34 appearing.\n" "%s -p 2 \n" "find the area of the Normal(0,1) between -infty and 2. \n" "\n" "-pval Find the p-value: integral from -infinity to your value\n" "-qval Find the q-value: integral from your value to infinity\n" "\n" "After giving an optional -p or -q, specify the distribution. \n" "Default is Normal(0, 1). Other options:\n" "\t\t-binom Binomial(n, p)\n" "\t\t-beta Beta(a, b)\n" "\t\t-f F distribution(df1, df2)\n" "\t\t-norm Normal(mu, sigma)\n" "\t\t-negative bin Negative binomial(n, p)\n" "\t\t-poisson Poisson(L)\n" "\t\t-t t distribution(df)\n" "I just need enough letters to distinctly identify a distribution.\n" , argv[0], argv[0], argv[0]); opterr=0; if(argc==1){ printf("%s", msg); return 0; } while ((c = getopt (argc, argv, "B:b:F:f:N:n:pqT:t:")) != -1){ switch (c){ case 'B': case 'b': if (optarg[0]=='i') distribution = Binomial; else if (optarg[0]=='e') distribution = Beta; else { printf("I can't parse the option -b%s\n", optarg); exit(0); } param1 = atof(argv[optind]); param2 = atof(argv[optind+1]); findme = atof(argv[optind+2]); break; case 'F': case 'f': distribution = F; param1 = atof(argv[optind]); findme = atof(argv[optind+1]); break; case 'H': case 'h': printf("%s", msg); return 0; case 'n': case 'N': if (optarg[0]=='o'){ //normal param1 = atof(argv[optind]); param2 = atof(argv[optind+1]); findme = atof(argv[optind+2]); } else if (optarg[0]=='e'){ distribution = Negbinom; param1 = atof(argv[optind]); param2 = atof(argv[optind+1]); findme = atof(argv[optind+2]); } else { printf("I can't parse the option -n%s\n", optarg); exit(0); } break; case 'p': if (!optarg || optarg[0] == 'v') pval++; else if (optarg[0] == 'o'){ distribution = Poisson; param1 = atof(argv[optind]); findme = atof(argv[optind+1]); } else { printf("I can't parse the option -p%s\n", optarg); exit(0); } break; case 'q': qval++; break; case 'T': case 't': distribution = T; param1 = atof(argv[optind]); findme = atof(argv[optind+1]); break; case '?'://probably a negative number if (optarg) snprintf(number, 1000, "%c%s", optopt, optarg); else snprintf(number, 1000, "%c", optopt); if (gsl_isnan(param1)) param1 = -atof(number); else if (gsl_isnan(param2)) param2 = -atof(number); else if (gsl_isnan(findme)) findme = -atof(number); } } if (gsl_isnan(findme)) findme = atof(argv[optind]); //defaults, as promised if (gsl_isnan(param1)) param1 = 0; if (gsl_isnan(param2)) param2 = 1; if (!pval && !qval){ double val = distribution == Beta ? gsl_ran_beta_pdf(findme, param1, param2) : distribution == Binomial ? gsl_ran_binomial_pdf(findme, param2, param1) : distribution == F ? gsl_ran_fdist_pdf(findme, param1, param2) : distribution == Negbinom ? gsl_ran_negative_binomial_pdf(findme, param2, param1) : distribution == Normal ? gsl_ran_gaussian_pdf(findme, param2)+param1 : distribution == Poisson ? gsl_ran_poisson_pdf(findme, param1) : distribution == T ? gsl_ran_tdist_pdf(findme, param1) : GSL_NAN; printf("%g\n", val); return 0; } if (distribution == Binomial){ printf("Sorry, the GSL doesn't have a Binomial CDF.\n"); return 0; } if (distribution == Negbinom){ printf("Sorry, the GSL doesn't have a Negative Binomial CDF.\n"); return 0; } if (distribution == Poisson){ printf("Sorry, the GSL doesn't have a Poisson CDF.\n"); return 0; } if (pval){ double val = distribution == Beta ? gsl_cdf_beta_P(findme, param1, param2) : distribution == F ? gsl_cdf_fdist_P(findme, param1, param2) : distribution == Normal ? gsl_cdf_gaussian_P(findme-param1, param2) : distribution == T ? gsl_cdf_tdist_P(findme, param1) : GSL_NAN; printf("%g\n", val); return 0; } if (qval){ double val = distribution == Beta ? gsl_cdf_beta_Q(findme, param1, param2) : distribution == F ? gsl_cdf_fdist_Q(findme, param1, param2) : distribution == Normal ? gsl_cdf_gaussian_Q(findme-param1, param2) : distribution == T ? gsl_cdf_tdist_Q(findme, param1) : GSL_NAN; printf("%g\n", val); } }