11/*
22 * Mathlib : A C Library of Special Functions
3- * Copyright (C) 2000-2020 The R Core Team
3+ * Copyright (C) 2000-2025 The R Core Team
44 * Copyright (C) 2005-2020 The R Foundation
55 * Copyright (C) 1998 Ross Ihaka
66 *
@@ -84,21 +84,6 @@ double rhyper(double nn1in, double nn2in, double kkin)
8484{
8585 /* extern double afc(int); */
8686
87- int nn1 , nn2 , kk ;
88- int ix ; // return value (coerced to double at the very end)
89- bool setup1 , setup2 ;
90-
91- /* These should become 'thread_local globals' : */
92- static int ks = -1 , n1s = -1 , n2s = -1 ;
93- static int m , minjx , maxjx ;
94- static int k , n1 , n2 ; // <- not allowing larger integer par
95- static double N ;
96-
97- // II :
98- static double w ;
99- // III:
100- static double a , d , s , xl , xr , kl , kr , lamdl , lamdr , p1 , p2 , p3 ;
101-
10287 /* check parameter validity */
10388
10489 if (!R_FINITE (nn1in ) || !R_FINITE (nn2in ) || !R_FINITE (kkin ))
@@ -113,6 +98,9 @@ double rhyper(double nn1in, double nn2in, double kkin)
11398 if (nn1in >= INT_MAX || nn2in >= INT_MAX || kkin >= INT_MAX ) {
11499 /* large n -- evade integer overflow (and inappropriate algorithms)
115100 -------- */
101+ #ifdef DEBUG_rhyper
102+ REprintf ("rhyper(nn1=%.0f, nn2=%.0f, kk=%.0f): 'large n' case\n" , nn1in , nn2in , kkin );
103+ #endif
116104 // FIXME: Much faster to give rbinom() approx when appropriate; -> see Kuensch(1989)
117105 // Johnson, Kotz,.. p.258 (top) mention the *four* different binomial approximations
118106 if (kkin == 1. ) { // Bernoulli
@@ -123,10 +111,19 @@ double rhyper(double nn1in, double nn2in, double kkin)
123111 /*lower_tail =*/ false, /*log_p = */ false);
124112 // lower_tail=false: a thinko, is still "correct" as equiv. to U <--> 1-U
125113 }
126- nn1 = (int )nn1in ;
127- nn2 = (int )nn2in ;
128- kk = (int )kkin ;
129114
115+ int
116+ nn1 = (int )nn1in ,
117+ nn2 = (int )nn2in ,
118+ kk = (int )kkin ;
119+
120+ /* These should become 'thread_local globals' : */
121+ static int ks = -1 , n1s = -1 , n2s = -1 ;
122+ static int m , minjx , maxjx ;
123+ static int k , n1 , n2 ; // <- not allowing larger integer par
124+ static double N ;
125+
126+ bool setup1 , setup2 ;
130127 /* if new parameter values, initialize */
131128 if (nn1 != n1s || nn2 != n2s ) { // n1 | n2 is changed: setup all
132129 setup1 = true; setup2 = true;
@@ -152,6 +149,7 @@ double rhyper(double nn1in, double nn2in, double kkin)
152149 } else {
153150 k = kk ;
154151 }
152+ // now have k < N/2 = (n1+n2)/2
155153 }
156154 if (setup1 || setup2 ) {
157155 m = (int ) ((k + 1. ) * (n1 + 1. ) / (N + 2. )); // m := floor(adjusted mean E[.])
@@ -162,7 +160,14 @@ double rhyper(double nn1in, double nn2in, double kkin)
162160 nn1 , nn2 , kk , m , minjx , maxjx );
163161#endif
164162 }
165- /* generate random variate --- Three basic cases */
163+ #ifdef DEBUG_rhyper
164+ else
165+ REprintf ("rhyper(n1=%d, n2=%d, k=%d); setup UNchanged\n" , nn1 , nn2 , kk );
166+ #endif
167+
168+ // generate random variate --- Three basic cases ---------------------------
169+
170+ int ix ; // return value (coerced to double at the very end) .. FIXME?? what if overflows
166171
167172 if (minjx == maxjx ) { /* I: degenerate distribution ---------------- */
168173#ifdef DEBUG_rhyper
@@ -174,20 +179,28 @@ double rhyper(double nn1in, double nn2in, double kkin)
174179 } else if (m - minjx < 10 ) { // II: (Scaled) algorithm HIN (inverse transformation) ----
175180 const static double scale = 1e25 ; // scaling factor against (early) underflow
176181 const static double con = 57.5646273248511421 ;
177- // 25*log(10) = log(scale) { <==> exp(con) == scale }
182+ // 25*log(10) = log(scale) { <==> exp(con) == scale }
183+ static double w ,
184+ lw ; // = log(w); w = exp(lw) * scale = exp(lw + log(scale)) = exp(lw + con)
178185 if (setup1 || setup2 ) {
179- double lw ; // log(w); w = exp(lw) * scale = exp(lw + log(scale)) = exp(lw + con)
186+ // NB: n1 <= n2 here
180187 if (k < n2 ) {
181188 lw = afc (n2 ) + afc (n1 + n2 - k ) - afc (n2 - k ) - afc (n1 + n2 );
182189 } else {
183190 lw = afc (n1 ) + afc ( k ) - afc (k - n2 ) - afc (n1 + n2 );
184191 }
185192 w = exp (lw + con );
186193 }
187- double p , u ;
194+
188195#ifdef DEBUG_rhyper
189- REprintf ("rhyper(), branch II; w = %g > 0\n" , w );
196+ REprintf (" branch II; w = %g %s\n" , w ,
197+ (w > 0 ) ? "> 0" : "= 0 <==> Underflow __NOT GOOD__" );
190198#endif
199+ if (w <= 0. )
200+ MATHLIB_ERROR (_ ("w = %g <= 0: Underflow in rhyper() SHOULD NOT HAPPEN!" ), w );
201+ // FIXME: MM has code "rhyper.c+M3" for switching to log space if w == 0
202+
203+ double p , u ;
191204 L10 :
192205 p = w ;
193206 ix = minjx ;
@@ -210,40 +223,49 @@ double rhyper(double nn1in, double nn2in, double kkin)
210223
211224 } else { /* III : H2PE Algorithm --------------------------------------- */
212225
213- double u ,v ;
214-
226+ static double a , xl , xr , lamdl , lamdr , p1 , p2 , p3 ;
215227 if (setup1 || setup2 ) {
216- s = sqrt ((N - k ) * k * n1 * n2 / (N - 1 ) / N / N );
217-
218- /* remark: d is defined in reference without int. */
219- /* the truncation centers the cell boundaries at 0.5 */
228+ double
229+ s = sqrt ((N - k ) * k * n1 * n2 / (N - 1 ) / N / N ),
220230
221- d = (int ) (1.5 * s ) + .5 ;
231+ /* remark: d is defined in reference without int. */
232+ /* the truncation centers the cell boundaries at 0.5 */
233+ d = (int ) (1.5 * s ) + .5 ;
222234 xl = m - d + .5 ;
223235 xr = m + d + .5 ;
224236 a = afc (m ) + afc (n1 - m ) + afc (k - m ) + afc (n2 - k + m );
225- kl = exp (a - afc ((int ) (xl )) - afc ((int ) (n1 - xl ))
226- - afc ((int ) (k - xl ))
227- - afc ((int ) (n2 - k + xl )));
228- kr = exp (a - afc ((int ) (xr - 1 ))
229- - afc ((int ) (n1 - xr + 1 ))
230- - afc ((int ) (k - xr + 1 ))
231- - afc ((int ) (n2 - k + xr - 1 )));
237+ double
238+ kl = exp (a - afc ((int ) (xl )) - afc ((int ) (n1 - xl ))
239+ - afc ((int ) (k - xl ))
240+ - afc ((int ) (n2 - k + xl ))),
241+ kr = exp (a - afc ((int ) (xr - 1 ))
242+ - afc ((int ) (n1 - xr + 1 ))
243+ - afc ((int ) (k - xr + 1 ))
244+ - afc ((int ) (n2 - k + xr - 1 )));
232245 lamdl = - log (xl * (n2 - k + xl ) / (n1 - xl + 1 ) / (k - xl + 1 ));
233246 lamdr = - log ((n1 - xr + 1 ) * (k - xr + 1 ) / xr / (n2 - k + xr ));
234247 p1 = d + d ;
235248 p2 = p1 + kl / lamdl ;
236249 p3 = p2 + kr / lamdr ;
237- }
238250#ifdef DEBUG_rhyper
239- REprintf ("rhyper(), branch III {accept/reject}: (xl,xr)= (%g,%g); (lamdl,lamdr)= (%g,%g)\n" ,
240- xl , xr , lamdl ,lamdr );
241- REprintf ("-------- p123= c(%g,%g,%g)\n" , p1 ,p2 , p3 );
251+ REprintf ("rhyper(), branch III {accept/reject}: (xl,xr)= (%g,%g); lamdl,r = (%g,%g)\n" ,
252+ xl , xr , lamdl , lamdr );
253+ REprintf (" --------> (p1,p2,p3) = (%g,%g,%g)\n" , p1 ,p2 ,p3 );
254+ }
255+ else
256+ REprintf ("rhyper(), branch III {accept/reject}: NO setup needed; lamdl,r = (%g,%g)\n" ,
257+ lamdl , lamdr );
258+ #else
259+ }
242260#endif
243- int n_uv = 0 ;
244- L30 :
245- u = unif_rand () * p3 ;
246- v = unif_rand ();
261+
262+ /* acceptance/rejection test */
263+ bool reject = true;
264+ int n_uv = 0 ;
265+ do { // L30: -------------- acceptance / rejection : loop while reject=true -------------
266+ double
267+ u = unif_rand () * p3 ,
268+ v = unif_rand ();
247269 n_uv ++ ;
248270 if (n_uv >= 10000 ) {
249271 REprintf ("rhyper(*, n1=%d, n2=%d, k=%d): branch III: giving up after %d rejections\n" ,
@@ -256,20 +278,29 @@ double rhyper(double nn1in, double nn2in, double kkin)
256278
257279 if (u < p1 ) { /* rectangular region */
258280 ix = (int ) (xl + u );
281+ #ifdef DEBUG_rhyper
282+ REprintf (" rectangular: ix=%d\n" , ix );
283+ #endif
259284 } else if (u <= p2 ) { /* left tail */
260285 ix = (int ) (xl + log (v ) / lamdl );
286+ #ifdef DEBUG_rhyper
287+ REprintf (" left tail: ix=%d %s" , ix , (ix < minjx )? "< minjx (=> L30)\n" : ">= minjx;" );
288+ #endif
261289 if (ix < minjx )
262- goto L30 ;
290+ continue ; // goto L30
263291 v = v * (u - p1 ) * lamdl ;
264292 } else { /* right tail */
265293 ix = (int ) (xr - log (v ) / lamdr );
294+ #ifdef DEBUG_rhyper
295+ REprintf (" right tail: ix=%d %s" , ix , (ix > maxjx )? "> maxjx (=> L30)\n" : "< maxjx;" );
296+ #endif
266297 if (ix > maxjx )
267- goto L30 ;
298+ continue ; // goto L30
268299 v = v * (u - p2 ) * lamdr ;
269300 }
270-
271- /* acceptance/rejection test */
272- bool reject = true;
301+ #ifdef DEBUG_rhyper
302+ if ( u >= p1 ) REprintf ( " new v = %g\n" , v );
303+ #endif
273304
274305 if (m < 100 || ix <= 50 ) {
275306 /* explicit evaluation */
@@ -278,15 +309,17 @@ double rhyper(double nn1in, double nn2in, double kkin)
278309 in the (m > ix) case, but the definition of the
279310 recurrence relation on p134 shows that the +1 is
280311 needed. */
281- int i ;
282312 double f = 1.0 ;
283313 if (m < ix ) {
284- for (i = m + 1 ; i <= ix ; i ++ )
314+ for (int i = m + 1 ; i <= ix ; i ++ )
285315 f = f * (n1 - i + 1 ) * (k - i + 1 ) / (n2 - k + i ) / i ;
286316 } else if (m > ix ) {
287- for (i = ix + 1 ; i <= m ; i ++ )
317+ for (int i = ix + 1 ; i <= m ; i ++ )
288318 f = f * i * (n2 - k + i ) / (n1 - i + 1 ) / (k - i + 1 );
289319 }
320+ #ifdef DEBUG_rhyper
321+ REprintf (" small m or ix: f = %g\n" , f );
322+ #endif
290323 if (v <= f ) {
291324 reject = false;
292325 }
@@ -295,55 +328,50 @@ double rhyper(double nn1in, double nn2in, double kkin)
295328 const static double deltal = 0.0078 ;
296329 const static double deltau = 0.0034 ;
297330
298- double e , g , r , t , y ;
299- double de , dg , dr , ds , dt , gl , gu , nk , nm , ub ;
300- double xk , xm , xn , y1 , ym , yn , yk , alv ;
301-
302331#ifdef DEBUG_rhyper
303332 REprintf (" ... accept/reject 'large' case v=%g\n" , v );
304333#endif
305334 /* squeeze using upper and lower bounds */
306- y = ix ;
307- y1 = y + 1.0 ;
308- ym = y - m ;
309- yn = n1 - y + 1.0 ;
310- yk = k - y + 1.0 ;
311- nk = n2 - k + y1 ;
312- r = - ym / y1 ;
313- s = ym / yn ;
314- t = ym / yk ;
315- e = - ym / nk ;
316- g = yn * yk / (y1 * nk ) - 1.0 ;
317- dg = 1.0 ;
318- if (g < 0.0 )
319- dg = 1.0 + g ;
320- gu = g * (1.0 + g * (-0.5 + g / 3.0 ));
321- gl = gu - .25 * (g * g * g * g ) / dg ;
322- xm = m + 0.5 ;
323- xn = n1 - m + 0.5 ;
324- xk = k - m + 0.5 ;
325- nm = n2 - k + xm ;
326- ub = y * gu - m * gl + deltau
335+ double
336+ y = ix ,
337+ y1 = y + 1.0 ,
338+ ym = y - m ,
339+ yn = n1 - y + 1.0 ,
340+ yk = k - y + 1.0 ,
341+ nk = n2 - k + y1 ,
342+ r = - ym / y1 ,
343+ s = ym / yn ,
344+ t = ym / yk ,
345+ e = - ym / nk ,
346+ g = yn * yk / (y1 * nk ) - 1.0 ,
347+ dg = (g < 0.0 ) ? 1. + g : 1. ,
348+ gu = g * (1.0 + g * (-0.5 + g / 3.0 )),
349+ gl = gu - .25 * (g * g * g * g ) / dg ,
350+ xm = m + 0.5 ,
351+ xn = n1 - m + 0.5 ,
352+ xk = k - m + 0.5 ,
353+ nm = n2 - k + xm ,
354+ ub = y * gu - m * gl + deltau
327355 + xm * r * (1. + r * (-0.5 + r / 3.0 ))
328356 + xn * s * (1. + s * (-0.5 + s / 3.0 ))
329357 + xk * t * (1. + t * (-0.5 + t / 3.0 ))
330358 + nm * e * (1. + e * (-0.5 + e / 3.0 ));
331359 /* test against upper bound */
332- alv = log (v );
360+ double alv = log (v );
333361 if (alv > ub ) {
334362 reject = true;
335363 } else {
336- /* test against lower bound */
337- dr = xm * (r * r * r * r );
338- if (r < 0.0 )
364+ /* test against lower bound */
365+ double dr = xm * (r * r * r * r );
366+ if (r < 0. )
339367 dr /= (1.0 + r );
340- ds = xn * (s * s * s * s );
368+ double ds = xn * (s * s * s * s );
341369 if (s < 0.0 )
342370 ds /= (1.0 + s );
343- dt = xk * (t * t * t * t );
371+ double dt = xk * (t * t * t * t );
344372 if (t < 0.0 )
345373 dt /= (1.0 + t );
346- de = nm * (e * e * e * e );
374+ double de = nm * (e * e * e * e );
347375 if (e < 0.0 )
348376 de /= (1.0 + e );
349377 if (alv < ub - 0.25 * (dr + ds + dt + de )
@@ -361,9 +389,9 @@ double rhyper(double nn1in, double nn2in, double kkin)
361389 }
362390 }
363391 }
364- } // else
365- if ( reject )
366- goto L30 ;
392+ } // end{ III "large" }
393+
394+ } while ( reject ) ;
367395
368396 } // end{branch III}
369397
0 commit comments