as181.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. #include <math.h>
  2. #include <stdio.h>
  3. #include <grass/cdhc.h>
  4. #include "local_proto.h"
  5. /* Local function prototypes */
  6. static double poly(double c[], int nord, double x);
  7. /*-Algorithm AS 181
  8. * by J.P. Royston, 1982.
  9. * Applied Statistics 31(2):176-180
  10. *
  11. * Translation to C by James Darrell McCauley, mccauley@ecn.purdue.edu.
  12. *
  13. * Calculates Shapiro and Wilk's W statistic and its sig. level
  14. *
  15. * Originally used:
  16. * Auxiliary routines required: Cdhc_alnorm = algorithm AS 66 and Cdhc_nscor2
  17. * from AS 177.
  18. * Note: ppnd() from as66 was replaced with ppnd16() from as241.
  19. */
  20. void wext(double x[], int n, double ssq, double a[], int n2, double eps,
  21. double *w, double *pw, int *ifault)
  22. {
  23. double eu3, lamda, ybar, sdy, al, un, ww, y, z;
  24. int i, j, n3, nc;
  25. static double wa[3] = { 0.118898, 0.133414, 0.327907 };
  26. static double wb[4] = { -0.37542, -0.492145, -1.124332, -0.199422 };
  27. static double wc[4] = { -3.15805, 0.729399, 3.01855, 1.558776 };
  28. static double wd[6] = { 0.480385, 0.318828, 0.0, -0.0241665, 0.00879701,
  29. 0.002989646
  30. };
  31. static double we[6] = { -1.91487, -1.37888, -0.04183209, 0.1066339,
  32. -0.03513666, -0.01504614
  33. };
  34. static double wf[7] = { -3.73538, -1.015807, -0.331885, 0.1773538,
  35. -0.01638782, -0.03215018, 0.003852646
  36. };
  37. static double unl[3] = { -3.8, -3.0, -1.0 };
  38. static double unh[3] = { 8.6, 5.8, 5.4 };
  39. static int nc1[3] = { 5, 5, 5 };
  40. static int nc2[3] = { 3, 4, 5 };
  41. double c[5];
  42. int upper = 1;
  43. static double pi6 = 1.90985932, stqr = 1.04719755;
  44. static double zero = 0.0, tqr = 0.75, one = 1.0;
  45. static double onept4 = 1.4, three = 3.0, five = 5.0;
  46. static double c1[5][3] = {
  47. {-1.26233, -2.28135, -3.30623},
  48. {1.87969, 2.26186, 2.76287},
  49. {0.0649583, 0.0, -0.83484},
  50. {-0.0475604, 0.0, 1.20857},
  51. {-0.0139682, -0.00865763, -0.507590}
  52. };
  53. static double c2[5][3] = {
  54. {-0.287696, -1.63638, -5.991908},
  55. {1.78953, 5.60924, 21.04575},
  56. {-0.180114, -3.63738, -24.58061},
  57. {0.0, 1.08439, 13.78661},
  58. {0.0, 0.0, -2.835295}
  59. };
  60. *ifault = 1;
  61. *pw = one;
  62. *w = one;
  63. if (n <= 2)
  64. return;
  65. *ifault = 3;
  66. if (n / 2 != n2)
  67. return;
  68. *ifault = 2;
  69. if (n > 2000)
  70. return;
  71. *ifault = 0;
  72. i = n - 1;
  73. for (*w = 0.0, j = 0; j < n2; ++j)
  74. *w += a[j] * (x[i--] - x[j]);
  75. *w *= *w / ssq;
  76. if (*w > one) {
  77. *w = one;
  78. return;
  79. }
  80. else if (n > 6) { /* Get significance level of W */
  81. /*
  82. * N between 7 and 2000 ... Transform W to Y, get mean and sd,
  83. * standardize and get significance level
  84. */
  85. if (n <= 20) {
  86. al = log((double)n) - three;
  87. lamda = poly(wa, 3, al);
  88. ybar = exp(poly(wb, 4, al));
  89. sdy = exp(poly(wc, 4, al));
  90. }
  91. else {
  92. al = log((double)n) - five;
  93. lamda = poly(wd, 6, al);
  94. ybar = exp(poly(we, 6, al));
  95. sdy = exp(poly(wf, 7, al));
  96. }
  97. y = pow(one - *w, lamda);
  98. z = (y - ybar) / sdy;
  99. *pw = Cdhc_alnorm(z, upper);
  100. return;
  101. }
  102. else {
  103. /* Deal with N less than 7 (Exact significance level for N = 3). */
  104. if (*w >= eps) {
  105. ww = *w;
  106. if (*w >= eps) {
  107. ww = *w;
  108. if (n == 3) {
  109. *pw = pi6 * (atan(sqrt(ww / (one - ww))) - stqr);
  110. return;
  111. }
  112. un = log((*w - eps) / (one - *w));
  113. n3 = n - 3;
  114. if (un >= unl[n3 - 1]) {
  115. if (un <= onept4) {
  116. nc = nc1[n3 - 1];
  117. for (i = 0; i < nc; ++i)
  118. c[i] = c1[i][n3 - 1];
  119. eu3 = exp(poly(c, nc, un));
  120. }
  121. else {
  122. if (un > unh[n3 - 1])
  123. return;
  124. nc = nc2[n3 - 1];
  125. for (i = 0; i < nc; ++i)
  126. c[i] = c2[i][n3 - 1];
  127. un = log(un); /*alog */
  128. eu3 = exp(exp(poly(c, nc, un)));
  129. }
  130. ww = (eu3 + tqr) / (one + eu3);
  131. *pw = pi6 * (atan(sqrt(ww / (one - ww))) - stqr);
  132. return;
  133. }
  134. }
  135. }
  136. *pw = zero;
  137. return;
  138. }
  139. return;
  140. }
  141. /*
  142. * Algorithm AS 181.1 Appl. Statist. (1982) Vol. 31, No. 2
  143. *
  144. * Obtain array A of weights for calculating W
  145. */
  146. void wcoef(double a[], int n, int n2, double *eps, int *ifault)
  147. {
  148. static double c4[2] = { 0.6869, 0.1678 };
  149. static double c5[2] = { 0.6647, 0.2412 };
  150. static double c6[3] = { 0.6431, 0.2806, 0.0875 };
  151. static double rsqrt2 = 0.70710678;
  152. double a1star, a1sq, sastar, an;
  153. int j;
  154. *ifault = 1;
  155. if (n <= 2)
  156. return;
  157. *ifault = 3;
  158. if (n / 2 != n2)
  159. return;
  160. *ifault = 2;
  161. if (n > 2000)
  162. return;
  163. *ifault = 0;
  164. if (n > 6) {
  165. /* Calculate rankits using approximate function Cdhc_nscor2(). (AS177) */
  166. Cdhc_nscor2(a, n, n2, ifault);
  167. for (sastar = 0.0, j = 1; j < n2; ++j)
  168. sastar += a[j] * a[j];
  169. sastar *= 8.0;
  170. an = n;
  171. if (n <= 20)
  172. an--;
  173. a1sq = exp(log(6.0 * an + 7.0) - log(6.0 * an + 13.0)
  174. + 0.5 * (1.0 + (an - 2.0) * log(an + 1.0) - (an - 1.0)
  175. * log(an + 2.0)));
  176. a1star = sastar / (1.0 / a1sq - 2.0);
  177. sastar = sqrt(sastar + 2.0 * a1star);
  178. a[0] = sqrt(a1star) / sastar;
  179. for (j = 1; j < n2; ++j)
  180. a[j] = 2.0 * a[j] / sastar;
  181. }
  182. else {
  183. /* Use exact values for weights */
  184. a[0] = rsqrt2;
  185. if (n != 3) {
  186. if (n - 3 == 3)
  187. for (j = 0; j < 3; ++j)
  188. a[j] = c6[j];
  189. else if (n - 3 == 2)
  190. for (j = 0; j < 2; ++j)
  191. a[j] = c5[j];
  192. else
  193. for (j = 0; j < 2; ++j)
  194. a[j] = c4[j];
  195. /*-
  196. goto (40,50,60), n3
  197. 40 do 45 j = 1,2
  198. 45 a(j) = c4(j)
  199. goto 70
  200. 50 do 55 j = 1,2
  201. 55 a(j) = c5(j)
  202. goto 70
  203. 60 do 65 j = 1,3
  204. 65 a(j) = c6(j)
  205. */
  206. }
  207. }
  208. /* Calculate the minimum possible value of W */
  209. *eps = a[0] * a[0] / (1.0 - 1.0 / (double)n);
  210. return;
  211. }
  212. /*
  213. * Algorithm AS 181.2 Appl. Statist. (1982) Vol. 31, No. 2
  214. *
  215. * Calculates the algebraic polynomial of order nored-1 with array of
  216. * coefficients c. Zero order coefficient is c(1)
  217. */
  218. static double poly(double c[], int nord, double x)
  219. {
  220. double p;
  221. int n2, i, j;
  222. if (nord == 1)
  223. return c[0];
  224. p = x * c[nord - 1];
  225. if (nord != 2) {
  226. n2 = nord - 2;
  227. j = n2;
  228. for (i = 0; i < n2; ++i)
  229. p = (p + c[j--]) * x;
  230. }
  231. return c[0] + p;
  232. }
  233. /*
  234. * AS R63 Appl. Statist. (1986) Vol. 35, No.2
  235. *
  236. * A remark on AS 181
  237. *
  238. * Calculates Sheppard Cdhc_corrected version of W test.
  239. *
  240. * Auxiliary functions required: Cdhc_alnorm = algorithm AS 66, and PPND =
  241. * algorithm AS 111 (or Cdhc_ppnd7 from AS 241).
  242. */
  243. void Cdhc_wgp(double x[], int n, double ssq, double gp, double h, double a[],
  244. int n2, double eps, double w, double u, double p, int *ifault)
  245. {
  246. double zbar, zsd, an1, hh;
  247. zbar = 0.0;
  248. zsd = 1.0;
  249. *ifault = 1;
  250. if (n < 7)
  251. return;
  252. if (gp > 0.0) { /* No Cdhc_correction applied if gp=0. */
  253. an1 = (double)(n - 1);
  254. /* Cdhc_correct ssq and find standardized grouping interval (h) */
  255. ssq = ssq - an1 * gp * gp / 12.0;
  256. h = gp / sqrt(ssq / an1);
  257. *ifault = 4;
  258. if (h > 1.5)
  259. return;
  260. }
  261. wext(x, n, ssq, a, n2, eps, &w, &p, ifault);
  262. if (*ifault != 0)
  263. return;
  264. if (!(p > 0.0 && p < 1.0)) {
  265. u = 5.0 - 10.0 * p;
  266. return;
  267. }
  268. if (gp > 0.0) {
  269. /* Cdhc_correct u for grouping interval (n<=100 and n>100 separately) */
  270. hh = sqrt(h);
  271. if (n <= 100) {
  272. zbar = -h * (1.07457 + hh * (-2.8185 + hh * 1.8898));
  273. zsd = 1.0 + h * (0.50933 + hh * (-0.98305 + hh * 0.7408));
  274. }
  275. else {
  276. zbar = -h * (0.96436 + hh * (-2.1300 + hh * 1.3196));
  277. zsd = 1.0 + h * (0.2579 + h * 0.15225);
  278. }
  279. }
  280. /* ppnd is AS 111 (Beasley and Springer, 1977) */
  281. u = (-ppnd16(p) - zbar) / zsd;
  282. /* Cdhc_alnorm is AS 66 (Hill, 1973) */
  283. p = Cdhc_alnorm(u, 1);
  284. return;
  285. }