diff --git a/CUtils/c_sources/rhyper.c b/CUtils/c_sources/rhyper.c
new file mode 100644
index 0000000000000000000000000000000000000000..b758f06dcfad1ba36d0d0b6f53485b6d1120e692
--- /dev/null
+++ b/CUtils/c_sources/rhyper.c
@@ -0,0 +1,341 @@
+#if 0
+/*
+ *  Mathlib : A C Library of Special Functions
+ *  Copyright (C) 1998 Ross Ihaka
+ *  Copyright (C) 2000-2012 The R Core Team
+ *  Copyright (C) 2005	The R Foundation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, a copy is available at
+ *  http://www.r-project.org/Licenses/
+ *
+ *  SYNOPSIS
+ *
+ *    #include <Rmath.h>
+ *    double rhyper(double NR, double NB, double n);
+ *
+ *  DESCRIPTION
+ *
+ *    Random variates from the hypergeometric distribution.
+ *    Returns the number of white balls drawn when kk balls
+ *    are drawn at random from an urn containing nn1 white
+ *    and nn2 black balls.
+ *
+ *  REFERENCE
+ *
+ *    V. Kachitvichyanukul and B. Schmeiser (1985).
+ *    ``Computer generation of hypergeometric random variates,''
+ *    Journal of Statistical Computation and Simulation 22, 127-145.
+ *
+ *    The original algorithm had a bug -- R bug report PR#7314 --
+ *    giving numbers slightly too small in case III h2pe
+ *    where (m < 100 || ix <= 50) , see below.
+ */
+
+#include "nmath.h"
+
+/* afc(i) :=  ln( i! )	[logarithm of the factorial i.
+ *	   If (i > 7), use Stirling's approximation, otherwise use table lookup.
+*/
+
+static double afc(int i)
+{
+    const static double al[9] =
+    {
+	0.0,
+	0.0,/*ln(0!)=ln(1)*/
+	0.0,/*ln(1!)=ln(1)*/
+	0.69314718055994530941723212145817,/*ln(2) */
+	1.79175946922805500081247735838070,/*ln(6) */
+	3.17805383034794561964694160129705,/*ln(24)*/
+	4.78749174278204599424770093452324,
+	6.57925121201010099506017829290394,
+	8.52516136106541430016553103634712
+	/*, 10.60460290274525022841722740072165*/
+    };
+    double di, value;
+
+    if (i < 0) {
+      MATHLIB_WARNING(("rhyper.c: afc(i), i=%d < 0 -- SHOULD NOT HAPPEN!\n"),
+		      i);
+      return -1;/* unreached (Wall) */
+    } else if (i <= 7) {
+	value = al[i + 1];
+    } else {
+	di = i;
+	value = (di + 0.5) * log(di) - di + 0.08333333333333 / di
+	    - 0.00277777777777 / di / di / di + 0.9189385332;
+    }
+    return value;
+}
+
+double rhyper(double nn1in, double nn2in, double kkin)
+{
+    const static double con = 57.56462733;
+    const static double deltal = 0.0078;
+    const static double deltau = 0.0034;
+    const static double scale = 1e25;
+
+    /* extern double afc(int); */
+
+    int nn1, nn2, kk;
+    int i, ix;
+    Rboolean reject, setup1, setup2;
+
+    double e, f, g, p, r, t, u, v, y;
+    double de, dg, dr, ds, dt, gl, gu, nk, nm, ub;
+    double xk, xm, xn, y1, ym, yn, yk, alv;
+
+    /* These should become `thread_local globals' : */
+    static int ks = -1;
+    static int n1s = -1, n2s = -1;
+
+    static int k, m;
+    static int minjx, maxjx, n1, n2;
+
+    static double a, d, s, w;
+    static double tn, xl, xr, kl, kr, lamdl, lamdr, p1, p2, p3;
+
+
+    /* check parameter validity */
+
+    if(!R_FINITE(nn1in) || !R_FINITE(nn2in) || !R_FINITE(kkin))
+	ML_ERR_return_NAN;
+
+    nn1 = (int) floor(nn1in+0.5);
+    nn2 = (int) floor(nn2in+0.5);
+    kk	= (int) floor(kkin +0.5);
+
+    if (nn1 < 0 || nn2 < 0 || kk < 0 || kk > nn1 + nn2)
+	ML_ERR_return_NAN;
+
+    /* if new parameter values, initialize */
+    reject = TRUE;
+    if (nn1 != n1s || nn2 != n2s) {
+	setup1 = TRUE;	setup2 = TRUE;
+    } else if (kk != ks) {
+	setup1 = FALSE;	setup2 = TRUE;
+    } else {
+	setup1 = FALSE;	setup2 = FALSE;
+    }
+    if (setup1) {
+	n1s = nn1;
+	n2s = nn2;
+	tn = nn1 + nn2;
+	if (nn1 <= nn2) {
+	    n1 = nn1;
+	    n2 = nn2;
+	} else {
+	    n1 = nn2;
+	    n2 = nn1;
+	}
+    }
+    if (setup2) {
+	ks = kk;
+	if (kk + kk >= tn) {
+	    k = (int)(tn - kk);
+	} else {
+	    k = kk;
+	}
+    }
+    if (setup1 || setup2) {
+	m = (int) ((k + 1.0) * (n1 + 1.0) / (tn + 2.0));
+	minjx = imax2(0, k - n2);
+	maxjx = imin2(n1, k);
+    }
+    /* generate random variate --- Three basic cases */
+
+    if (minjx == maxjx) { /* I: degenerate distribution ---------------- */
+	ix = maxjx;
+	/* return ix;
+	   No, need to unmangle <TSL>*/
+	/* return appropriate variate */
+
+	if (kk + kk >= tn) {
+	  if (nn1 > nn2) {
+	    ix = kk - nn2 + ix;
+	  } else {
+	    ix = nn1 - ix;
+	  }
+	} else {
+	  if (nn1 > nn2)
+	    ix = kk - ix;
+	}
+	return ix;
+
+    } else if (m - minjx < 10) { /* II: inverse transformation ---------- */
+	if (setup1 || setup2) {
+	    if (k < n2) {
+		w = exp(con + afc(n2) + afc(n1 + n2 - k)
+			- afc(n2 - k) - afc(n1 + n2));
+	    } else {
+		w = exp(con + afc(n1) + afc(k)
+			- afc(k - n2) - afc(n1 + n2));
+	    }
+	}
+      L10:
+	p = w;
+	ix = minjx;
+	u = unif_rand() * scale;
+      L20:
+	if (u > p) {
+	    u -= p;
+	    p *= (n1 - ix) * (k - ix);
+	    ix++;
+	    p = p / ix / (n2 - k + ix);
+	    if (ix > maxjx)
+		goto L10;
+	    goto L20;
+	}
+    } else { /* III : h2pe --------------------------------------------- */
+
+	if (setup1 || setup2) {
+	    s = sqrt((tn - k) * k * n1 * n2 / (tn - 1) / tn / tn);
+
+	    /* remark: d is defined in reference without int. */
+	    /* the truncation centers the cell boundaries at 0.5 */
+
+	    d = (int) (1.5 * s) + .5;
+	    xl = m - d + .5;
+	    xr = m + d + .5;
+	    a = afc(m) + afc(n1 - m) + afc(k - m) + afc(n2 - k + m);
+	    kl = exp(a - afc((int) (xl)) - afc((int) (n1 - xl))
+		     - afc((int) (k - xl))
+		     - afc((int) (n2 - k + xl)));
+	    kr = exp(a - afc((int) (xr - 1))
+		     - afc((int) (n1 - xr + 1))
+		     - afc((int) (k - xr + 1))
+		     - afc((int) (n2 - k + xr - 1)));
+	    lamdl = -log(xl * (n2 - k + xl) / (n1 - xl + 1) / (k - xl + 1));
+	    lamdr = -log((n1 - xr + 1) * (k - xr + 1) / xr / (n2 - k + xr));
+	    p1 = d + d;
+	    p2 = p1 + kl / lamdl;
+	    p3 = p2 + kr / lamdr;
+	}
+      L30:
+	u = unif_rand() * p3;
+	v = unif_rand();
+	if (u < p1) {		/* rectangular region */
+	    ix = (int) (xl + u);
+	} else if (u <= p2) {	/* left tail */
+	    ix = (int) (xl + log(v) / lamdl);
+	    if (ix < minjx)
+		goto L30;
+	    v = v * (u - p1) * lamdl;
+	} else {		/* right tail */
+	    ix = (int) (xr - log(v) / lamdr);
+	    if (ix > maxjx)
+		goto L30;
+	    v = v * (u - p2) * lamdr;
+	}
+
+	/* acceptance/rejection test */
+
+	if (m < 100 || ix <= 50) {
+	    /* explicit evaluation */
+	    /* The original algorithm (and TOMS 668) have
+		   f = f * i * (n2 - k + i) / (n1 - i) / (k - i);
+	       in the (m > ix) case, but the definition of the
+	       recurrence relation on p134 shows that the +1 is
+	       needed. */
+	    f = 1.0;
+	    if (m < ix) {
+		for (i = m + 1; i <= ix; i++)
+		    f = f * (n1 - i + 1) * (k - i + 1) / (n2 - k + i) / i;
+	    } else if (m > ix) {
+		for (i = ix + 1; i <= m; i++)
+		    f = f * i * (n2 - k + i) / (n1 - i + 1) / (k - i + 1);
+	    }
+	    if (v <= f) {
+		reject = FALSE;
+	    }
+	} else {
+	    /* squeeze using upper and lower bounds */
+	    y = ix;
+	    y1 = y + 1.0;
+	    ym = y - m;
+	    yn = n1 - y + 1.0;
+	    yk = k - y + 1.0;
+	    nk = n2 - k + y1;
+	    r = -ym / y1;
+	    s = ym / yn;
+	    t = ym / yk;
+	    e = -ym / nk;
+	    g = yn * yk / (y1 * nk) - 1.0;
+	    dg = 1.0;
+	    if (g < 0.0)
+		dg = 1.0 + g;
+	    gu = g * (1.0 + g * (-0.5 + g / 3.0));
+	    gl = gu - .25 * (g * g * g * g) / dg;
+	    xm = m + 0.5;
+	    xn = n1 - m + 0.5;
+	    xk = k - m + 0.5;
+	    nm = n2 - k + xm;
+	    ub = y * gu - m * gl + deltau
+		+ xm * r * (1. + r * (-0.5 + r / 3.0))
+		+ xn * s * (1. + s * (-0.5 + s / 3.0))
+		+ xk * t * (1. + t * (-0.5 + t / 3.0))
+		+ nm * e * (1. + e * (-0.5 + e / 3.0));
+	    /* test against upper bound */
+	    alv = log(v);
+	    if (alv > ub) {
+		reject = TRUE;
+	    } else {
+				/* test against lower bound */
+		dr = xm * (r * r * r * r);
+		if (r < 0.0)
+		    dr /= (1.0 + r);
+		ds = xn * (s * s * s * s);
+		if (s < 0.0)
+		    ds /= (1.0 + s);
+		dt = xk * (t * t * t * t);
+		if (t < 0.0)
+		    dt /= (1.0 + t);
+		de = nm * (e * e * e * e);
+		if (e < 0.0)
+		    de /= (1.0 + e);
+		if (alv < ub - 0.25 * (dr + ds + dt + de)
+		    + (y + m) * (gl - gu) - deltal) {
+		    reject = FALSE;
+		}
+		else {
+		    /* * Stirling's formula to machine accuracy
+		     */
+		    if (alv <= (a - afc(ix) - afc(n1 - ix)
+				- afc(k - ix) - afc(n2 - k + ix))) {
+			reject = FALSE;
+		    } else {
+			reject = TRUE;
+		    }
+		}
+	    }
+	}
+	if (reject)
+	    goto L30;
+    }
+
+    /* return appropriate variate */
+
+    if (kk + kk >= tn) {
+	if (nn1 > nn2) {
+	    ix = kk - nn2 + ix;
+	} else {
+	    ix = nn1 - ix;
+	}
+    } else {
+	if (nn1 > nn2)
+	    ix = kk - ix;
+    }
+    return ix;
+}
+#endif