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