-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathqtukey.c
190 lines (163 loc) · 5.5 KB
/
qtukey.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*
* Mathlib : A C Library of Special Functions
* Copyright (C) 1998 Ross Ihaka
* Copyright (C) 2000--2005 The R Core Team
* based in part on AS70 (C) 1974 Royal Statistical Society
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* http://www.r-project.org/Licenses/
*
* SYNOPSIS
*
* #include <Rmath.h>
* double qtukey(p, rr, cc, df, lower_tail, log_p);
*
* DESCRIPTION
*
* Computes the quantiles of the maximum of rr studentized
* ranges, each based on cc means and with df degrees of freedom
* for the standard error, is less than q.
*
* The algorithm is based on that of the reference.
*
* REFERENCE
*
* Copenhaver, Margaret Diponzio & Holland, Burt S.
* Multiple comparisons of simple effects in
* the two-way analysis of variance with fixed effects.
* Journal of Statistical Computation and Simulation,
* Vol.30, pp.1-15, 1988.
*/
#include "nmath.h"
#include "dpq.h"
/* qinv() :
* this function finds percentage point of the studentized range
* which is used as initial estimate for the secant method.
* function is adapted from portion of algorithm as 70
* from applied statistics (1974) ,vol. 23, no. 1
* by odeh, r. e. and evans, j. o.
*
* p = percentage point
* c = no. of columns or treatments
* v = degrees of freedom
* qinv = returned initial estimate
*
* vmax is cutoff above which degrees of freedom
* is treated as infinity.
*/
static double qinv(double p, double c, double v)
{
const static double p0 = 0.322232421088;
const static double q0 = 0.993484626060e-01;
const static double p1 = -1.0;
const static double q1 = 0.588581570495;
const static double p2 = -0.342242088547;
const static double q2 = 0.531103462366;
const static double p3 = -0.204231210125;
const static double q3 = 0.103537752850;
const static double p4 = -0.453642210148e-04;
const static double q4 = 0.38560700634e-02;
const static double c1 = 0.8832;
const static double c2 = 0.2368;
const static double c3 = 1.214;
const static double c4 = 1.208;
const static double c5 = 1.4142;
const static double vmax = 120.0;
double ps, q, t, yi;
ps = 0.5 - 0.5 * p;
yi = sqrt (log (1.0 / (ps * ps)));
t = yi + (((( yi * p4 + p3) * yi + p2) * yi + p1) * yi + p0)
/ (((( yi * q4 + q3) * yi + q2) * yi + q1) * yi + q0);
if (v < vmax) t += (t * t * t + t) / v / 4.0;
q = c1 - c2 * t;
if (v < vmax) q += -c3 / v + c4 * t / v;
return t * (q * log (c - 1.0) + c5);
}
/*
* Copenhaver, Margaret Diponzio & Holland, Burt S.
* Multiple comparisons of simple effects in
* the two-way analysis of variance with fixed effects.
* Journal of Statistical Computation and Simulation,
* Vol.30, pp.1-15, 1988.
*
* Uses the secant method to find critical values.
*
* p = confidence level (1 - alpha)
* rr = no. of rows or groups
* cc = no. of columns or treatments
* df = degrees of freedom of error term
*
* ir(1) = error flag = 1 if wprob probability > 1
* ir(2) = error flag = 1 if ptukey probability > 1
* ir(3) = error flag = 1 if convergence not reached in 50 iterations
* = 2 if df < 2
*
* qtukey = returned critical value
*
* If the difference between successive iterates is less than eps,
* the search is terminated
*/
double qtukey(double p, double rr, double cc, double df,
int lower_tail, int log_p)
{
const static double eps = 0.0001;
const int maxiter = 50;
double ans = 0.0, valx0, valx1, x0, x1, xabs;
int iter;
#ifdef IEEE_754
if (ISNAN(p) || ISNAN(rr) || ISNAN(cc) || ISNAN(df)) {
ML_ERROR(ME_DOMAIN, "qtukey");
return p + rr + cc + df;
}
#endif
/* df must be > 1 ; there must be at least two values */
if (df < 2 || rr < 1 || cc < 2) ML_ERR_return_NAN;
R_Q_P01_boundaries(p, 0, ML_POSINF);
p = R_DT_qIv(p); /* lower_tail,non-log "p" */
/* Initial value */
x0 = qinv(p, cc, df);
/* Find prob(value < x0) */
valx0 = ptukey(x0, rr, cc, df, /*LOWER*/TRUE, /*LOG_P*/FALSE) - p;
/* Find the second iterate and prob(value < x1). */
/* If the first iterate has probability value */
/* exceeding p then second iterate is 1 less than */
/* first iterate; otherwise it is 1 greater. */
if (valx0 > 0.0)
x1 = fmax2(0.0, x0 - 1.0);
else
x1 = x0 + 1.0;
valx1 = ptukey(x1, rr, cc, df, /*LOWER*/TRUE, /*LOG_P*/FALSE) - p;
/* Find new iterate */
for(iter=1 ; iter < maxiter ; iter++) {
ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0));
valx0 = valx1;
/* New iterate must be >= 0 */
x0 = x1;
if (ans < 0.0) {
ans = 0.0;
valx1 = -p;
}
/* Find prob(value < new iterate) */
valx1 = ptukey(ans, rr, cc, df, /*LOWER*/TRUE, /*LOG_P*/FALSE) - p;
x1 = ans;
/* If the difference between two successive */
/* iterates is less than eps, stop */
xabs = fabs(x1 - x0);
if (xabs < eps)
return ans;
}
/* The process did not converge in 'maxiter' iterations */
ML_ERROR(ME_NOCONV, "qtukey");
return ans;
}