1 module rmathd.beta;
2 
3 public import rmathd.common;
4 public import rmathd.toms708;
5 
6 /*
7 ** dmd beta.d common.d && ./beta
8 */
9 
10 T lbeta(T: double)(T a, T b)
11 {
12     T corr, p, q;
13 
14     if(isNaN(a) || isNaN(b))
15 	    return a + b;
16 
17     p = q = a;
18     if(b < p) p = b;/* := min(a,b) */
19     if(b > q) q = b;/* := max(a,b) */
20 
21     /* both arguments must be >= 0 */
22     if (p < 0)
23 	    return T.nan;
24     else if (p == 0) {
25 	return T.infinity;
26     }
27     else if (!isFinite(q)) { /* q == +Inf */
28 	return -T.infinity;
29     }
30 
31     if (p >= 10) {
32 	    /* p and q are big. */
33 	    corr = lgammacor!T(p) + lgammacor!T(q) - lgammacor!T(p + q);
34 	    return log(q) * -0.5 + M_LN_SQRT_2PI + corr + (p - 0.5) * log(p / (p + q)) + q * log1p(-p / (p + q));
35     } else if (q >= 10) {
36 	    /* p is small, but q is big. */
37 	    corr = lgammacor!T(q) - lgammacor!T(p + q);
38 	    return lgammafn!T(p) + corr + p - p * log(p + q)
39 	    	+ (q - 0.5) * log1p(-p / (p + q));
40     }
41     else {
42 	/* p and q are small: p <= q < 10. */
43 	/* R change for very small args */
44 	if (p < 1e-306)
45 		return lgamma!T(p) + (lgamma!T(q) - lgamma!T(p + q));
46 	else return log(gammafn!T(p)*(gammafn!T(q)/gammafn!T(p + q)));
47     }
48 }
49 
50 
51 T beta(T: double)(T a, T b)
52 {
53     //#ifdef NOMORE_FOR_THREADS
54     static T xmin, xmax = 0;/*-> typically = 171.61447887 for IEEE */
55     static T lnsml = 0;/*-> typically = -708.3964185 */
56 
57     if (xmax == 0) {
58 	    gammalims!T(&xmin, &xmax);
59 	    lnsml = log(d1mach!T(1));
60     }
61     //#else
62     ///* For IEEE double precision DBL_EPSILON = 2^-52 = 2.220446049250313e-16 :
63     // *   xmin, xmax : see ./gammalims.c
64     // *   lnsml = log(DBL_MIN) = log(2 ^ -1022) = -1022 * log(2)
65     //*/
66     //# define xmin  -170.5674972726612
67     //# define xmax   171.61447887182298
68     //# define lnsml -708.39641853226412
69     //#endif
70 
71     /* NaNs propagated correctly */
72     if(isNaN(a) || isNaN(b))
73     	return a + b;
74 
75     if (a < 0 || b < 0)
76 	    return T.nan;
77     else if (a == 0 || b == 0)
78 	    return T.infinity;
79     else if (!isFinite(a) || !isFinite(b))
80 	    return 0;
81 
82     if (a + b < xmax) {/* ~= 171.61 for IEEE */
83         //	return gammafn(a) * gammafn(b) / gammafn(a+b);
84 	    /* All the terms are positive, and all can be large for large
85 	       or small arguments.  They are never much less than one.
86 	       gammafn(x) can still overflow for x ~ 1e-308,
87 	       but the result would too.
88 	    */
89 	    return (1/gammafn!T(a + b)) * gammafn!T(a) * gammafn!T(b);
90     } else {
91 	    T val = lbeta!T(a, b);
92         // underflow to 0 is not harmful per se;  exp(-999) also gives no warning
93 	    if (val < lnsml) {
94 	        /* a and/or b so big that beta underflows */
95 	        //ML_ERROR(ME_UNDERFLOW, "beta");
96 	        /* return ML_UNDERFLOW; pointless giving incorrect value */
97 	    }
98 	    return exp(val);
99     }
100 }
101 
102 
103 T dbeta(T: double)(T x, T a, T b, int give_log)
104 {
105 	mixin R_D__0!give_log;
106     /* NaNs propagated correctly */
107     if (isNaN(x) || isNaN(a) || isNaN(b))
108     	return x + a + b;
109 
110     if (a < 0 || b < 0)
111     	return T.nan;
112     if (x < 0 || x > 1)
113     	return(R_D__0);
114 
115     // limit cases for (a,b), leading to point masses
116     if(a == 0 || b == 0 || !isFinite(a) || !isFinite(b)) {
117 	    if(a == 0 && b == 0) { // point mass 1/2 at each of {0,1} :
118 	        if (x == 0 || x == 1) 
119 	            return T.infinity;
120 	        else 
121 	            return R_D__0;
122 	    }
123 	    if (a == 0 || a/b == 0) { // point mass 1 at 0
124 	        if (x == 0) return T.infinity; else return R_D__0;
125 	    }
126 	    if (b == 0 || b/a == 0) { // point mass 1 at 1
127 	        if (x == 1) return T.infinity; else return R_D__0;
128 	    }
129 	    // else, remaining case:  a = b = Inf : point mass 1 at 1/2
130 	    if (x == 0.5) return T.infinity; else return R_D__0;
131     }
132 
133     if (x == 0) {
134 	if(a > 1)
135 		return R_D__0;
136 	if(a < 1)
137 		return T.infinity;
138 	/* a == 1 : */ return R_D_val!T(b, give_log);
139     }
140     if (x == 1) {
141 	if(b > 1)
142 		return R_D__0;
143 	if(b < 1)
144 		return(T.infinity);
145 	/* b == 1 : */ return R_D_val!T(a, give_log);
146     }
147 
148     T lval;
149     if (a <= 2 || b <= 2)
150 	    lval = (a - 1)*log(x) + (b - 1)*log1p(-x) - lbeta!T(a, b);
151     else
152 	    lval = log(a + b - 1) + dbinom_raw!T(a - 1, a + b - 2, x, 1 - x, 1);
153 
154     return R_D_exp!T(lval, give_log);
155 }
156 
157 
158 T pbeta_raw(T)(T x, T a, T b, int lower_tail, int log_p)
159 {
160     // treat limit cases correctly here:
161     if(a == 0 || b == 0 || !isFinite(a) || !isFinite(b)) {
162 	// NB:  0 < x < 1 :
163 	if(a == 0 && b == 0) // point mass 1/2 at each of {0,1} :
164 	    return (log_p ? -M_LN2 : 0.5);
165 	if (a == 0 || a/b == 0) // point mass 1 at 0 ==> P(X <= x) = 1, all x > 0
166 	    return R_DT_1!T(lower_tail, log_p);
167 	if (b == 0 || b/a == 0) // point mass 1 at 1 ==> P(X <= x) = 0, all x < 1
168 	    return R_DT_0!T(lower_tail, log_p);
169 	// else, remaining case:  a = b = Inf : point mass 1 at 1/2
170 	if (x < 0.5)
171 		return R_DT_0!T(lower_tail, log_p);
172 	else
173 		return R_DT_1!T(lower_tail, log_p);
174     }
175     // Now:  0 < a < Inf;  0 < b < Inf
176 
177     T x1 = 0.5 - x + 0.5, w, wc;
178     int ierr;
179     //====
180     bratio!T(a, b, x, x1, &w, &wc, &ierr, log_p); /* -> ./toms708.c */
181     //====
182     // ierr in {10,14} <==> bgrat() error code ierr-10 in 1:4; for 1 and 4, warned *there*
183     //if(ierr && ierr != 11 && ierr != 14)
184 	//    MATHLIB_WARNING4(_("pbeta_raw(%g, a=%g, b=%g, ..) -> bratio() gave error code %d"), x, a,b, ierr);
185     return lower_tail ? w : wc;
186 } /* pbeta_raw() */
187 
188 T pbeta(T: double)(T x, T a, T b, int lower_tail, int log_p)
189 {
190     if (isNaN(x) || isNaN(a) || isNaN(b))
191     	return x + a + b;
192 
193     if (a < 0 || b < 0)
194     	return T.nan;
195     // allowing a==0 and b==0  <==> treat as one- or two-point mass
196 
197     if (x <= 0)
198 	    return R_DT_0!T(lower_tail, log_p);
199     if (x >= 1)
200 	    return R_DT_1!T(lower_tail, log_p);
201 
202     return pbeta_raw!T(x, a, b, lower_tail, log_p);
203 }
204 
205 enum USE_LOG_X_CUTOFF = -5.;
206 enum n_NEWTON_FREE = 4;
207 enum MLOGICAL_NA = -1;
208 
209 static const double DBL_very_MIN  = DBL_MIN / 4., 
210        DBL_log_v_MIN = M_LN2*(DBL_MIN_EXP - 2), DBL_1__eps = 0x1.fffffffffffffp-1;
211 
212 enum fpu = 3e-308;
213 enum acu_min = 1e-300;
214 enum p_lo = fpu;
215 enum p_hi = 1-2.22e-16;
216 
217 enum const1 = 2.30753;
218 enum const2 = 0.27061;
219 enum const3 = 0.99229;
220 enum const4 = 0.04481;
221 
222 immutable(string) return_q_0(){
223 	return `if(give_log_q){
224 	        	qb[0] = T.infinity; qb[1] = 0;
225 	        } else {
226 	        	qb[0] = 0; qb[1] = 1;
227 	        }
228 	            return;`;
229 }
230 
231 immutable(string) return_q_1(){
232 	return `if(give_log_q){
233 	         	qb[0] = 0; qb[1] = -T.infinity;
234 	         } else {
235 	             qb[0] = 1; qb[1] = 0;
236 	         }
237 	         return;`;
238 }
239 
240 immutable(string) return_q_half(){
241 	    return `if(give_log_q)
242 	                qb[0] = qb[1] = -M_LN2;
243 	            else
244 	            	qb[0] = qb[1] = 0.5;
245 	            return;`;
246 }
247 
248 void qbeta_raw(T)(T alpha, T p, T q, int lower_tail, int log_p,
249 	  int swap_01, // {TRUE, NA, FALSE}: if NA, algorithm decides swap_tail
250 	  T log_q_cut, /* if == Inf: return log(qbeta(..));
251 			       otherwise, if finite: the bound for
252 			       switching to log(x)-scale; see use_log_x */
253 	  int n_N,  // number of "unconstrained" Newton steps before switching to constrained
254 	  T *qb) // = qb[0:1] = { qbeta(), 1 - qbeta() }
255 {
256 	//Rboolean
257     int swap_choose = (swap_01 == MLOGICAL_NA),
258 	    swap_tail, log_, give_log_q = (log_q_cut == T.infinity),
259 	    use_log_x = give_log_q, // or u < log_q_cut  below
260 	    warned = 0, add_N_step = 1;
261     int i_pb, i_inn, bad_init, bad_u;
262     T adj = 1.;
263     T a, la, logbeta, g, h, pp, p_, qq, r, s, t, w, y = -1., u_n;
264     T wprev, prev;
265     /* volatile */ T u, xinbta;
266 
267     // Assuming p >= 0, q >= 0  here ...
268 
269     // Deal with boundary cases here:
270     if(alpha == R_DT_0!T(lower_tail, log_p)){
271         //#define return_q_0						\
272         //	if(give_log_q) { qb[0] = ML_NEGINF; qb[1] = 0; }	\
273         //	else {           qb[0] = 0;         qb[1] = 1; }	\
274         //	return
275         mixin (return_q_0());
276     }
277     if(alpha == R_DT_1!T(lower_tail, log_p)){
278         //#define return_q_1						\
279         //	if(give_log_q) { qb[0] = 0; qb[1] = ML_NEGINF; }	\
280         //	else {           qb[0] = 1; qb[1] = 0;         }	\
281         //	return
282 	    mixin (return_q_1());
283     }
284 
285     // check alpha {*before* transformation which may all accuracy}:
286     if((log_p && alpha > 0) || (!log_p && (alpha < 0 || alpha > 1))) { // alpha is outside
287 	    //R_ifDEBUG_printf("qbeta(alpha=%g, %g, %g, .., log_p=%d): %s%s\n",
288 	    //		 alpha, p,q, log_p, "alpha not in ", log_p ? "[-Inf, 0]" : "[0,1]");
289 	    //ML_ERROR(ME_DOMAIN, "");
290 	    qb[0] = qb[1] = T.nan; return;
291     }
292 
293     //  p==0, q==0, p = Inf, q = Inf  <==> treat as one- or two-point mass
294     if(p == 0 || q == 0 || !isFinite(p) || !isFinite(q)) {
295 	    // We know 0 < T(alpha) < 1 : pbeta() is constant and trivial in {0, 1/2, 1}
296 	    //R_ifDEBUG_printf(
297 	    //    "qbeta(%g, %g, %g, lower_t=%d, log_p=%d): (p,q)-boundary: trivial\n",  alpha, p,q, lower_tail, log_p);
298 	    if(p == 0 && q == 0) { // point mass 1/2 at each of {0,1} :
299 	        if(alpha < R_D_half(log_p)){
300 	        	return_q_0;
301 	        }
302 	        if(alpha > R_D_half(log_p)){
303 	        	return_q_1;
304 	        }
305 	        // else:  alpha == "1/2"
306         //#define return_q_half					\
307         //	    if(give_log_q) qb[0] = qb[1] = -M_LN2;	\
308         //	    else	   qb[0] = qb[1] = 0.5;		\
309         //	    return
310         
311 	        mixin (return_q_half());
312 	    } else if (p == 0 || p/q == 0) { // point mass 1 at 0 - "flipped around"
313 	        return_q_0;
314 	    } else if (q == 0 || q/p == 0) { // point mass 1 at 0 - "flipped around"
315 	        return_q_1;
316 	    }
317 	    // else:  p = q = Inf : point mass 1 at 1/2
318 	    mixin (return_q_half());
319     }
320 
321     mixin R_DT_qIv!(alpha);
322     mixin R_DT_CIv!(alpha);
323     /* initialize */
324     p_ = R_DT_qIv;/* lower_tail prob (in any case) */
325     // Conceptually,  0 < p_ < 1  (but can be 0 or 1 because of cancellation!)
326     logbeta = lbeta!T(p, q);
327 
328     swap_tail = (swap_choose) ? (p_ > 0.5) : swap_01;
329     // change tail; default (swap_01 = NA): afterwards 0 < a <= 1/2
330     if(swap_tail) { /* change tail, swap  p <-> q :*/
331 	    a = R_DT_CIv; // = 1 - p_ < 1/2
332 	    /* la := log(a), but without numerical cancellation: */
333 	    la = R_DT_Clog!T(alpha, lower_tail, log_p);
334 	    pp = q; qq = p;
335     }
336     else {
337 	    a = p_;
338 	    la = R_DT_log!T(alpha, lower_tail);
339 	    pp = p; qq = q;
340     }
341 
342     /* calculate the initial approximation */
343 
344     /* Desired accuracy for Newton iterations (below) should depend on  (a,p)
345      * This is from Remark .. on AS 109, adapted.
346      * However, it's not clear if this is "optimal" for IEEE double prec.
347 
348      * acu = fmax2(acu_min, pow(10., -25. - 5./(pp * pp) - 1./(a * a)));
349 
350      * NEW: 'acu' accuracy NOT for squared adjustment, but simple;
351      * ---- i.e.,  "new acu" = sqrt(old acu)
352      */
353     T acu = fmax2(acu_min, pow(10., -13. - 2.5/(pp * pp) - 0.5/(a * a)));
354     // try to catch  "extreme left tail" early
355     T tx, u0 = (la + log(pp) + logbeta) / pp; // = log(x_0)
356     static const T log_eps_c = M_LN2 * (1. - DBL_MANT_DIG);// = log(DBL_EPSILON) = -36.04..
357     r = pp*(1. - qq)/(pp + 1.);
358 
359     t = 0.2;
360     // FIXME: Factor 0.2 is a bit arbitrary;  '1' is clearly much too much.
361 
362     //R_ifDEBUG_printf(
363 	//"qbeta(%g, %g, %g, lower_t=%d, log_p=%d):%s\n"
364 	//"  swap_tail=%d, la=%#8g, u0=%#8g (bnd: %g (%g)) ",
365 	//alpha, p,q, lower_tail, log_p,
366 	//(log_p && (p_ == 0. || p_ == 1.)) ? (p_==0.?" p_=0":" p_=1") : "",
367 	//swap_tail, la, u0,
368 	//(t*log_eps_c - log(fabs(pp*(1.-qq)*(2.-qq)/(2.*(pp+2.)))))/2.,
369 	// t*log_eps_c - log(fabs(r))
370 	//);
371 
372     if(M_LN2 * DBL_MIN_EXP < u0 && // cannot allow exp(u0) = 0 ==> exp(u1) = exp(u0) = 0
373        u0 < -0.01 && // (must: u0 < 0, but too close to 0 <==> x = exp(u0) = 0.99..)
374        // qq <= 2 && // <--- "arbitrary"
375        // u0 <  t*log_eps_c - log(fabs(r)) &&
376        u0 < (t*log_eps_c - log(fabs(pp*(1. - qq)*(2. - qq)/(2.*(pp + 2.)))))/2.)
377     {
378         // TODO: maybe jump here from below, when initial u "fails" ?
379         // L_tail_u:
380 	    // MM's one-step correction (cheaper than 1 Newton!)
381 	    r = r*exp(u0);// = r*x0
382 	    if(r > -1.) {
383 	        u = u0 - log1p(r)/pp;
384 	        //R_ifDEBUG_printf("u1-u0=%9.3g --> choosing u = u1\n", u-u0);
385 	    } else {
386 	        u = u0;
387 	        //R_ifDEBUG_printf("cannot cheaply improve u0\n");
388 	    }
389 	    tx = xinbta = exp(u);
390 	    use_log_x = 1; // or (u < log_q_cut)  ??
391 	    goto L_Newton;
392     }
393 
394     // y := y_\alpha in AS 64 := Hastings(1955) approximation of qnorm(1 - a) :
395     r = sqrt(-2 * la);
396     y = r - (const1 + const2 * r) / (1. + (const3 + const4 * r) * r);
397 
398     if (pp > 1 && qq > 1) { // use  Carter(1947), see AS 109, remark '5.'
399 	    r = (y * y - 3.) / 6.;
400 	    s = 1. / (pp + pp - 1.);
401 	    t = 1. / (qq + qq - 1.);
402 	    h = 2. / (s + t);
403 	    w = y * sqrt(h + r) / h - (t - s) * (r + 5. / 6. - 2. / (3. * h));
404 	    //R_ifDEBUG_printf("p,q > 1 => w=%g", w);
405 	    if(w > 300) { // exp(w+w) is huge or overflows
406 	        t = w+w + log(qq) - log(pp); // = argument of log1pexp(.)
407 	        u = // log(xinbta) = - log1p(qq/pp * exp(w+w)) = -log(1 + exp(t))
408 	    	(t <= 18) ? -log1p(exp(t)) : -t - exp(-t);
409 	        xinbta = exp(u);
410 	    } else {
411 	        xinbta = pp / (pp + qq * exp(w + w));
412 	        u = // log(xinbta)
413 	    	- log1p(qq/pp * exp(w + w));
414 	    }
415     } else { // use the original AS 64 proposal, Scheffé-Tukey (1944) and Wilson-Hilferty
416 	r = qq + qq;
417 	    /* A slightly more stable version of  t := \chi^2_{alpha} of AS 64
418 	     * t = 1. / (9. * qq); t = r * R_pow_di(1. - t + y * sqrt(t), 3);  */
419 	    t = 1. / (3. * sqrt(qq));
420 	    t = r * R_pow_di!T(1. + t*(-t + y), 3);// = \chi^2_{alpha} of AS 64
421 	    s = 4. * pp + r - 2.;// 4p + 2q - 2 = numerator of new t = (...) / chi^2
422 	    //R_ifDEBUG_printf("min(p,q) <= 1: t=%g", t);
423 	    if (t == 0 || (t < 0. && s >= t)) { // cannot use chisq approx
424 	        // x0 = 1 - { (1-a)*q*B(p,q) } ^{1/q}    {AS 65}
425 	        // xinbta = 1. - exp((log(1-a)+ log(qq) + logbeta) / qq);
426 	        T l1ma;/* := log(1-a), directly from alpha (as 'la' above):
427 	    		 * FIXME: not worth it? log1p(-a) always the same ?? */
428 	        if(swap_tail)
429 	    	l1ma = R_DT_log!T(alpha, lower_tail);
430 	        else
431 	    	l1ma = R_DT_Clog!T(alpha, lower_tail, log_p);
432 	        //R_ifDEBUG_printf(" t <= 0 : log1p(-a)=%.15g, better l1ma=%.15g\n", log1p(-a), l1ma);
433 	        T xx = (l1ma + log(qq) + logbeta) / qq;
434 	        if(xx <= 0.) {
435 	    	xinbta = -expm1(xx);
436 	    	u = R_Log1_Exp!T(xx);// =  log(xinbta) = log(1 - exp(...A...))
437 	        } else { // xx > 0 ==> 1 - e^xx < 0 .. is nonsense
438 	    	    //R_ifDEBUG_printf(" xx=%g > 0: xinbta:= 1-e^xx < 0\n", xx);
439 	    	    xinbta = 0; u = -T.infinity; /// FIXME can do better?
440 	        }
441 	    } else {
442 	        t = s / t;
443 	        //R_ifDEBUG_printf(" t > 0 or s < t < 0:  new t = %g ( > 1 ?)\n", t);
444 	        if (t <= 1.) { // cannot use chisq, either
445 	    	    u = (la + log(pp) + logbeta) / pp;
446 	    	    xinbta = exp(u);
447 	        } else { // (1+x0)/(1-x0) = t,  solved for x0 :
448 	    	    xinbta = 1. - 2. / (t + 1.);
449 	    	    u = log1p(-2. / (t + 1.));
450 	        }
451 	    }
452     }
453 
454     // Problem: If initial u is completely wrong, we make a wrong decision here
455     if(swap_choose && (( swap_tail && u >= -exp(  log_q_cut)) || // ==> "swap back"
456 	(!swap_tail && u >= -exp(4*log_q_cut) && pp / qq < 1000.) // ==> "swap now"
457 	   )) {
458 	// "revert swap" -- and use_log_x
459 	swap_tail = !swap_tail;
460 	//R_ifDEBUG_printf(" u = %g (e^u = xinbta = %.16g) ==> ", u, xinbta);
461 	if(swap_tail) { // "swap now" (much less easily)
462 	    a = R_DT_CIv; // needed ?
463 	    la = R_DT_Clog!T(alpha, lower_tail, log_p);
464 	    pp = q; qq = p;
465 	}
466 	else { // swap back :
467 	    a = p_;
468 	    la = R_DT_log!T(alpha, lower_tail);
469 	    pp = p; qq = q;
470 	}
471 	//R_ifDEBUG_printf("\"%s\"; la = %g\n", (swap_tail ? "swap now" : "swap back"), la);
472 	// we could redo computations above, but this should be stable
473 	u = R_Log1_Exp!T(u);
474 	xinbta = exp(u);
475 
476 /* Careful: "swap now"  should not fail if
477    1) the above initial xinbta is "completely wrong"
478    2) The correction step can go outside (u_n > 0 ==>  e^u > 1 is illegal)
479    e.g., for  qbeta(0.2066, 0.143891, 0.05)
480 */
481     } //else R_ifDEBUG_printf("\n");
482 
483     if(!use_log_x)
484 	use_log_x = (u < log_q_cut);// <==> xinbta = e^u < exp(log_q_cut)
485     //Rboolean
486     bad_u = !isFinite(u);
487     bad_init = bad_u || xinbta > p_hi;
488 
489     //R_ifDEBUG_printf(" -> u = %g, e^u = xinbta = %.16g, (Newton acu=%g%s%s%s)\n",
490 	//	     u, xinbta, acu, (bad_u ? ", ** bad u **" : ""),
491 	//	     ((bad_init && !bad_u) ? ", ** bad_init **" : ""),
492 	//	     (use_log_x ? ", on u = LOG(x) SCALE" : ""));
493 
494     u_n = 1.; // -Wall
495     tx = xinbta; // keeping "original initial x" (for now)
496 
497     if(bad_u || u < log_q_cut) {
498 	    /* e.g.
499 	       qbeta(0.21, .001, 0.05)
500 	       try "left border" quickly, i.e.,
501 	       try at smallest positive number: */
502 	    w = pbeta_raw!T(DBL_very_MIN, pp, qq, 1, log_p);
503 	    if(w > (log_p ? la : a)) {
504 	        //R_ifDEBUG_printf(
505 	    	//" quantile is left of %g; \"convergence\"\n", DBL_very_MIN);
506 	        if(log_p || fabs(w - a) < fabs(0 - a)) { // DBL_very_MIN is better than 0
507 	    	    tx   = DBL_very_MIN;
508 	    	    u_n  = DBL_log_v_MIN;// = log(DBL_very_MIN)
509 	        } else {
510 	    	    tx   = 0.;
511 	    	    u_n  = -T.infinity;
512 	        }
513 	        use_log_x = log_p; add_N_step = 0; goto L_return;
514 	    } else {
515 	        //R_ifDEBUG_printf(" pbeta(%g, *) = %g <= %g (= %s) --> continuing\n",
516 	    	//	     DBL_log_v_MIN, w, (log_p ? la : a), (log_p ? "la" : "a"));
517 	        if(u  < DBL_log_v_MIN) {
518 	    	    u = DBL_log_v_MIN;// = log(DBL_very_MIN)
519 	    	    xinbta = DBL_very_MIN;
520 	        }
521 	    }
522     }
523 
524 
525     /* Sometimes the approximation is negative (and == 0 is also not "ok") */
526     if (bad_init && !(use_log_x && tx > 0)) {
527 	    if(u == -T.infinity) {
528 	        //R_ifDEBUG_printf("  u = -Inf;");
529 	        u = M_LN2 * DBL_MIN_EXP;
530 	        xinbta = DBL_MIN;
531 	    } else {
532 	        //R_ifDEBUG_printf(" bad_init: u=%g, xinbta=%g;", u,xinbta);
533 	        xinbta = (xinbta > 1.1) // i.e. "way off"
534 	    	? 0.5 // otherwise, keep the respective boundary:
535 	    	: ((xinbta < p_lo) ? exp(u) : p_hi);
536 	        if(bad_u)
537 	    	    u = log(xinbta);
538 	        // otherwise: not changing "potentially better" u than the above
539 	    }
540 	    //R_ifDEBUG_printf(" -> (partly)new u=%g, xinbta=%g\n", u,xinbta);
541     }
542 
543 L_Newton:
544     /* --------------------------------------------------------------------
545 
546      * Solve for x by a modified Newton-Raphson method, using pbeta_raw()
547      */
548     r = 1 - pp;
549     t = 1 - qq;
550     wprev = 0., prev = 1.; // -Wall
551 
552     if(use_log_x) { // find  log(xinbta) -- work in  u := log(x) scale
553 	    // if(bad_init && tx > 0) xinbta = tx;// may have been better
554 	    for (i_pb = 0; i_pb < 1000; i_pb++) {
555 	        // using log_p == TRUE  unconditionally here
556 	        /* FIXME: if exp(u) = xinbta underflows to 0,
557 	         *  want different formula pbeta_log(u, ..) */
558 	        y = pbeta_raw!T(xinbta, pp, qq, /*lower_tail = */ 1, 1);
559         
560 	        /* w := Newton step size for   L(u) = log F(e^u)  =!= 0;   u := log(x)
561 	         *   =  (L(.) - la) / L'(.);  L'(u)= (F'(e^u) * e^u ) / F(e^u)
562 	         *   =  (L(.) - la)*F(.) / {F'(e^u) * e^u } =
563 	         *   =  (L(.) - la) * e^L(.) * e^{-log F'(e^u) - u}
564 	         *   =  ( y   - la) * e^{ y - u -log F'(e^u)}
565 	         and  -log F'(x)= -log f(x) = - -logbeta + (1-p) log(x) + (1-q) log(1-x)
566 	                                    = logbeta + (1-p) u + (1-q) log(1-e^u)
567 	        */
568 	        w = (y == -T.infinity) // y = -Inf  well possible: we are on log scale!
569 	    	? 0. : (y - la) * exp(y - u + logbeta + r * u + t * R_Log1_Exp(u));
570 	        if(!isFinite(w))
571 	    	break;
572 	        if (i_pb >= n_N && w * wprev <= 0.)
573 	    	prev = fmax2!T(fabs(adj),fpu);
574 	        //R_ifDEBUG_printf(
575 	    	//"N(i=%2d): u=%#20.16g, pb(e^u)=%#15.9g, w=%#15.9g, %s prev=%g,",
576 	    	//i_pb, u, y, w, (i_pb >= n_N && w * wprev <= 0.) ? "new" : "old", prev);
577 	        g = 1;
578 	        for (i_inn = 0; i_inn < 1000; i_inn++) {
579 	    	    adj = g * w;
580 	    	    // safe guard (here, from the very beginning)
581 	    	    if (fabs(adj) < prev) {
582 	    	        u_n = u - adj; // u_{n+1} = u_n - g*w
583 	    	        if (u_n <= 0.) { // <==> 0 <  xinbta := e^u  <= 1
584 	    	    	if (prev <= acu || fabs(w) <= acu) {
585 	    	     	    //R_ifDEBUG_printf(" it{in}=%d, -adj=%g, %s <= acu  ==> convergence\n",
586 	    	    		//i_inn, -adj, (prev <= acu) ? "prev" : "|w|");
587 	    	    	    goto L_converged;
588 	    	    	}
589 	    	    	// if (u_n != ML_NEGINF && u_n != 1)
590 	    	    	break;
591 	    	        }
592 	    	    }
593 	    	    g /= 3;
594 	        }
595 	        // (cancellation in (u_n -u) => may differ from adj:
596 	        T D = fmin2!T(fabs(adj), fabs(u_n - u));
597 	        /* R_ifDEBUG_printf(" delta(u)=%g\n", u_n - u); */
598 	        //R_ifDEBUG_printf(" it{in}=%d, delta(u)=%9.3g, D/|.|=%.3g\n",
599 	    	//	     i_inn, u_n - u, D/fabs(u_n + u));
600 	        if (D <= 4e-16 * fabs(u_n + u))
601 	    	goto L_converged;
602 	        u = u_n;
603 	        xinbta = exp(u);
604 	        wprev = w;
605 	    } // for(i )
606         
607     } else { // "normal scale" Newton
608 
609 	for (i_pb=0; i_pb < 1000; i_pb++) {
610 	    y = pbeta_raw!T(xinbta, pp, qq, /*lower_tail = */ 1, log_p);
611 	    // delta{y} :   d_y = y - (log_p ? la : a);
612 	    if(!isFinite(y) && !(log_p && y == T.infinity))// y = -Inf  is ok if(log_p)
613 		{ // ML_ERR_return_NAN :
614 		    //ML_ERROR(ME_DOMAIN, "");
615 		    qb[0] = qb[1] = T.nan; return;
616 		}
617 
618 
619 	    /* w := Newton step size  (F(.) - a) / F'(.)  or,
620 	     * --   log: (lF - la) / (F' / F) = exp(lF) * (lF - la) / F'
621 	     */
622 	    w = log_p
623 		? (y - la) * exp(y + logbeta + r * log(xinbta) + t * log1p(-xinbta))
624 		: (y - a)  * exp(    logbeta + r * log(xinbta) + t * log1p(-xinbta));
625 	    if (i_pb >= n_N && w * wprev <= 0.)
626 		prev = fmax2!T(fabs(adj),fpu);
627 	    //R_ifDEBUG_printf(
628 		//"N(i=%2d): x0=%#17.15g, pb(x0)=%#15.9g, w=%#15.9g, %s prev=%g,",
629 		//i_pb, xinbta, y, w,
630 		//(i_pb >= n_N && w * wprev <= 0.) ? "new" : "old", prev);
631 	    g = 1;
632 	    for (i_inn = 0; i_inn < 1000; i_inn++) {
633 		    adj = g * w;
634 		    // take full Newton steps at the beginning; only then safe guard:
635 		    if (i_pb < n_N || fabs(adj) < prev) {
636 		        tx = xinbta - adj; // x_{n+1} = x_n - g*w
637 		        if (0. <= tx && tx <= 1.) {
638 		    	if (prev <= acu || fabs(w) <= acu) {
639 		    	    //R_ifDEBUG_printf(" it{in}=%d, delta(x)=%g, %s <= acu  ==> convergence\n",
640 		    		//	     i_inn, -adj, (prev <= acu) ? "prev" : "|w|");
641 		    	    goto L_converged;
642 		    	}
643 		    	if (tx != 0. && tx != 1)
644 		    	    break;
645 		        }
646 		    }
647 		    g /= 3;
648 	    }
649 	    //R_ifDEBUG_printf(" it{in}=%d, delta(x)=%g\n", i_inn, tx - xinbta);
650 	    if (fabs(tx - xinbta) <= 4e-16 * (tx + xinbta)) // "<=" : (.) == 0
651 		    goto L_converged;
652 	    xinbta = tx;
653 	    if(tx == 0) // "we have lost"
654 		    break;
655 	    wprev = w;
656 	} // for( i_pb ..)
657 
658     } // end{else : normal scale Newton}
659 
660     /*-- NOT converged: Iteration count --*/
661     warned = 1;
662     //ML_ERROR(ME_PRECISION, "qbeta");
663 
664 L_converged:
665     log_ = log_p || use_log_x; // only for printing
666     //R_ifDEBUG_printf(" %s: Final delta(y) = %g%s\n",
667 	//	     warned ? "_NO_ convergence" : "converged",
668 	//	     y - (log_ ? la : a), (log_ ? " (log_)" : ""));
669     if((log_ && y == -T.infinity) || (!log_ && y == 0)) {
670 	    // stuck at left, try if smallest positive number is "better"
671 	    w = pbeta_raw!T(DBL_very_MIN, pp, qq, 1, log_);
672 	    if(log_ || fabs(w - a) <= fabs(y - a)) {
673 	        tx  = DBL_very_MIN;
674 	        u_n = DBL_log_v_MIN;// = log(DBL_very_MIN)
675 	    }
676 	    add_N_step = 0; // not trying to do better anymore
677     }
678     else if(!warned && (log_ ? fabs(y - la) > 3 : fabs(y - a) > 1e-4)) {
679 	if(!(log_ && y == -T.infinity && pbeta_raw!T(DBL_1__eps, pp, qq, 1, 1) > la + 2))
680 		doNothing();
681 	    //MATHLIB_WARNING2( // low accuracy for more platform independent output:
682 		//"qbeta(a, *) =: x0 with |pbeta(x0,*%s) - alpha| = %.5g is not accurate",
683 		//(log_ ? ", log_" : ""), fabs(y - (log_ ? la : a)));
684     }
685 L_return:
686     if(give_log_q) { // ==> use_log_x , too
687 	    if(!use_log_x) // (see if claim above is true)
688 	        //MATHLIB_WARNING(
689 	    	//"qbeta() L_return, u_n=%g;  give_log_q=TRUE but use_log_x=FALSE -- please report!", u_n);
690 	    r = R_Log1_Exp!T(u_n);
691 	    if(swap_tail) {
692 	        qb[0] = r; qb[1] = u_n;
693 	    } else {
694 	        qb[0] = u_n; qb[1] = r;
695 	    }
696     } else {
697 	if(use_log_x) {
698 	    if(add_N_step) {
699 		/* add one last Newton step on original x scale, e.g., for
700 		   qbeta(2^-98, 0.125, 2^-96) */
701 		xinbta = exp(u_n);
702 		y = pbeta_raw!T(xinbta, pp, qq, /*lower_tail = */ 1, log_p);
703 		w = log_p
704 		    ? (y - la) * exp(y + logbeta + r * log(xinbta) + t * log1p(-xinbta))
705 		    : (y - a)  * exp(logbeta + r * log(xinbta) + t * log1p(-xinbta));
706 		tx = xinbta - w;
707 		//R_ifDEBUG_printf(" Final Newton correction(non-log scale):\n"
708 		//						   //   \n  xinbta=%.16g
709 		//		 "  xinbta=%.16g, y=%g, w=-Delta(x)=%g. \n=> new x=%.16g\n",
710 		//    xinbta, y, w, tx);
711 	    } else {
712 		    if(swap_tail){
713 		        qb[0] = -expm1(u_n); qb[1] =  exp(u_n);
714 		    } else {
715 		        qb[0] =  exp(u_n); qb[1] = -expm1(u_n);
716 		    }
717 		    return;
718 	    }
719 	}
720 	    if(swap_tail){
721 	        qb[0] = 1 - tx; qb[1] = tx;
722 	    } else {
723 	        qb[0] = tx;	qb[1] = 1 - tx;
724 	    }
725     }
726     return;
727 }
728 
729 T qbeta(T: double)(T alpha, T p, T q, int lower_tail, int log_p)
730 {
731 
732     /* test for admissibility of parameters */
733     if (isNaN(p) || isNaN(q) || isNaN(alpha))
734 	    return p + q + alpha;
735     if(p < 0. || q < 0.)
736     	return T.nan;
737     // allowing p==0 and q==0  <==> treat as one- or two-point mass
738 
739     T[2] qbet;// = { qbeta(), 1 - qbeta() }
740     qbeta_raw!T(alpha, p, q, lower_tail, log_p, MLOGICAL_NA, USE_LOG_X_CUTOFF, n_NEWTON_FREE, qbet.ptr);
741     return qbet[0];
742 }
743 
744 enum expmax = (DBL_MAX_EXP * M_LN2); /* = log(DBL_MAX) */
745 
746 immutable(string) v_w_from__u1_bet_b(){
747 	    return `v = beta * log(u1 / (1.0 - u1));
748 	    if (v <= expmax) {
749 		w = b * exp(v);
750 		if(!isFinite(w)) w = DBL_MAX;
751 	    } else
752 		w = DBL_MAX;`;
753 }
754 
755 immutable(string) v_w_from__u1_bet_a(){
756 	    return `v = beta * log(u1 / (1.0 - u1));
757 	    if (v <= expmax) {
758 		w = a * exp(v);
759 		if(!isFinite(w)) w = DBL_MAX;
760 	    } else
761 		w = DBL_MAX;`;
762 }
763 
764 T rbeta(T: double)(T aa, T bb)
765 {
766     if (isNaN(aa) || isNaN(bb) || aa < 0. || bb < 0.)
767 	    return T.nan;
768     if (!isFinite(aa) && !isFinite(bb)) // a = b = Inf : all mass at 1/2
769 	    return 0.5;
770     if (aa == 0. && bb == 0.) // point mass 1/2 at each of {0,1} :
771 	    return (unif_rand!T() < 0.5) ? 0. : 1.;
772     // now, at least one of a, b is finite and positive
773     if (!isFinite(aa) || bb == 0.)
774     	return 1.0;
775     if (!isFinite(bb) || aa == 0.)
776     	return 0.0;
777 
778     T a, b, alpha;
779     T r, s, t, u1, u2, v, w, y, z;
780     int qsame;
781     /* FIXME:  Keep Globals (properly) for threading */
782     /* Uses these GLOBALS to save time when many rv's are generated : */
783     static T beta, gamma, delta, k1, k2;
784     static T olda = -1.0;
785     static T oldb = -1.0;
786 
787     /* Test if we need new "initializing" */
788     qsame = (olda == aa) && (oldb == bb);
789     if (!qsame) { olda = aa; oldb = bb; }
790 
791     a = fmin2(aa, bb);
792     b = fmax2(aa, bb); /* a <= b */
793     alpha = a + b;
794 
795     //#define v_w_from__u1_bet(AA) 			\
796     //	    v = beta * log(u1 / (1.0 - u1));	\
797     //	    if (v <= expmax) {			\
798     //		w = AA * exp(v);		\
799     //		if(!R_FINITE(w)) w = DBL_MAX;	\
800     //	    } else				\
801     //		w = DBL_MAX
802 
803 
804     if (a <= 1.0) {	/* --- Algorithm BC --- */
805 
806 	/* changed notation, now also a <= b (was reversed) */
807 
808 	if (!qsame) { /* initialize */
809 	    beta = 1.0 / a;
810 	    delta = 1.0 + b - a;
811 	    k1 = delta * (0.0138889 + 0.0416667 * a) / (b * beta - 0.777778);
812 	    k2 = 0.25 + (0.5 + 0.25 / delta) * a;
813 	}
814 	/* FIXME: "do { } while()", but not trivially because of "continue"s:*/
815 	for(;;) {
816 	    u1 = unif_rand!T();
817 	    u2 = unif_rand!T();
818 	    if (u1 < 0.5) {
819 		y = u1 * u2;
820 		z = u1 * y;
821 		if (0.25 * u2 + z - y >= k1)
822 		    continue;
823 	    } else {
824 		z = u1 * u1 * u2;
825 		if (z <= 0.25) {
826 		    mixin (v_w_from__u1_bet_b());
827 		    break;
828 		}
829 		if (z >= k2)
830 		    continue;
831 	    }
832 
833 	    mixin (v_w_from__u1_bet_b());
834 
835 	    if (alpha * (log(alpha / (a + w)) + v) - 1.3862944 >= log(z))
836 		break;
837 	}
838 	return (aa == a) ? a / (a + w) : w / (a + w);
839 
840     } else {		/* Algorithm BB */
841 
842 	if (!qsame) { /* initialize */
843 	    beta = sqrt((alpha - 2.0) / (2.0 * a * b - alpha));
844 	    gamma = a + 1.0 / beta;
845 	}
846 	do {
847 	    u1 = unif_rand!T();
848 	    u2 = unif_rand!T();
849 
850 	    mixin (v_w_from__u1_bet_a());
851 
852 	    z = u1 * u1 * u2;
853 	    r = gamma * v - 1.3862944;
854 	    s = a + r - w;
855 	    if (s + 2.609438 >= 5.0 * z)
856 		break;
857 	    t = log(z);
858 	    if (s > t)
859 		break;
860 	} while (r + alpha * log(alpha / (b + w)) < t);
861 
862 	return (aa != a) ? b / (b + w) : w / (b + w);
863     }
864 }
865 
866 
867 
868 void test_beta(){
869 	import std.stdio: writeln;
870 	writeln("beta: ", beta(2., 4.));
871 	writeln("dbeta: ", dbeta(.7, 3., 5., 1));
872 	writeln("pbeta: ", pbeta(.7, 3., 5., 1, 0));
873 	writeln("qbeta: ", qbeta(.7, 3., 5., 1, 0));
874 	writeln("rbeta: ", rbeta(3., 5.), ", rbeta: ", rbeta(3., 5.), ", rbeta: ", rbeta(3., 5.));
875 }