diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java
index e95c7189cd7745d5022597c190f60ff0c973b1bc..9ba8e64a12ac14fa2575067e12d4dc4b878b8eec 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java
@@ -18,22 +18,22 @@ import static com.oracle.truffle.r.library.stats.StatsUtil.fmax2;
 import static com.oracle.truffle.r.library.stats.StatsUtil.fmin2;
 
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
-import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
 
 public final class RBeta implements RandFunction2_Double {
 
     private static final double expmax = (DBL_MAX_EXP * M_LN2); /* = log(DBL_MAX) */
 
     @Override
-    public double evaluate(double aa, double bb, RandomNumberGenerator rand) {
+    public double evaluate(double aa, double bb, RandomNumberProvider rand) {
         if (Double.isNaN(aa) || Double.isNaN(bb) || aa < 0. || bb < 0.) {
-            StatsUtil.mlError();
+            return StatsUtil.mlError();
         }
         if (!Double.isFinite(aa) && !Double.isFinite(bb)) { // a = b = Inf : all mass at 1/2
             return 0.5;
         }
         if (aa == 0. && bb == 0.) { // point mass 1/2 at each of {0,1} :
-            return (rand.genrandDouble() < 0.5) ? 0. : 1.;
+            return (rand.unifRand() < 0.5) ? 0. : 1.;
         }
         // now, at least one of a, b is finite and positive
         if (!Double.isFinite(aa) || bb == 0.) {
@@ -54,14 +54,15 @@ public final class RBeta implements RandFunction2_Double {
         double w = 0;
         double y;
         double z;
-        double olda = -1.0;
-        double oldb = -1.0;
 
+        // TODO: state variables
         double beta = 0;
         double gamma = 1;
         double delta;
         double k1 = 0;
         double k2 = 0;
+        double olda = -1.0;
+        double oldb = -1.0;
 
         /* Test if we need new "initializing" */
         boolean qsame = (olda == aa) && (oldb == bb);
@@ -84,8 +85,8 @@ public final class RBeta implements RandFunction2_Double {
             }
             /* FIXME: "do { } while()", but not trivially because of "continue"s: */
             for (;;) {
-                u1 = rand.genrandDouble();
-                u2 = rand.genrandDouble();
+                u1 = rand.unifRand();
+                u2 = rand.unifRand();
                 if (u1 < 0.5) {
                     y = u1 * u2;
                     z = u1 * y;
@@ -120,8 +121,8 @@ public final class RBeta implements RandFunction2_Double {
                 gamma = a + 1.0 / beta;
             }
             do {
-                u1 = rand.genrandDouble();
-                u2 = rand.genrandDouble();
+                u1 = rand.unifRand();
+                u2 = rand.unifRand();
 
                 v = beta * Math.log(u1 / (1.0 - u1));
                 w = wFromU1Bet(a, v, w);
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java
index 5cd94ab53398bc96da43415388b6f59079046f55..accf46e7c246e8914ab9075568984edbe7194507 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java
@@ -14,18 +14,18 @@ package com.oracle.truffle.r.library.stats;
 import static com.oracle.truffle.r.library.stats.MathConstants.M_PI;
 
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
-import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
 
 public final class RCauchy implements RandFunction2_Double {
     @Override
-    public double evaluate(double location, double scale, RandomNumberGenerator rand) {
+    public double evaluate(double location, double scale, RandomNumberProvider rand) {
         if (Double.isNaN(location) || !Double.isFinite(scale) || scale < 0) {
             return StatsUtil.mlError();
         }
         if (scale == 0. || !Double.isFinite(location)) {
             return location;
         } else {
-            return location + scale * Math.tan(M_PI * rand.genrandDouble());
+            return location + scale * Math.tan(M_PI * rand.unifRand());
         }
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java
new file mode 100644
index 0000000000000000000000000000000000000000..0e8581b5035469b7af5bc26d512b224447bf5dfd
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java
@@ -0,0 +1,207 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 1998--2008, The R Core Team
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import static com.oracle.truffle.r.library.stats.TOMS708.fabs;
+
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
+
+public class RGamma implements RandFunction2_Double {
+    private static final double sqrt32 = 5.656854;
+    private static final double exp_m1 = 0.36787944117144232159; /* exp(-1) = 1/e */
+
+    /*
+     * Coefficients q[k] - for q0 = sum(q[k]*a^(-k)) Coefficients a[k] - for q =
+     * q0+(t*t/2)*sum(a[k]*v^k) Coefficients e[k] - for exp(q)-1 = sum(e[k]*q^k)
+     */
+    private static final double q1 = 0.04166669;
+    private static final double q2 = 0.02083148;
+    private static final double q3 = 0.00801191;
+    private static final double q4 = 0.00144121;
+    private static final double q5 = -7.388e-5;
+    private static final double q6 = 2.4511e-4;
+    private static final double q7 = 2.424e-4;
+
+    private static final double a1 = 0.3333333;
+    private static final double a2 = -0.250003;
+    private static final double a3 = 0.2000062;
+    private static final double a4 = -0.1662921;
+    private static final double a5 = 0.1423657;
+    private static final double a6 = -0.1367177;
+    private static final double a7 = 0.1233795;
+
+    @Override
+    public double evaluate(double a, double scale, RandomNumberProvider rand) {
+
+        // TODO: state variables
+        double aa = 0.;
+        double aaa = 0.;
+        double s = 0;
+        double s2 = 0;
+        double d = 0; /* no. 1 (step 1) */
+        double q0 = 0;
+        double b = 0;
+        double si = 0;
+        double c = 0; /* no. 2 (step 4) */
+
+        double e;
+        double p;
+        double q;
+        double r;
+        double t;
+        double u;
+        double v;
+        double w;
+        double x;
+        double retVal;
+
+        if (Double.isNaN(a) || Double.isNaN(scale)) {
+            return StatsUtil.mlError();
+        }
+        if (a <= 0.0 || scale <= 0.0) {
+            if (scale == 0. || a == 0.) {
+                return 0.;
+            }
+            return StatsUtil.mlError();
+        }
+        if (!Double.isFinite(a) || !Double.isFinite(scale)) {
+            return Double.POSITIVE_INFINITY;
+        }
+
+        if (a < 1.) { /* GS algorithm for parameters a < 1 */
+            e = 1.0 + exp_m1 * a;
+            while (true) {
+                p = e * rand.unifRand();
+                if (p >= 1.0) {
+                    x = -Math.log((e - p) / a);
+                    if (rand.expRand() >= (1.0 - a) * Math.log(x)) {
+                        break;
+                    }
+                } else {
+                    x = Math.exp(Math.log(p) / a);
+                    if (rand.expRand() >= x) {
+                        break;
+                    }
+                }
+            }
+            return scale * x;
+        }
+
+        /* --- a >= 1 : GD algorithm --- */
+
+        /* Step 1: Recalculations of s2, s, d if a has changed */
+        if (a != aa) {
+            aa = a;
+            s2 = a - 0.5;
+            s = Math.sqrt(s2);
+            d = sqrt32 - s * 12.0;
+        }
+        /*
+         * Step 2: t = standard normal deviate, x = (s,1/2) -normal deviate.
+         */
+
+        /* immediate acceptance (i) */
+        t = rand.normRand();
+        x = s + 0.5 * t;
+        retVal = x * x;
+        if (t >= 0.0) {
+            return scale * retVal;
+        }
+
+        /* Step 3: u = 0,1 - uniform sample. squeeze acceptance (s) */
+        u = rand.unifRand();
+        if (d * u <= Math.pow(t, 3)) {
+            return scale * retVal;
+        }
+
+        /* Step 4: recalculations of q0, b, si, c if necessary */
+
+        if (a != aaa) {
+            aaa = a;
+            r = 1.0 / a;
+            q0 = ((((((q7 * r + q6) * r + q5) * r + q4) * r + q3) * r + q2) * r + q1) * r;
+
+            /* Approximation depending on size of parameter a */
+            /* The constants in the expressions for b, si and c */
+            /* were established by numerical experiments */
+
+            if (a <= 3.686) {
+                b = 0.463 + s + 0.178 * s2;
+                si = 1.235;
+                c = 0.195 / s - 0.079 + 0.16 * s;
+            } else if (a <= 13.022) {
+                b = 1.654 + 0.0076 * s2;
+                si = 1.68 / s + 0.275;
+                c = 0.062 / s + 0.024;
+            } else {
+                b = 1.77;
+                si = 0.75;
+                c = 0.1515 / s;
+            }
+        }
+        /* Step 5: no quotient test if x not positive */
+
+        if (x > 0.0) {
+            /* Step 6: calculation of v and quotient q */
+            v = t / (s + s);
+            if (fabs(v) <= 0.25) {
+                q = q0 + 0.5 * t * t * ((((((a7 * v + a6) * v + a5) * v + a4) * v + a3) * v + a2) * v + a1) * v;
+            } else {
+                q = q0 - s * t + 0.25 * t * t + (s2 + s2) * Math.log(1.0 + v);
+            }
+
+            /* Step 7: quotient acceptance (q) */
+            if (Math.log(1.0 - u) <= q) {
+                return scale * retVal;
+            }
+        }
+
+        while (true) {
+            /*
+             * Step 8: e = standard exponential deviate u = 0,1 -uniform deviate t = (b,si)-double
+             * exponential (laplace) sample
+             */
+            e = rand.expRand();
+            u = rand.unifRand();
+            u = u + u - 1.0;
+            if (u < 0.0) {
+                t = b - si * e;
+            } else {
+                t = b + si * e;
+            }
+            /* Step 9: rejection if t < tau(1) = -0.71874483771719 */
+            if (t >= -0.71874483771719) {
+                /* Step 10: calculation of v and quotient q */
+                v = t / (s + s);
+                if (fabs(v) <= 0.25) {
+                    q = q0 + 0.5 * t * t *
+                                    ((((((a7 * v + a6) * v + a5) * v + a4) * v + a3) * v + a2) * v + a1) * v;
+                } else {
+                    q = q0 - s * t + 0.25 * t * t + (s2 + s2) * Math.log(1.0 + v);
+                }
+                /* Step 11: hat acceptance (h) */
+                /* (if q not positive go to step 8) */
+                if (q > 0.0) {
+                    w = StatsUtil.expm1(q);
+                    /* ^^^^^ original code had approximation with rel.err < 2e-7 */
+                    /* if t is rejected sample again at step 8 */
+                    if (c * fabs(u) <= w * Math.exp(e - 0.5 * t * t)) {
+                        break;
+                    }
+                }
+            }
+        } /* repeat .. until `t' is accepted */
+        x = s + 0.5 * t;
+        return scale * x * x;
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandGenerationFunctions.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandGenerationFunctions.java
index f0381ccb39d6e3c3a24b978d359775034b67a8ad..733f8f8b97449acb57f0c39504b63e914afcc7f5 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandGenerationFunctions.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandGenerationFunctions.java
@@ -39,6 +39,7 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractVector;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.rng.RRNG;
+import com.oracle.truffle.r.runtime.rng.RRNG.NormKind;
 import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
 
 public final class RandGenerationFunctions {
@@ -48,23 +49,45 @@ public final class RandGenerationFunctions {
         // static class
     }
 
+    public static final class RandomNumberProvider {
+        private final RandomNumberGenerator generator;
+        private final NormKind normKind;
+
+        public RandomNumberProvider(RandomNumberGenerator generator, NormKind normKind) {
+            this.generator = generator;
+            this.normKind = normKind;
+        }
+
+        public double unifRand() {
+            return generator.genrandDouble();
+        }
+
+        public double normRand() {
+            return SNorm.normRand(generator, normKind);
+        }
+
+        public double expRand() {
+            return SExp.expRand(generator);
+        }
+    }
+
     // inspired by the DEFRAND{X}_REAL and DEFRAND{X}_INT macros in GnuR
 
     public interface RandFunction3_Int {
-        int evaluate(double a, double b, double c, RandomNumberGenerator rand);
+        int evaluate(double a, double b, double c, RandomNumberProvider rand);
     }
 
     public interface RandFunction2_Int extends RandFunction3_Int {
         @Override
-        default int evaluate(double a, double b, double c, RandomNumberGenerator rand) {
+        default int evaluate(double a, double b, double c, RandomNumberProvider rand) {
             return evaluate(a, b, rand);
         }
 
-        int evaluate(double a, double b, RandomNumberGenerator rand);
+        int evaluate(double a, double b, RandomNumberProvider rand);
     }
 
     public interface RandFunction2_Double {
-        double evaluate(double a, double b, RandomNumberGenerator rand);
+        double evaluate(double a, double b, RandomNumberProvider rand);
     }
 
     static final class RandGenerationProfiles {
@@ -73,15 +96,20 @@ public final class RandGenerationFunctions {
         final VectorLengthProfile resultVectorLengthProfile = VectorLengthProfile.create();
         final LoopConditionProfile loopConditionProfile = LoopConditionProfile.createCountingProfile();
         final ValueProfile randClassProfile = ValueProfile.createClassProfile();
+        final ValueProfile normKindProfile = ValueProfile.createEqualityProfile();
 
         public static RandGenerationProfiles create() {
             return new RandGenerationProfiles();
         }
+
+        public RandomNumberProvider createRandProvider() {
+            return new RandomNumberProvider(randClassProfile.profile(RRNG.currentGenerator()), normKindProfile.profile(RRNG.currentNormKind()));
+        }
     }
 
     private static RAbstractIntVector evaluate3Int(Node node, RandFunction3_Int function, int lengthIn, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c,
                     RandGenerationProfiles profiles) {
-        int length = profiles.resultVectorLengthProfile.profile(lengthIn);
+        int length = lengthIn;
         int aLength = a.getLength();
         int bLength = b.getLength();
         int cLength = c.getLength();
@@ -93,11 +121,12 @@ public final class RandGenerationFunctions {
             return RDataFactory.createIntVector(nansResult, false);
         }
 
+        length = profiles.resultVectorLengthProfile.profile(length);
         RNode.reportWork(node, length);
         boolean nans = false;
         int[] result = new int[length];
         RRNG.getRNGState();
-        RandomNumberGenerator rand = profiles.randClassProfile.profile(RRNG.currentGenerator());
+        RandomNumberProvider rand = profiles.createRandProvider();
         for (int i = 0; profiles.loopConditionProfile.inject(i < length); i++) {
             double aValue = a.getDataAt(i % aLength);
             double bValue = b.getDataAt(i % bLength);
@@ -117,21 +146,22 @@ public final class RandGenerationFunctions {
     }
 
     private static RAbstractDoubleVector evaluate2Double(Node node, RandFunction2_Double function, int lengthIn, RAbstractDoubleVector a, RAbstractDoubleVector b, RandGenerationProfiles profiles) {
-        int length = profiles.resultVectorLengthProfile.profile(lengthIn);
+        int length = lengthIn;
         int aLength = a.getLength();
         int bLength = b.getLength();
         if (aLength == 0 || bLength == 0) {
             profiles.nanResult.enter();
-            RError.warning(SHOW_CALLER, RError.Message.NAN_PRODUCED);
+            RError.warning(SHOW_CALLER, RError.Message.NA_PRODUCED);
             return createVectorOf(length, RRuntime.DOUBLE_NA);
         }
 
+        length = profiles.resultVectorLengthProfile.profile(length);
         RNode.reportWork(node, length);
         boolean nans = false;
         double[] result;
         result = new double[length];
         RRNG.getRNGState();
-        RandomNumberGenerator rand = profiles.randClassProfile.profile(RRNG.currentGenerator());
+        RandomNumberProvider rand = profiles.createRandProvider();
         for (int i = 0; profiles.loopConditionProfile.inject(i < length); i++) {
             double aValue = a.getDataAt(i % aLength);
             double bValue = b.getDataAt(i % bLength);
@@ -168,7 +198,7 @@ public final class RandGenerationFunctions {
                         @Cached("createNonPreserving()") CastIntegerNode castNode,
                         @Cached("create()") BranchProfile seenNA) {
             int result = ((RAbstractIntVector) castNode.execute(vector)).getDataAt(0);
-            if (RRuntime.isNA(result)) {
+            if (RRuntime.isNA(result) || result < 0) {
                 seenNA.enter();
                 throw RError.error(SHOW_CALLER, INVALID_UNNAMED_ARGUMENTS);
             }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rbinom.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rbinom.java
index 5fe4514576b2765ade7665cf488fa7ceb46199f2..c63e7e44f3249f3bdd66e7595efa23d543fa2ff8 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rbinom.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rbinom.java
@@ -13,8 +13,8 @@
 package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Int;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
 
 // transcribed from rbinom.c
 
@@ -22,12 +22,8 @@ public final class Rbinom implements RandFunction2_Int {
 
     private final Qbinom qbinom = new Qbinom();
 
-    private static double unifRand(RandomNumberGenerator rand) {
-        return rand.genrandDouble();
-    }
-
     @Override
-    public int evaluate(double nin, double pp, RandomNumberGenerator rand) {
+    public int evaluate(double nin, double pp, RandomNumberProvider rand) {
         double psave = -1.0;
         int nsave = -1;
 
@@ -54,7 +50,7 @@ public final class Rbinom implements RandFunction2_Int {
             /*
              * evade integer overflow, and r == INT_MAX gave only even values
              */
-            return (int) qbinom.evaluate(unifRand(rand), r, pp, /* lower_tail */false, /* log_p */false);
+            return (int) qbinom.evaluate(rand.unifRand(), r, pp, /* lower_tail */false, /* log_p */false);
         }
         /* else */
         int n = (int) r;
@@ -135,8 +131,8 @@ public final class Rbinom implements RandFunction2_Int {
 
                 /*-------------------------- np = n*p >= 30 : ------------------- */
                 while (true) {
-                    u = unifRand(rand) * p4;
-                    v = unifRand(rand);
+                    u = rand.unifRand() * p4;
+                    v = rand.unifRand();
                     /* triangular region */
                     if (u <= p1) {
                         ix = (int) (xm - p1 * v + u);
@@ -223,7 +219,7 @@ public final class Rbinom implements RandFunction2_Int {
             while (true) {
                 ix = 0;
                 f = qn;
-                u = unifRand(rand);
+                u = rand.unifRand();
                 while (true) {
                     if (u < f) {
                         // goto finis;
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java
index 5fd5a252462c5aac511252763505a7aa25279e60..24f2aed7d53b9d6f82635bec1bb53b441f4daa9b 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Rnorm.java
@@ -12,17 +12,18 @@
 package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
-import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
 
 public final class Rnorm implements RandFunction2_Double {
-
-    private static final double BIG = 134217728;
-
     @Override
-    public double evaluate(double mu, double sigma, RandomNumberGenerator rand) {
-        // TODO: GnuR invokes norm_rand to get "rand"
-        double u1 = (int) (BIG * rand.genrandDouble()) + rand.genrandDouble();
-        double random = Random2.qnorm5(u1 / BIG, 0.0, 1.0, true, false);
-        return random * sigma + mu;
+    public double evaluate(double mu, double sigma, RandomNumberProvider rand) {
+        if (Double.isNaN(mu) || !Double.isFinite(sigma) || sigma < 0.) {
+            return StatsUtil.mlError();
+        }
+        if (sigma == 0. || !Double.isFinite(mu)) {
+            return mu; /* includes mu = +/- Inf with finite sigma */
+        } else {
+            return mu + sigma * rand.normRand();
+        }
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java
index 39cf514eec0c8fc57f225a99e9c90ccb72370ec0..57a877536fa532404eb5899b115ba11e4c812043 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Runif.java
@@ -23,15 +23,18 @@
 package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandomNumberProvider;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
 
 public final class Runif implements RandFunction2_Double {
     @Override
-    public double evaluate(double min, double max, RandomNumberGenerator rand) {
+    public double evaluate(double min, double max, RandomNumberProvider rand) {
         if (!RRuntime.isFinite(min) || !RRuntime.isFinite(max) || max < min) {
             return StatsUtil.mlError();
         }
-        return min + rand.genrandDouble() * (max - min);
+        if (min == max) {
+            return min;
+        }
+        return min + rand.unifRand() * (max - min);
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SExp.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SExp.java
new file mode 100644
index 0000000000000000000000000000000000000000..924bbf783c4fd9c35c6caef2ab52e4bf660ef859
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SExp.java
@@ -0,0 +1,81 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 1998--2008, The R Core Team
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
+import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
+
+/**
+ * Generation of random value from standard exponential distribution. Corresponds to {@code sexp.c}
+ * in GnuR.
+ */
+public final class SExp {
+    private SExp() {
+        // only static members
+    }
+
+    /* q[k-1] = sum(log(2)^k / k!) k=1,..,n, */
+    /* The highest n (here 16) is determined by q[n-1] = 1.0 */
+    /* within standard precision */
+    @CompilationFinal(dimensions = 1) private static final double[] q = {
+                    0.6931471805599453,
+                    0.9333736875190459,
+                    0.9888777961838675,
+                    0.9984959252914960,
+                    0.9998292811061389,
+                    0.9999833164100727,
+                    0.9999985691438767,
+                    0.9999998906925558,
+                    0.9999999924734159,
+                    0.9999999995283275,
+                    0.9999999999728814,
+                    0.9999999999985598,
+                    0.9999999999999289,
+                    0.9999999999999968,
+                    0.9999999999999999,
+                    1.0000000000000000
+    };
+
+    public static double expRand(RandomNumberGenerator generator) {
+        double a = 0.;
+        // precaution if u = 0 is ever returned
+        double u = generator.genrandDouble();
+        while (u <= 0. || u >= 1.) {
+            u = generator.genrandDouble();
+        }
+
+        for (;;) {
+            u += u;
+            if (u > 1.) {
+                break;
+            }
+            a += q[0];
+        }
+        u -= 1.;
+
+        if (u <= q[0]) {
+            return a + u;
+        }
+
+        int i = 0;
+        double ustar = generator.genrandDouble();
+        double umin = ustar;
+        do {
+            ustar = generator.genrandDouble();
+            if (umin > ustar) {
+                umin = ustar;
+            }
+            i++;
+        } while (u > q[i]);
+        return a + umin * q[0];
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SNorm.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SNorm.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f6737a37571d2144c6858be57453fcbac413ec8
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SNorm.java
@@ -0,0 +1,40 @@
+/*
+ * This material is distributed under the GNU General Public License
+ * Version 2. You may review the terms of this license at
+ * http://www.gnu.org/licenses/gpl-2.0.html
+ *
+ * Copyright (C) 1998 Ross Ihaka
+ * Copyright (c) 1998--2008, The R Core Team
+ * Copyright (c) 2016, 2016, Oracle and/or its affiliates
+ *
+ * All rights reserved.
+ */
+package com.oracle.truffle.r.library.stats;
+
+import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.rng.RRNG.NormKind;
+import com.oracle.truffle.r.runtime.rng.RandomNumberGenerator;
+
+/**
+ * Generation of random value from standard normal distribution N(0,1). Corresponds to
+ * {@code snorm.c} in GnuR.
+ */
+public final class SNorm {
+    private SNorm() {
+        // only static members
+    }
+
+    // TODO: implement other normKinds
+
+    private static final double BIG = 134217728; /* 2^27 */
+
+    public static double normRand(RandomNumberGenerator rand, NormKind normKind) {
+        if (normKind != NormKind.INVERSION) {
+            throw RError.nyi(null, "unifNorm(): no other NormKind than the default INVERSION is implemented");
+        }
+        /* unif_rand() alone is not of high enough precision */
+        double u1 = rand.genrandDouble();
+        u1 = (int) (BIG * u1) + rand.genrandDouble();
+        return Random2.qnorm5(u1 / BIG, 0.0, 1.0, true, false);
+    }
+}
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java
index d1ddd7ab798fad0019530278e8c1fb32355175a2..a61e44b42201c5c5af425fa83c95fd84718d8e8f 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java
@@ -67,7 +67,7 @@ public class TOMS708 {
         return Math.exp(v);
     }
 
-    private static double fabs(double v) {
+    public static double fabs(double v) {
         return Math.abs(v);
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
index 78711bb74f4d359f21ad84a4ee3cb0920b671b67..388be65497adda69afdb59679e4479668c23f0f5 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/foreign/ForeignFunctions.java
@@ -56,6 +56,7 @@ import com.oracle.truffle.r.library.stats.Qbinom;
 import com.oracle.truffle.r.library.stats.Qnorm;
 import com.oracle.truffle.r.library.stats.RBeta;
 import com.oracle.truffle.r.library.stats.RCauchy;
+import com.oracle.truffle.r.library.stats.RGamma;
 import com.oracle.truffle.r.library.stats.RandGenerationFunctionsFactory;
 import com.oracle.truffle.r.library.stats.Rbinom;
 import com.oracle.truffle.r.library.stats.Rnorm;
@@ -370,6 +371,8 @@ public class ForeignFunctions {
                     return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new Runif());
                 case "rbeta":
                     return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new RBeta());
+                case "rgamma":
+                    return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new RGamma());
                 case "rcauchy":
                     return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new RCauchy());
                 case "qgamma":
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
index 33103290487d5e45ef00062deac549ec1edb093d..28b845bc33c215403cf214cfd2a27a4a58ff08e1 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RRNG.java
@@ -197,7 +197,7 @@ public class RRNG {
         return getContextState().currentGenerator;
     }
 
-    private static NormKind currentNormKind() {
+    public static NormKind currentNormKind() {
         return getContextState().currentNormKind;
     }
 
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 3043028d705efe1ff3e2eb9914fb6aae55dbbea2..a2de816f0c240b28945dbaac017e02f3a702cbd5 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -111074,16 +111074,6 @@ Error: 'x' is NULL
 Warning message:
 In qgamma(10, 1) : NaNs produced
 
-##com.oracle.truffle.r.test.library.stats.TestExternal_rbeta.testRbeta#
-#set.seed(42); rbeta(10, 10, 10)
- [1] 0.4282247 0.5459560 0.5805863 0.5512005 0.4866080 0.6987626 0.4880555
- [8] 0.7691043 0.4920874 0.6702352
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rbeta.testRbeta#
-#set.seed(42); rbeta(10, c(0.1, 2:10), c(0.1, 0.5, 0.9, 3:5))
- [1] 0.002930982 0.969019187 0.872817723 0.593769928 0.260911852 0.561458988
- [7] 1.000000000 0.929063923 0.991793861 0.914489454
-
 ##com.oracle.truffle.r.test.library.stats.TestExternal_rbinom.testRbinom#
 #set.seed(42); rbinom('10', 10, 0.5)
  [1] 7 7 4 7 6 5 6 3 6 6
@@ -111110,63 +111100,6 @@ In rbinom("aa", 10, 0.5) : NAs introduced by coercion
 #set.seed(42); rbinom(c(1,2), 11:12, c(0.1, 0.5, 0.9))
 [1] 3 9
 
-##com.oracle.truffle.r.test.library.stats.TestExternal_rcauchy.testRcauchy#
-#set.seed(42); rcauchy(10, 10, -1)
- [1] NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
-Warning message:
-In rcauchy(10, 10, -1) : NAs produced
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rcauchy.testRcauchy#
-#set.seed(42); rcauchy(10, 10, 10)
- [1]    7.2577591    7.9970061   22.5740275    4.1049817  -10.9520771
- [6] -156.4897232   -0.8802923   14.5025696   -8.6041975   -3.3131055
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rcauchy.testRcauchy#
-#set.seed(42); rcauchy(10, NaN, 10)
- [1] NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN
-Warning message:
-In rcauchy(10, NaN, 10) : NAs produced
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rnorm.testRnorm#
-#set.seed(42); rnorm('10', 10, 5)
- [1] 16.854792  7.176509 11.815642 13.164313 12.021342  9.469377 17.557610
- [8]  9.526705 20.092119  9.686430
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rnorm.testRnorm#Output.IgnoreWarningContext#
-#set.seed(42); rnorm('aa', 10, 0.5)
-Error in rnorm("aa", 10, 0.5) : invalid arguments
-In addition: Warning message:
-In rnorm("aa", 10, 0.5) : NAs introduced by coercion
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rnorm.testRnorm#
-#set.seed(42); rnorm(10, 10, 10)
- [1] 23.709584  4.353018 13.631284 16.328626 14.042683  8.938755 25.115220
- [8]  9.053410 30.184237  9.372859
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rnorm.testRnorm#
-#set.seed(42); rnorm(10, 2:10, c(0.1, 0.5, 0.9))
- [1]  2.137096  2.717651  4.326816  5.063286  6.202134  6.904488  8.151152
- [8]  8.952670 11.816581  1.993729
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rnorm.testRnorm#
-#set.seed(42); rnorm(1:10, 2:10, c(0.1, 0.5, 0.9))
- [1]  2.137096  2.717651  4.326816  5.063286  6.202134  6.904488  8.151152
- [8]  8.952670 11.816581  1.993729
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_rnorm.testRnorm#
-#set.seed(42); rnorm(c(1,2), 11:12, c(0.1, 0.5, 0.9))
-[1] 11.13710 11.71765
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_runif.testRunif#
-#set.seed(1); runif(5);
-[1] 0.2655087 0.3721239 0.5728534 0.9082078 0.2016819
-
-##com.oracle.truffle.r.test.library.stats.TestExternal_runif.testRunif#
-#set.seed(1); runif(5, 10, 2.5);
-[1] NaN NaN NaN NaN NaN
-Warning message:
-In runif(5, 10, 2.5) : NAs produced
-
 ##com.oracle.truffle.r.test.library.stats.TestFitting.testLm#Output.IgnoreWhitespace#
 #y <- c(26.55, 37.21, 57.28, 90.82, 20.16, 89.838, 94.46, 20.5, 17.6, 68.7, 38.41, 76.9, 49.7, 71, 99.19, 16); x <- c(26.55, 37.21, 57.28, 90.82, 20.16, 89.838, 94.46, 20.5, 17.6, 68.7, 38.41, 76.9, 49.7, 71, 99.19, 16); res <- lm(y~x); print(res$coefficients);print(res$fitted.values);print(res$xlevels);print(res$residuals);print(res$assign);print(res$effects);print(res$qr$qr);print(res$rank);print(res$model);
   (Intercept)             x
@@ -113519,6 +113452,115 @@ $variables
 list(y, z)
 
 
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rbeta(10, 10, 10)
+ [1] 0.4202441 0.5231868 0.3929161 0.7104015 0.5416782 0.3949132 0.5618393
+ [8] 0.5943116 0.5732049 0.4613867
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rbeta(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0))
+ [1] NaN NaN NaN NaN NaN NaN NaN   0 NaN NaN NaN NaN
+Warning message:
+In rbeta(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rbeta(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3))
+ [1]        NaN 0.00000000 1.00000000 0.82338531 0.17213601        NaN
+ [7] 1.00000000        NaN 0.00000000 0.06525112        NaN 1.00000000
+[13] 0.99955874 0.92371833        NaN        NaN 1.00000000 0.99409008
+[19] 0.93534230 0.58348863
+Warning message:
+In rbeta(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rgamma(10, 10, 10)
+ [1] 0.7667251 1.4040808 1.3826660 1.0820993 0.5346417 1.1061754 1.1911950
+ [8] 1.1357558 0.8582045 0.7196892
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rgamma(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0))
+ [1] NaN NaN NaN NaN NaN NaN NaN   0 NaN NaN NaN NaN
+Warning message:
+In rgamma(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rgamma(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3))
+ [1]         NaN  0.00000000  0.01881730  1.92594160  0.45110798         NaN
+ [7]         Inf         NaN  0.00000000  0.05989429         NaN         Inf
+[13] 62.08824595  6.89167118         NaN  0.00000000         Inf 22.88066299
+[19]  2.26717120  0.72159817
+Warning message:
+In rgamma(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rnorm(10, 10, 10)
+ [1]  3.735462 11.836433  1.643714 25.952808 13.295078  1.795316 14.874291
+ [8] 17.383247 15.757814  6.946116
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rnorm(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0))
+ [1] NaN NaN NaN NaN NaN NaN NaN   0 NaN NaN NaN NaN
+Warning message:
+In rnorm(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); rnorm(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3))
+ [1]        NaN  0.0000000  0.1373546  2.1652790  0.4931142        NaN
+ [7]  5.0000000 -0.8404719  0.2965570 -2.2614052        NaN  3.0000000
+[13]  4.0487429  5.6644922  0.7273441        NaN  0.2000000  1.9694612
+[19]  4.3606031  5.1695297
+Warning message:
+In rnorm(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); runif(10, 10, 10)
+ [1] 10 10 10 10 10 10 10 10 10 10
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); runif(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0))
+ [1] NaN NaN NaN NaN NaN NaN NaN   0 NaN NaN NaN NaN
+Warning message:
+In runif(12, c(NA, 0, NaN), c(NaN, NaN, NA, 0)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2#
+#set.seed(1); runif(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3))
+ [1] -1.0000000  0.0000000        NaN        NaN  3.0000000        NaN
+ [7]        NaN -0.7079405  0.3349115  1.8039894        NaN        NaN
+[13]        NaN        NaN  2.6328312        NaN        NaN        NaN
+[19]        NaN        NaN
+Warning message:
+In runif(20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3)) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2Infrastructure#
+#length(runif('3'))
+[1] 3
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2Infrastructure#
+#length(runif(c('a', 'b', 'b', 'd')))
+[1] 4
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2Infrastructure#
+#length(runif(c(1,2,3)))
+[1] 3
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2Infrastructure#Output.IgnoreWarningContext#
+#runif('hello')
+Error in runif("hello") : invalid arguments
+In addition: Warning message:
+In runif("hello") : NAs introduced by coercion
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2Infrastructure#
+#runif(2, 2, numeric())
+[1] NA NA
+Warning message:
+In runif(2, 2, numeric()) : NAs produced
+
+##com.oracle.truffle.r.test.library.stats.TestRandGenerationFunctions.testFunctions2Infrastructure#
+#runif(2, numeric(), 2)
+[1] NA NA
+Warning message:
+In runif(2, numeric(), 2) : NAs produced
+
 ##com.oracle.truffle.r.test.library.stats.TestStats.testCor#
 #{ as.integer(cor(c(1,2,3),c(1,2,5))*10000000) }
 [1] 9607689
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rbeta.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rbeta.java
deleted file mode 100644
index f4ab519fd490edcbcb89bb8f9e1f1e6a94b2cf7b..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rbeta.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.test.library.stats;
-
-import org.junit.Test;
-
-import com.oracle.truffle.r.test.TestBase;
-
-public class TestExternal_rbeta extends TestBase {
-    @Test
-    public void testRbeta() {
-        assertEval("set.seed(42); rbeta(10, 10, 10)");
-        assertEval("set.seed(42); rbeta(10, c(0.1, 2:10), c(0.1, 0.5, 0.9, 3:5))");
-    }
-}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rcauchy.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rcauchy.java
deleted file mode 100644
index f909eb9268bf84271a71a98d47b9a9c536c8e89e..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rcauchy.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.test.library.stats;
-
-import org.junit.Test;
-
-import com.oracle.truffle.r.test.TestBase;
-
-public class TestExternal_rcauchy extends TestBase {
-    @Test
-    public void testRcauchy() {
-        assertEval("set.seed(42); rcauchy(10, 10, 10)");
-        assertEval("set.seed(42); rcauchy(10, 10, -1)");
-        assertEval("set.seed(42); rcauchy(10, NaN, 10)");
-    }
-}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rnorm.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rnorm.java
deleted file mode 100644
index 1bd9882bfcde589cdb3fce85d3a8de27d0432d0f..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rnorm.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.test.library.stats;
-
-import org.junit.Test;
-
-import com.oracle.truffle.r.test.TestBase;
-
-public class TestExternal_rnorm extends TestBase {
-    @Test
-    public void testRnorm() {
-        assertEval("set.seed(42); rnorm(10, 10, 10)");
-        assertEval("set.seed(42); rnorm('10', 10, 5)");
-        assertEval(Output.IgnoreWarningContext, "set.seed(42); rnorm('aa', 10, 0.5)");
-        assertEval("set.seed(42); rnorm(10, 2:10, c(0.1, 0.5, 0.9))");
-        assertEval("set.seed(42); rnorm(1:10, 2:10, c(0.1, 0.5, 0.9))");
-        assertEval("set.seed(42); rnorm(c(1,2), 11:12, c(0.1, 0.5, 0.9))");
-    }
-}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_runif.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_runif.java
deleted file mode 100644
index ad117436f0b49f14a365a15ae38563b7b26ca3fc..0000000000000000000000000000000000000000
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_runif.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code 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
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package com.oracle.truffle.r.test.library.stats;
-
-import org.junit.Test;
-
-import com.oracle.truffle.r.test.TestBase;
-
-public class TestExternal_runif extends TestBase {
-    @Test
-    public void testRunif() {
-        assertEval("set.seed(1); runif(5);");
-        assertEval("set.seed(1); runif(5, 10, 2.5);");
-    }
-}
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestRandGenerationFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestRandGenerationFunctions.java
new file mode 100644
index 0000000000000000000000000000000000000000..14efb145327e9c3093af8b615cbf8dda254e5650
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestRandGenerationFunctions.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.r.test.library.stats;
+
+import org.junit.Test;
+
+import com.oracle.truffle.r.test.TestBase;
+
+/**
+ * Tests the rxxx functions against common set of arguments. Each such function may have additional
+ * tests for its specific corner cases if those are not covered here.
+ */
+public class TestRandGenerationFunctions extends TestBase {
+    private static final String[] FUNCTION2_NAMES = {"rnorm", "runif", "rgamma", "rbeta", "rcauchy"};
+    private static final String[] FUNCTION2_PARAMS = {
+                    "10, 10, 10",
+                    "20, c(-1, 0, 0.2, 2:5), c(-1, 0, 0.1, 0.9, 3)",
+                    "30, c(NA, 0, NaN, 1/0, -1/0), c(NaN, NaN, NA, 0, 1/0, -1/0)"
+    };
+
+    @Test
+    public void testFunctions2() {
+        assertEval(Output.IgnoreWarningContext, template("set.seed(1); %0(%1)", FUNCTION2_NAMES, FUNCTION2_PARAMS));
+    }
+
+    @Test
+    public void testFunctions2Infrastructure() {
+        // calculating the size of the result:
+        assertEval("length(runif(c(1,2,3)))");
+        assertEval("length(runif(c('a', 'b', 'b', 'd')))");
+        assertEval("length(runif('3'))");
+        // wrong size argument
+        assertEval(Output.IgnoreWarningContext, "runif('hello')");
+        // empty parameters
+        assertEval("runif(2, numeric(), 2)");
+        assertEval("runif(2, 2, numeric())");
+        // wrong parameters
+        assertEval("runif(-1, 1, 2)");
+    }
+}
diff --git a/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index d76934e4506834d6521c3efa1b2386f4a4ef143a..3fb3dd1a3377fca6fabc141ca520bc6218bcd6ba 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -55,6 +55,9 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsFunctio
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RandGenerationFunctions.java,gnu_r_gentleman_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java,gnu_r_ihaka.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/TOMS708.java,gnu_r.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SNorm.java,gnu_r_ihaka_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/SExp.java,gnu_r_ihaka_core.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RGamma.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/DirChmod.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/tools/ToolsText.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/utils/CountFields.java,gnu_r.copyright