1 module pnt; 2 3 import rmathd.common; 4 import rmathd.t; 5 import rmathd.normal; 6 import rmathd.beta; 7 import rmathd.chisq; 8 9 import std.stdio: writeln; 10 11 12 /* 13 ** 14 ** dmd pnt.d common.d t.d normal.d beta.d chisq.d && ./pnt 15 */ 16 17 18 T pnt(T)(T t, T df, T ncp, int lower_tail, int log_p) 19 { 20 T albeta, a, b, del, errbd, lambda, rxb, tt, x; 21 real geven, godd, p, q, s, tnc, xeven, xodd; 22 int it, negdel; 23 24 /* note - itrmax and errmax may be changed to suit one's needs. */ 25 26 const int itrmax = 1000; 27 const static T errmax = 1.0e-12; 28 29 if (df <= 0.0) 30 return T.nan; 31 if(ncp == 0.0) 32 return pt!T(t, df, lower_tail, log_p); 33 34 if(!isFinite(t)) 35 return (t < 0) ? R_DT_0!T(lower_tail, log_p) : R_DT_1!T(lower_tail, log_p); 36 if (t >= 0.) { 37 negdel = 0; tt = t; del = ncp; 38 } else { 39 /* We deal quickly with left tail if extreme, 40 since pt(q, df, ncp) <= pt(0, df, ncp) = \Phi(-ncp) */ 41 if (ncp > 40 && (!log_p || !lower_tail)) 42 return R_DT_0!T(lower_tail, log_p); 43 negdel = 1; tt = -t; del = -ncp; 44 } 45 46 if (df > 4e5 || del*del > 2*M_LN2*(-DBL_MIN_EXP)) { 47 /*-- 2nd part: if del > 37.62, then p=0 below 48 FIXME: test should depend on `df', `tt' AND `del' ! */ 49 /* Approx. from Abramowitz & Stegun 26.7.10 (p.949) */ 50 s = 1./(4.*df); 51 52 return pnorm!T(cast(T)(tt*(1. - s)), del, 53 sqrt(cast(T) (1. + tt*tt*2.*s)), 54 lower_tail != negdel, log_p); 55 } 56 57 /* initialize twin series */ 58 /* Guenther, J. (1978). Statist. Computn. Simuln. vol.6, 199. */ 59 60 x = t * t; 61 rxb = df/(x + df);/* := (1 - x) {x below} -- but more accurately */ 62 x = x / (x + df);/* in [0,1) */ 63 //#ifdef DEBUG_pnt 64 // REprintf("pnt(t=%7g, df=%7g, ncp=%7g) ==> x= %10g:",t,df,ncp, x); 65 //#endif 66 if (x > 0.) {/* <==> t != 0 */ 67 lambda = del * del; 68 p = .5 * exp(-.5 * lambda); 69 //#ifdef DEBUG_pnt 70 // REprintf("\t p=%10Lg\n",p); 71 //#endif 72 if(p == 0.) { /* underflow! */ 73 74 /*========== really use an other algorithm for this case !!! */ 75 //ML_ERROR(ME_UNDERFLOW, "pnt"); 76 //ML_ERROR(ME_RANGE, "pnt"); /* |ncp| too large */ 77 //assert(0, "Underflow pnt"); 78 //assert(0, "Range pnt"); 79 return R_DT_0!T(lower_tail, log_p); 80 } 81 //#ifdef DEBUG_pnt 82 // REprintf("it 1e5*(godd, geven)| p q s" 83 // /* 1.3 1..4..7.9 1..4..7.9|1..4..7.901 1..4..7.901 1..4..7.901 */ 84 // " pnt(*) errbd\n"); 85 // /* 1..4..7..0..34 1..4..7.9*/ 86 //#endif 87 q = M_SQRT_2dPI * p * del; 88 s = .5 - p; 89 /* s = 0.5 - p = 0.5*(1 - exp(-.5 L)) = -0.5*expm1(-.5 L)) */ 90 if(s < 1e-7) 91 s = -0.5 * expm1(-0.5 * lambda); 92 a = .5; 93 b = .5 * df; 94 /* rxb = (1 - x) ^ b [ ~= 1 - b*x for tiny x --> see 'xeven' below] 95 * where '(1 - x)' =: rxb {accurately!} above */ 96 rxb = pow(rxb, b); 97 albeta = M_LN_SQRT_PI + lgammafn!T(b) - lgammafn!T(.5 + b); 98 xodd = pbeta!T(x, a, b, /*lower*/1, /*log_p*/0); 99 godd = 2. * rxb * exp(a * log(x) - albeta); 100 tnc = b * x; 101 xeven = (tnc < DBL_EPSILON) ? tnc : 1. - rxb; 102 geven = tnc * rxb; 103 tnc = p * xodd + q * xeven; 104 105 /* repeat until convergence or iteration limit */ 106 for(it = 1; it <= itrmax; it++) { 107 a += 1.; 108 xodd -= godd; 109 xeven -= geven; 110 godd *= x * (a + b - 1.) / a; 111 geven *= x * (a + b - .5) / (a + .5); 112 p *= lambda / (2 * it); 113 q *= lambda / (2 * it + 1); 114 tnc += p * xodd + q * xeven; 115 s -= p; 116 /* R 2.4.0 added test for rounding error here. */ 117 if(s < -1.0e-10) { /* happens e.g. for (t,df,ncp)=(40,10,38.5), after 799 it.*/ 118 119 //ML_ERROR(ME_PRECISION, "pnt"); 120 //assert(0, "Precision pnt"); 121 //#ifdef DEBUG_pnt 122 // REprintf("s = %#14.7Lg < 0 !!! ---> non-convergence!!\n", s); 123 //#endif 124 goto finis; 125 } 126 if(s <= 0 && it > 1) 127 goto finis; 128 errbd = cast(T)(2. * s * (xodd - godd)); 129 //#ifdef DEBUG_pnt 130 // REprintf("%3d %#9.4g %#9.4g|%#11.4Lg %#11.4Lg %#11.4Lg %#14.10Lg %#9.4g\n", 131 // it, 1e5*(double)godd, 1e5*(double)geven, p, q, s, tnc, errbd); 132 //#endif 133 writeln("for loop, tnc: ", tnc, ", s: ", s, ", p: ", p); 134 if(fabs(errbd) < errmax) 135 goto finis;/*convergence*/ 136 } 137 /* non-convergence:*/ 138 //ML_ERROR(ME_NOCONV, "pnt"); 139 assert(0, "Non-Convergence pnt"); 140 } else { /* x = t = 0 */ 141 tnc = 0.; 142 } 143 finis: 144 tnc += pnorm!T(- del, 0., 1., /*lower*/1, /*log_p*/0); 145 146 writeln("tnc after finis: ", tnc); 147 148 lower_tail = lower_tail != negdel; /* xor */ 149 if(tnc > 1 - 1e-10 && lower_tail) 150 assert(0, "Precision pnt{final}"); 151 //ML_ERROR(ME_PRECISION, "pnt{final}"); 152 153 return R_DT_val!T(fmin2!T(cast(T)tnc, 1.), lower_tail, log_p); 154 } 155 156 157 void test_pnt() 158 { 159 import std.stdio: writeln; 160 writeln("pnt: ", pnt(3., 40., 2., 1, 0)); 161 writeln("pnt: ", pnt(-3., 40., 2., 1, 0)); 162 } 163