fastglmm
Massively scalable generalized linear mixed models
Loading...
Searching...
No Matches
qnorm_R.h
Go to the documentation of this file.
1/*
2 * Mathlib : A C Library of Special Functions
3 * Copyright (C) 2000--2023 The R Core Team
4 * Copyright (C) 1998 Ross Ihaka
5 * based on AS 241 (C) 1988 Royal Statistical Society
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, a copy is available at
19 * https://www.R-project.org/Licenses/
20 *
21 * SYNOPSIS
22 *
23 * double qnorm5(double p, double mu, double sigma,
24 * int lower_tail, int log_p)
25 * {qnorm (..) is synonymous and preferred inside R}
26 *
27 * DESCRIPTION
28 *
29 * Compute the quantile function for the normal distribution.
30 *
31 * The algorithm AS 241 of Wichura is used,
32 * and has been improved for the very extreme tail (and log_p=TRUE)
33 *
34 * REFERENCE
35 *
36 * Wichura, M.J. (1988).
37 * Algorithm AS 241: The Percentage Points of the Normal Distribution.
38 * Applied Statistics, 37, 477-484.
39 *
40 * Maechler, M. (2022). Asymptotic tail formulas for gaussian quantiles;
41 * https://CRAN.R-project.org/package=DPQ/vignettes/qnorm-asymp.pdf
42 */
43
44
45// Define here to avoid depending on R
46
47#include <cmath>
48
49namespace glm {
50
51#ifndef ML_NEGINF
52#define ML_NEGINF std::numeric_limits<double>::min()
53#endif
54
55
56#ifndef ML_POSINF
57#define ML_POSINF std::numeric_limits<double>::max()
58#endif
59
60#ifndef NAN
61#define NAN std::numeric_limits<double>::quiet_NaN()
62#endif
63
64
65#ifndef R_D_Lval
66#define R_D_Lval(p) (lower_tail ? (p) : (0.5 - (p) + 0.5)) /* p */
67#endif
68
69
70
71#ifndef R_DT_qIv
72#define R_DT_qIv(p) (log_p ? (lower_tail ? exp(p) : - expm1(p)) \
73 : R_D_Lval(p))
74#endif
75
76
77/* Do the boundaries exactly for q*() functions :
78 * Often _LEFT_ = ML_NEGINF , and very often _RIGHT_ = ML_POSINF;
79 *
80 * R_Q_P01_boundaries(p, _LEFT_, _RIGHT_) :<==>
81 *
82 * R_Q_P01_check(p);
83 * if (p == R_DT_0) return _LEFT_ ;
84 * if (p == R_DT_1) return _RIGHT_;
85 *
86 * the following implementation should be more efficient (less tests):
87 */
88#ifndef R_Q_P01_boundaries
89#define R_Q_P01_boundaries(p, _LEFT_, _RIGHT_) \
90 if (log_p) { \
91 if(p > 0) \
92 NAN; \
93 if(p == 0) /* upper bound*/ \
94 return lower_tail ? _RIGHT_ : _LEFT_; \
95 if(p == ML_NEGINF) \
96 return lower_tail ? _LEFT_ : _RIGHT_; \
97 } \
98 else { /* !log_p */ \
99 if(p < 0 || p > 1) \
100 NAN; \
101 if(p == 0) \
102 return lower_tail ? _LEFT_ : _RIGHT_; \
103 if(p == 1) \
104 return lower_tail ? _RIGHT_ : _LEFT_; \
105 }
106#endif
107
108static double qnorm(double p, double mu, double sigma, int lower_tail, int log_p){
109 double p_, q, r, val;
110
111// #ifdef IEEE_754
112 if (std::isnan(p) || std::isnan(mu) || std::isnan(sigma))
113 return p + mu + sigma;
114// #endif
116
117 if(sigma < 0) NAN;
118 if(sigma == 0) return mu;
119
120 p_ = R_DT_qIv(p);/* real lower_tail prob. p */
121 q = p_ - 0.5;
122
123// #ifdef DEBUG_qnorm
124// REprintf("qnorm(p=%10.7g, m=%g, s=%g, l.t.= %d, log= %d): q = %g\n",
125// p,mu,sigma, lower_tail, log_p, q);
126// #endif
127
128
129/*-- use AS 241 --- */
130/* double ppnd16_(double *p, long *ifault)*/
131/* ALGORITHM AS241 APPL. STATIST. (1988) VOL. 37, NO. 3
132
133 Produces the normal deviate Z corresponding to a given lower
134 tail area of P; Z is accurate to about 1 part in 10**16.
135
136 (original fortran code used PARAMETER(..) for the coefficients
137 and provided hash codes for checking them...)
138*/
139 if (fabs(q) <= .425) {/* |p~ - 0.5| <= .425 <==> 0.075 <= p~ <= 0.925 */
140 r = .180625 - q * q; // = .425^2 - q^2 >= 0
141 val =
142 q * (((((((r * 2509.0809287301226727 +
143 33430.575583588128105) * r + 67265.770927008700853) * r +
144 45921.953931549871457) * r + 13731.693765509461125) * r +
145 1971.5909503065514427) * r + 133.14166789178437745) * r +
146 3.387132872796366608)
147 / (((((((r * 5226.495278852854561 +
148 28729.085735721942674) * r + 39307.89580009271061) * r +
149 21213.794301586595867) * r + 5394.1960214247511077) * r +
150 687.1870074920579083) * r + 42.313330701600911252) * r + 1.);
151 }
152 else { /* closer than 0.075 from {0,1} boundary :
153 * r := log(p~); p~ = min(p, 1-p) < 0.075 : */
154 double lp;
155 if(log_p && ((lower_tail && q <= 0) || (!lower_tail && q > 0))) {
156 lp = p;
157 } else {
158 lp = log( (q > 0) ? R_DT_CIv(p) /* 1-p */ : p_ /* = R_DT_Iv(p) ^= p */);
159 }
160 // r = sqrt( - log(min(p,1-p)) ) <==> min(p, 1-p) = exp( - r^2 ) :
161 r = sqrt(-lp);
162#ifdef DEBUG_qnorm
163 REprintf("\t close to 0 or 1: r = %7g\n", r);
164#endif
165 if (r <= 5.) { /* <==> min(p,1-p) >= exp(-25) ~= 1.3888e-11 */
166 r += -1.6;
167 val = (((((((r * 7.7454501427834140764e-4 +
168 .0227238449892691845833) * r + .24178072517745061177) *
169 r + 1.27045825245236838258) * r +
170 3.64784832476320460504) * r + 5.7694972214606914055) *
171 r + 4.6303378461565452959) * r +
172 1.42343711074968357734)
173 / (((((((r *
174 1.05075007164441684324e-9 + 5.475938084995344946e-4) *
175 r + .0151986665636164571966) * r +
176 .14810397642748007459) * r + .68976733498510000455) *
177 r + 1.6763848301838038494) * r +
178 2.05319162663775882187) * r + 1.);
179 }
180 else if(r <= 27) { /* p is very close to 0 or 1: r in (5, 27] :
181 * r > 5 <==> min(p,1-p) < exp(-25) = 1.3888..e-11
182 * r <= 27 <==> min(p,1-p) >= exp(-27^2) = exp(-729) ~= 2.507972e-317
183 * i.e., we are just barely in the range where min(p, 1-p) has not yet underflowed to zero.
184 */
185 // Wichura, p.478: minimax rational approx R_3(t) is for 5 <= t <= 27 (t :== r)
186 r += -5.;
187 val = (((((((r * 2.01033439929228813265e-7 +
188 2.71155556874348757815e-5) * r +
189 .0012426609473880784386) * r + .026532189526576123093) *
190 r + .29656057182850489123) * r +
191 1.7848265399172913358) * r + 5.4637849111641143699) *
192 r + 6.6579046435011037772)
193 / (((((((r *
194 2.04426310338993978564e-15 + 1.4215117583164458887e-7)*
195 r + 1.8463183175100546818e-5) * r +
196 7.868691311456132591e-4) * r + .0148753612908506148525)
197 * r + .13692988092273580531) * r +
198 .59983220655588793769) * r + 1.);
199 }
200 else { // r > 27: p is *really* close to 0 or 1 .. practically only when log_p =TRUE
201 if(r >= 6.4e8) { // p is *very extremely* close to 0 or 1
202 // Using the asymptotical formula ("0-th order"): qn = sqrt(2*s)
203 val = r * M_SQRT2;
204 } else {
205 double s2 = -ldexp(lp, 1), // = -2*lp = 2s
206 x2 = s2 - log(M_2PI * s2); // = xs_1
207 // if(r >= 36000.) # <==> s >= 36000^2 use x2 = xs_1 above
208 if(r < 36000.) {
209 x2 = s2 - log(M_2PI * x2) - 2./(2. + x2); // == xs_2
210 if(r < 840.) { // 27 < r < 840
211 x2 = s2 - log(M_2PI * x2) + 2*log1p(- (1 - 1/(4 + x2))/(2. + x2)); // == xs_3
212 if(r < 109.) { // 27 < r < 109
213 x2 = s2 - log(M_2PI * x2) +
214 2*log1p(- (1 - (1 - 5/(6 + x2))/(4. + x2))/(2. + x2)); // == xs_4
215 if(r < 55.) { // 27 < r < 55
216 x2 = s2 - log(M_2PI * x2) +
217 2*log1p(- (1 - (1 - (5 - 9/(8. + x2))/(6. + x2))/(4. + x2))/(2. + x2)); // == xs_5
218 }
219 }
220 }
221 }
222 val = sqrt(x2);
223 }
224 }
225 if(q < 0.0)
226 val = -val;
227 }
228 return mu + sigma * val;
229}
230
231};
Definition qnorm_R.h:49
#define R_Q_P01_boundaries(p, _LEFT_, _RIGHT_)
Definition qnorm_R.h:89
#define R_DT_qIv(p)
Definition qnorm_R.h:72
#define NAN
Definition qnorm_R.h:61
#define ML_POSINF
Definition qnorm_R.h:57
#define ML_NEGINF
Definition qnorm_R.h:52