123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /* Re Kolmogorov statistics, here is Birnbaum and Tingey's formula for the
- distribution of D+, the maximum of all positive deviations between a
- theoretical distribution function P(x) and an empirical one Sn(x)
- from n samples.
- +
- D = sup [P(x) - S (x)]
- n -inf < x < inf n
- [n(1-e)]
- + - v-1 n-v
- Pr{D > e} = > C e (e + v/n) (1 - e - v/n)
- n - n v
- v=0
- [n(1-e)] is the largest integer not exceeding n(1-e).
- nCv is the number of combinations of n things taken v at a time. */
- #include <math.h>
- #ifdef ANSIPROT
- extern double pow ( double, double );
- extern double floor ( double );
- extern double lgam ( double );
- extern double exp ( double );
- extern double sqrt ( double );
- extern double log ( double );
- extern double fabs ( double );
- double smirnov ( int, double );
- double kolmogorov ( double );
- #else
- double pow (), floor (), lgam (), exp (), sqrt (), log (), fabs ();
- double smirnov (), kolmogorov ();
- #endif
- extern double MAXLOG;
- /* Exact Smirnov statistic, for one-sided test. */
- double
- smirnov (n, e)
- int n;
- double e;
- {
- int v, nn;
- double evn, omevn, p, t, c, lgamnp1;
- if (n <= 0 || e < 0.0 || e > 1.0)
- return (-1.0);
- nn = floor ((double) n * (1.0 - e));
- p = 0.0;
- if (n < 1013)
- {
- c = 1.0;
- for (v = 0; v <= nn; v++)
- {
- evn = e + ((double) v) / n;
- p += c * pow (evn, (double) (v - 1))
- * pow (1.0 - evn, (double) (n - v));
- /* Next combinatorial term; worst case error = 4e-15. */
- c *= ((double) (n - v)) / (v + 1);
- }
- }
- else
- {
- lgamnp1 = lgam ((double) (n + 1));
- for (v = 0; v <= nn; v++)
- {
- evn = e + ((double) v) / n;
- omevn = 1.0 - evn;
- if (fabs (omevn) > 0.0)
- {
- t = lgamnp1
- - lgam ((double) (v + 1))
- - lgam ((double) (n - v + 1))
- + (v - 1) * log (evn)
- + (n - v) * log (omevn);
- if (t > -MAXLOG)
- p += exp (t);
- }
- }
- }
- return (p * e);
- }
- /* Kolmogorov's limiting distribution of two-sided test, returns
- probability that sqrt(n) * max deviation > y,
- or that max deviation > y/sqrt(n).
- The approximation is useful for the tail of the distribution
- when n is large. */
- double
- kolmogorov (y)
- double y;
- {
- double p, t, r, sign, x;
- x = -2.0 * y * y;
- sign = 1.0;
- p = 0.0;
- r = 1.0;
- do
- {
- t = exp (x * r * r);
- p += sign * t;
- if (t == 0.0)
- break;
- r += 1.0;
- sign = -sign;
- }
- while ((t / p) > 1.1e-16);
- return (p + p);
- }
- /* Functional inverse of Smirnov distribution
- finds e such that smirnov(n,e) = p. */
- double
- smirnovi (n, p)
- int n;
- double p;
- {
- double e, t, dpde;
- if (p <= 0.0 || p > 1.0)
- {
- mtherr ("smirnovi", DOMAIN);
- return 0.0;
- }
- /* Start with approximation p = exp(-2 n e^2). */
- e = sqrt (-log (p) / (2.0 * n));
- do
- {
- /* Use approximate derivative in Newton iteration. */
- t = -2.0 * n * e;
- dpde = 2.0 * t * exp (t * e);
- if (fabs (dpde) > 0.0)
- t = (p - smirnov (n, e)) / dpde;
- else
- {
- mtherr ("smirnovi", UNDERFLOW);
- return 0.0;
- }
- e = e + t;
- if (e >= 1.0 || e <= 0.0)
- {
- mtherr ("smirnovi", OVERFLOW);
- return 0.0;
- }
- }
- while (fabs (t / e) > 1e-10);
- return (e);
- }
- /* Functional inverse of Kolmogorov statistic for two-sided test.
- Finds y such that kolmogorov(y) = p.
- If e = smirnovi (n,p), then kolmogi(2 * p) / sqrt(n) should
- be close to e. */
- double
- kolmogi (p)
- double p;
- {
- double y, t, dpdy;
- if (p <= 0.0 || p > 1.0)
- {
- mtherr ("kolmogi", DOMAIN);
- return 0.0;
- }
- /* Start with approximation p = 2 exp(-2 y^2). */
- y = sqrt (-0.5 * log (0.5 * p));
- do
- {
- /* Use approximate derivative in Newton iteration. */
- t = -2.0 * y;
- dpdy = 4.0 * t * exp (t * y);
- if (fabs (dpdy) > 0.0)
- t = (p - kolmogorov (y)) / dpdy;
- else
- {
- mtherr ("kolmogi", UNDERFLOW);
- return 0.0;
- }
- y = y + t;
- }
- while (fabs (t / y) > 1e-10);
- return (y);
- }
- #ifdef SALONE
- /* Type in a number. */
- void
- getnum (s, px)
- char *s;
- double *px;
- {
- char str[30];
- printf (" %s (%.15e) ? ", s, *px);
- gets (str);
- if (str[0] == '\0' || str[0] == '\n')
- return;
- sscanf (str, "%lf", px);
- printf ("%.15e\n", *px);
- }
- /* Type in values, get answers. */
- void
- main ()
- {
- int n;
- double e, p, ps, pk, ek, y;
- n = 5;
- e = 0.0;
- p = 0.1;
- loop:
- ps = n;
- getnum ("n", &ps);
- n = ps;
- if (n <= 0)
- {
- printf ("? Operator error.\n");
- goto loop;
- }
- /*
- getnum ("e", &e);
- ps = smirnov (n, e);
- y = sqrt ((double) n) * e;
- printf ("y = %.4e\n", y);
- pk = kolmogorov (y);
- printf ("Smirnov = %.15e, Kolmogorov/2 = %.15e\n", ps, pk / 2.0);
- */
- getnum ("p", &p);
- e = smirnovi (n, p);
- printf ("Smirnov e = %.15e\n", e);
- y = kolmogi (2.0 * p);
- ek = y / sqrt ((double) n);
- printf ("Kolmogorov e = %.15e\n", ek);
- goto loop;
- }
- #endif
|