kolmogorov.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 <math.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
  33. smirnov (n, e)
  34. int n;
  35. double e;
  36. {
  37. int v, nn;
  38. double evn, omevn, p, t, c, lgamnp1;
  39. if (n <= 0 || e < 0.0 || e > 1.0)
  40. return (-1.0);
  41. nn = floor ((double) n * (1.0 - e));
  42. p = 0.0;
  43. if (n < 1013)
  44. {
  45. c = 1.0;
  46. for (v = 0; v <= nn; v++)
  47. {
  48. evn = e + ((double) v) / n;
  49. p += c * pow (evn, (double) (v - 1))
  50. * pow (1.0 - evn, (double) (n - v));
  51. /* Next combinatorial term; worst case error = 4e-15. */
  52. c *= ((double) (n - v)) / (v + 1);
  53. }
  54. }
  55. else
  56. {
  57. lgamnp1 = lgam ((double) (n + 1));
  58. for (v = 0; v <= nn; v++)
  59. {
  60. evn = e + ((double) v) / n;
  61. omevn = 1.0 - evn;
  62. if (fabs (omevn) > 0.0)
  63. {
  64. t = lgamnp1
  65. - lgam ((double) (v + 1))
  66. - lgam ((double) (n - v + 1))
  67. + (v - 1) * log (evn)
  68. + (n - v) * log (omevn);
  69. if (t > -MAXLOG)
  70. p += exp (t);
  71. }
  72. }
  73. }
  74. return (p * e);
  75. }
  76. /* Kolmogorov's limiting distribution of two-sided test, returns
  77. probability that sqrt(n) * max deviation > y,
  78. or that max deviation > y/sqrt(n).
  79. The approximation is useful for the tail of the distribution
  80. when n is large. */
  81. double
  82. kolmogorov (y)
  83. double y;
  84. {
  85. double p, t, r, sign, x;
  86. x = -2.0 * y * y;
  87. sign = 1.0;
  88. p = 0.0;
  89. r = 1.0;
  90. do
  91. {
  92. t = exp (x * r * r);
  93. p += sign * t;
  94. if (t == 0.0)
  95. break;
  96. r += 1.0;
  97. sign = -sign;
  98. }
  99. while ((t / p) > 1.1e-16);
  100. return (p + p);
  101. }
  102. /* Functional inverse of Smirnov distribution
  103. finds e such that smirnov(n,e) = p. */
  104. double
  105. smirnovi (n, p)
  106. int n;
  107. double p;
  108. {
  109. double e, t, dpde;
  110. if (p <= 0.0 || p > 1.0)
  111. {
  112. mtherr ("smirnovi", DOMAIN);
  113. return 0.0;
  114. }
  115. /* Start with approximation p = exp(-2 n e^2). */
  116. e = sqrt (-log (p) / (2.0 * n));
  117. do
  118. {
  119. /* Use approximate derivative in Newton iteration. */
  120. t = -2.0 * n * e;
  121. dpde = 2.0 * t * exp (t * e);
  122. if (fabs (dpde) > 0.0)
  123. t = (p - smirnov (n, e)) / dpde;
  124. else
  125. {
  126. mtherr ("smirnovi", UNDERFLOW);
  127. return 0.0;
  128. }
  129. e = e + t;
  130. if (e >= 1.0 || e <= 0.0)
  131. {
  132. mtherr ("smirnovi", OVERFLOW);
  133. return 0.0;
  134. }
  135. }
  136. while (fabs (t / e) > 1e-10);
  137. return (e);
  138. }
  139. /* Functional inverse of Kolmogorov statistic for two-sided test.
  140. Finds y such that kolmogorov(y) = p.
  141. If e = smirnovi (n,p), then kolmogi(2 * p) / sqrt(n) should
  142. be close to e. */
  143. double
  144. kolmogi (p)
  145. double p;
  146. {
  147. double y, t, dpdy;
  148. if (p <= 0.0 || p > 1.0)
  149. {
  150. mtherr ("kolmogi", DOMAIN);
  151. return 0.0;
  152. }
  153. /* Start with approximation p = 2 exp(-2 y^2). */
  154. y = sqrt (-0.5 * log (0.5 * p));
  155. do
  156. {
  157. /* Use approximate derivative in Newton iteration. */
  158. t = -2.0 * y;
  159. dpdy = 4.0 * t * exp (t * y);
  160. if (fabs (dpdy) > 0.0)
  161. t = (p - kolmogorov (y)) / dpdy;
  162. else
  163. {
  164. mtherr ("kolmogi", UNDERFLOW);
  165. return 0.0;
  166. }
  167. y = y + t;
  168. }
  169. while (fabs (t / y) > 1e-10);
  170. return (y);
  171. }
  172. #ifdef SALONE
  173. /* Type in a number. */
  174. void
  175. getnum (s, px)
  176. char *s;
  177. double *px;
  178. {
  179. char str[30];
  180. printf (" %s (%.15e) ? ", s, *px);
  181. gets (str);
  182. if (str[0] == '\0' || str[0] == '\n')
  183. return;
  184. sscanf (str, "%lf", px);
  185. printf ("%.15e\n", *px);
  186. }
  187. /* Type in values, get answers. */
  188. void
  189. main ()
  190. {
  191. int n;
  192. double e, p, ps, pk, ek, y;
  193. n = 5;
  194. e = 0.0;
  195. p = 0.1;
  196. loop:
  197. ps = n;
  198. getnum ("n", &ps);
  199. n = ps;
  200. if (n <= 0)
  201. {
  202. printf ("? Operator error.\n");
  203. goto loop;
  204. }
  205. /*
  206. getnum ("e", &e);
  207. ps = smirnov (n, e);
  208. y = sqrt ((double) n) * e;
  209. printf ("y = %.4e\n", y);
  210. pk = kolmogorov (y);
  211. printf ("Smirnov = %.15e, Kolmogorov/2 = %.15e\n", ps, pk / 2.0);
  212. */
  213. getnum ("p", &p);
  214. e = smirnovi (n, p);
  215. printf ("Smirnov e = %.15e\n", e);
  216. y = kolmogi (2.0 * p);
  217. ek = y / sqrt ((double) n);
  218. printf ("Kolmogorov e = %.15e\n", ek);
  219. goto loop;
  220. }
  221. #endif