/src/r-source/src/nmath/pnt.c
Line | Count | Source |
1 | | /* |
2 | | * Mathlib : A C Library of Special Functions |
3 | | * Copyright (C) 1998-2015 The R Core Team |
4 | | * based on AS243 (C) 1989 Royal Statistical Society |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, a copy is available at |
18 | | * https://www.R-project.org/Licenses/ |
19 | | */ |
20 | | |
21 | | /* Algorithm AS 243 Lenth,R.V. (1989). Appl. Statist., Vol.38, 185-189. |
22 | | * ---------------- |
23 | | * Cumulative probability at t of the non-central t-distribution |
24 | | * with df degrees of freedom (may be fractional) and non-centrality |
25 | | * parameter delta. |
26 | | * |
27 | | * NOTE |
28 | | * |
29 | | * Requires the following auxiliary routines: |
30 | | * |
31 | | * lgammafn(x) - log gamma function |
32 | | * pbeta(x, a, b) - incomplete beta function |
33 | | * pnorm(x) - normal distribution function |
34 | | * |
35 | | * CONSTANTS |
36 | | * |
37 | | * M_SQRT_2dPI = 1/ {gamma(1.5) * sqrt(2)} = sqrt(2 / pi) |
38 | | * M_LN_SQRT_PI = ln(sqrt(pi)) = ln(pi)/2 |
39 | | */ |
40 | | |
41 | | #include "nmath.h" |
42 | | #include "dpq.h" |
43 | | |
44 | | /*----------- DEBUGGING ------------- |
45 | | * |
46 | | * make CFLAGS='-DDEBUG_pnt -g' |
47 | | |
48 | | * -- Feb.3, 1999; M.Maechler: |
49 | | - For 't > ncp > 20' (or so) the result is completely WRONG! <== no longer true |
50 | | - but for ncp > 100 |
51 | | */ |
52 | | |
53 | | double pnt(double t, double df, double ncp, int lower_tail, int log_p) |
54 | 0 | { |
55 | 0 | double albeta, a, b, del, errbd, lambda, rxb, tt, x; |
56 | 0 | LDOUBLE geven, godd, p, q, s, tnc, xeven, xodd; |
57 | 0 | int it, negdel; |
58 | | |
59 | | /* note - itrmax and errmax may be changed to suit one's needs. */ |
60 | |
|
61 | 0 | const int itrmax = 1000; |
62 | 0 | const static double errmax = 1.e-12; |
63 | |
|
64 | 0 | if (df <= 0.0) ML_WARN_return_NAN; |
65 | 0 | if(ncp == 0.0) return pt(t, df, lower_tail, log_p); |
66 | | |
67 | 0 | if(!R_FINITE(t)) |
68 | 0 | return (t < 0) ? R_DT_0 : R_DT_1; |
69 | 0 | if (t >= 0.) { |
70 | 0 | negdel = FALSE; tt = t; del = ncp; |
71 | 0 | } |
72 | 0 | else { |
73 | | /* We deal quickly with left tail if extreme, |
74 | | since pt(q, df, ncp) <= pt(0, df, ncp) = \Phi(-ncp) */ |
75 | 0 | if (ncp > 40 && (!log_p || !lower_tail)) return R_DT_0; |
76 | 0 | negdel = TRUE; tt = -t; del = -ncp; |
77 | 0 | } |
78 | | |
79 | 0 | if (df > 4e5 || del*del > 2*M_LN2*(-(DBL_MIN_EXP))) { |
80 | | /*-- 2nd part: if del > 37.62, then p=0 below |
81 | | FIXME: test should depend on `df', `tt' AND `del' ! */ |
82 | | /* Approx. from Abramowitz & Stegun 26.7.10 (p.949) */ |
83 | 0 | s = 1./(4.*df); |
84 | |
|
85 | 0 | return pnorm((double)(tt*(1. - s)), del, |
86 | 0 | sqrt((double) (1. + tt*tt*2.*s)), |
87 | 0 | lower_tail != negdel, log_p); |
88 | 0 | } |
89 | | |
90 | | /* initialize twin series */ |
91 | | /* Guenther, J. (1978). Statist. Computn. Simuln. vol.6, 199. */ |
92 | | |
93 | 0 | x = t * t; |
94 | 0 | rxb = df/(x + df);/* := (1 - x) {x below} -- but more accurately */ |
95 | 0 | x = x / (x + df);/* in [0,1) */ |
96 | | #ifdef DEBUG_pnt |
97 | | REprintf("pnt(t=%7g, df=%7g, ncp=%7g) ==> x= %10g:",t,df,ncp, x); |
98 | | #endif |
99 | 0 | if (x > 0.) {/* <==> t != 0 */ |
100 | 0 | lambda = del * del; |
101 | 0 | p = .5 * exp(-.5 * lambda); |
102 | | #ifdef DEBUG_pnt |
103 | | REprintf("\t p=%10Lg\n",p); |
104 | | #endif |
105 | 0 | if(p == 0.) { /* underflow! */ |
106 | | |
107 | | /*========== really use an other algorithm for this case !!! */ |
108 | 0 | ML_WARNING(ME_UNDERFLOW, "pnt"); |
109 | 0 | ML_WARNING(ME_RANGE, "pnt"); /* |ncp| too large */ |
110 | 0 | return R_DT_0; |
111 | 0 | } |
112 | | #ifdef DEBUG_pnt |
113 | | REprintf("it 1e5*(godd, geven)| p q s" |
114 | | /* 1.3 1..4..7.9 1..4..7.9|1..4..7.901 1..4..7.901 1..4..7.901 */ |
115 | | " pnt(*) errbd\n"); |
116 | | /* 1..4..7..0..34 1..4..7.9*/ |
117 | | #endif |
118 | 0 | q = M_SQRT_2dPI * p * del; |
119 | 0 | s = .5 - p; |
120 | | /* s = 0.5 - p = 0.5*(1 - exp(-.5 L)) = -0.5*expm1(-.5 L)) */ |
121 | 0 | if(s < 1e-7) |
122 | 0 | s = -0.5 * expm1(-0.5 * lambda); |
123 | 0 | a = .5; |
124 | 0 | b = .5 * df; |
125 | | /* rxb = (1 - x) ^ b [ ~= 1 - b*x for tiny x --> see 'xeven' below] |
126 | | * where '(1 - x)' =: rxb {accurately!} above */ |
127 | 0 | rxb = pow(rxb, b); |
128 | 0 | albeta = M_LN_SQRT_PI + lgammafn(b) - lgammafn(.5 + b); |
129 | 0 | xodd = pbeta(x, a, b, /*lower*/TRUE, /*log_p*/FALSE); |
130 | 0 | godd = 2. * rxb * exp(a * log(x) - albeta); |
131 | 0 | tnc = b * x; |
132 | 0 | xeven = (tnc < DBL_EPSILON) ? tnc : 1. - rxb; |
133 | 0 | geven = tnc * rxb; |
134 | 0 | tnc = p * xodd + q * xeven; |
135 | | |
136 | | /* repeat until convergence or iteration limit */ |
137 | 0 | for(it = 1; it <= itrmax; it++) { |
138 | 0 | a += 1.; |
139 | 0 | xodd -= godd; |
140 | 0 | xeven -= geven; |
141 | 0 | godd *= x * (a + b - 1.) / a; |
142 | 0 | geven *= x * (a + b - .5) / (a + .5); |
143 | 0 | p *= lambda / (2 * it); |
144 | 0 | q *= lambda / (2 * it + 1); |
145 | 0 | tnc += p * xodd + q * xeven; |
146 | 0 | s -= p; |
147 | | /* R 2.4.0 added test for rounding error here. */ |
148 | 0 | if(s < -1.e-10) { /* happens e.g. for (t,df,ncp)=(40,10,38.5), after 799 it.*/ |
149 | 0 | ML_WARNING(ME_PRECISION, "pnt"); |
150 | | #ifdef DEBUG_pnt |
151 | | REprintf("s = %#14.7Lg < 0 !!! ---> non-convergence!!\n", s); |
152 | | #endif |
153 | 0 | goto finis; |
154 | 0 | } |
155 | 0 | if(s <= 0 && it > 1) goto finis; |
156 | 0 | errbd = (double)(2. * s * (xodd - godd)); |
157 | | #ifdef DEBUG_pnt |
158 | | REprintf("%3d %#9.4g %#9.4g|%#11.4Lg %#11.4Lg %#11.4Lg %#14.10Lg %#9.4g\n", |
159 | | it, 1e5*(double)godd, 1e5*(double)geven, p, q, s, tnc, errbd); |
160 | | #endif |
161 | 0 | if(fabs(errbd) < errmax) goto finis;/*convergence*/ |
162 | 0 | } |
163 | | /* non-convergence:*/ |
164 | 0 | ML_WARNING(ME_NOCONV, "pnt"); |
165 | 0 | } |
166 | 0 | else { /* x = t = 0 */ |
167 | 0 | tnc = 0.; |
168 | 0 | } |
169 | 0 | finis: |
170 | 0 | tnc += pnorm(- del, 0., 1., /*lower*/TRUE, /*log_p*/FALSE); |
171 | |
|
172 | 0 | lower_tail = lower_tail != negdel; /* xor */ |
173 | 0 | if(tnc > 1 - 1e-10 && lower_tail) |
174 | 0 | ML_WARNING(ME_PRECISION, "pnt{final}"); |
175 | |
|
176 | 0 | return R_DT_val(fmin2((double)tnc, 1.) /* Precaution */); |
177 | 0 | } |