kolmogorov.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. /* Re Kolmogorov statistics, here is Birnbaum and Tingey's formula for the
  2. distribution of D+, the maximum of all positive deviations between a
  3. theoretical distribution function P(x) and an empirical one Sn(x)
  4. from n samples.
  5. +
  6. D = sup [P(x) - S (x)]
  7. n -inf < x < inf n
  8. [n(1-e)]
  9. + - v-1 n-v
  10. Pr{D > e} = > C e (e + v/n) (1 - e - v/n)
  11. n - n v
  12. v=0
  13. [n(1-e)] is the largest integer not exceeding n(1-e).
  14. nCv is the number of combinations of n things taken v at a time. */
  15. #include "mconf.h"
  16. #ifdef ANSIPROT
  17. extern double pow(double, double);
  18. extern double floor(double);
  19. extern double lgam(double);
  20. extern double exp(double);
  21. extern double sqrt(double);
  22. extern double log(double);
  23. extern double fabs(double);
  24. double smirnov(int, double);
  25. double kolmogorov(double);
  26. #else
  27. double pow(), floor(), lgam(), exp(), sqrt(), log(), fabs();
  28. double smirnov(), kolmogorov();
  29. #endif
  30. extern double MAXLOG;
  31. /* Exact Smirnov statistic, for one-sided test. */
  32. double smirnov(n, e) int n;
  33. double e;
  34. {
  35. int v, nn;
  36. double evn, omevn, p, t, c, lgamnp1;
  37. if (n <= 0 || e < 0.0 || e > 1.0)
  38. return (-1.0);
  39. nn = floor((double)n * (1.0 - e));
  40. p = 0.0;
  41. if (n < 1013) {
  42. c = 1.0;
  43. for (v = 0; v <= nn; v++) {
  44. evn = e + ((double)v) / n;
  45. p += c * pow(evn, (double)(v - 1)) * pow(1.0 - evn, (double)(n - v));
  46. /* Next combinatorial term; worst case error = 4e-15. */
  47. c *= ((double)(n - v)) / (v + 1);
  48. }
  49. } else {
  50. lgamnp1 = lgam((double)(n + 1));
  51. for (v = 0; v <= nn; v++) {
  52. evn = e + ((double)v) / n;
  53. omevn = 1.0 - evn;
  54. if (fabs(omevn) > 0.0) {
  55. t = lgamnp1 - lgam((double)(v + 1)) - lgam((double)(n - v + 1)) +
  56. (v - 1) * log(evn) + (n - v) * log(omevn);
  57. if (t > -MAXLOG)
  58. p += exp(t);
  59. }
  60. }
  61. }
  62. return (p * e);
  63. }
  64. /* Kolmogorov's limiting distribution of two-sided test, returns
  65. probability that sqrt(n) * max deviation > y,
  66. or that max deviation > y/sqrt(n).
  67. The approximation is useful for the tail of the distribution
  68. when n is large. */
  69. double kolmogorov(y) double y;
  70. {
  71. double p, t, r, sign, x;
  72. x = -2.0 * y * y;
  73. sign = 1.0;
  74. p = 0.0;
  75. r = 1.0;
  76. do {
  77. t = exp(x * r * r);
  78. p += sign * t;
  79. if (t == 0.0)
  80. break;
  81. r += 1.0;
  82. sign = -sign;
  83. } while ((t / p) > 1.1e-16);
  84. return (p + p);
  85. }
  86. /* Functional inverse of Smirnov distribution
  87. finds e such that smirnov(n,e) = p. */
  88. double smirnovi(n, p) int n;
  89. double p;
  90. {
  91. double e, t, dpde;
  92. if (p <= 0.0 || p > 1.0) {
  93. mtherr("smirnovi", DOMAIN);
  94. return 0.0;
  95. }
  96. /* Start with approximation p = exp(-2 n e^2). */
  97. e = sqrt(-log(p) / (2.0 * n));
  98. do {
  99. /* Use approximate derivative in Newton iteration. */
  100. t = -2.0 * n * e;
  101. dpde = 2.0 * t * exp(t * e);
  102. if (fabs(dpde) > 0.0)
  103. t = (p - smirnov(n, e)) / dpde;
  104. else {
  105. mtherr("smirnovi", UNDERFLOW);
  106. return 0.0;
  107. }
  108. e = e + t;
  109. if (e >= 1.0 || e <= 0.0) {
  110. mtherr("smirnovi", OVERFLOW);
  111. return 0.0;
  112. }
  113. } while (fabs(t / e) > 1e-10);
  114. return (e);
  115. }
  116. /* Functional inverse of Kolmogorov statistic for two-sided test.
  117. Finds y such that kolmogorov(y) = p.
  118. If e = smirnovi (n,p), then kolmogi(2 * p) / sqrt(n) should
  119. be close to e. */
  120. double kolmogi(p) double p;
  121. {
  122. double y, t, dpdy;
  123. if (p <= 0.0 || p > 1.0) {
  124. mtherr("kolmogi", DOMAIN);
  125. return 0.0;
  126. }
  127. /* Start with approximation p = 2 exp(-2 y^2). */
  128. y = sqrt(-0.5 * log(0.5 * p));
  129. do {
  130. /* Use approximate derivative in Newton iteration. */
  131. t = -2.0 * y;
  132. dpdy = 4.0 * t * exp(t * y);
  133. if (fabs(dpdy) > 0.0)
  134. t = (p - kolmogorov(y)) / dpdy;
  135. else {
  136. mtherr("kolmogi", UNDERFLOW);
  137. return 0.0;
  138. }
  139. y = y + t;
  140. } while (fabs(t / y) > 1e-10);
  141. return (y);
  142. }
  143. #ifdef SALONE
  144. /* Type in a number. */
  145. void getnum(s, px) char *s;
  146. double *px;
  147. {
  148. char str[30];
  149. printf(" %s (%.15e) ? ", s, *px);
  150. gets(str);
  151. if (str[0] == '\0' || str[0] == '\n')
  152. return;
  153. sscanf(str, "%lf", px);
  154. printf("%.15e\n", *px);
  155. }
  156. /* Type in values, get answers. */
  157. void main() {
  158. int n;
  159. double e, p, ps, pk, ek, y;
  160. n = 5;
  161. e = 0.0;
  162. p = 0.1;
  163. loop:
  164. ps = n;
  165. getnum("n", &ps);
  166. n = ps;
  167. if (n <= 0) {
  168. printf("? Operator error.\n");
  169. goto loop;
  170. }
  171. /*
  172. getnum ("e", &e);
  173. ps = smirnov (n, e);
  174. y = sqrt ((double) n) * e;
  175. printf ("y = %.4e\n", y);
  176. pk = kolmogorov (y);
  177. printf ("Smirnov = %.15e, Kolmogorov/2 = %.15e\n", ps, pk / 2.0);
  178. */
  179. getnum("p", &p);
  180. e = smirnovi(n, p);
  181. printf("Smirnov e = %.15e\n", e);
  182. y = kolmogi(2.0 * p);
  183. ek = y / sqrt((double)n);
  184. printf("Kolmogorov e = %.15e\n", ek);
  185. goto loop;
  186. }
  187. #endif