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
new file mode 100644
index 0000000000000000000000000000000000000000..d7e72dd1f0745a5be4e65d8488bc54fdaee65656
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java
@@ -0,0 +1,157 @@
+/*
+ * 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) 1995, 1996, 1997  Robert Gentleman and Ross Ihaka
+ * Copyright (c) 1998-2013, The R Core Team
+ * Copyright (c) 2003-2015, The R Foundation
+ * 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.MathConstants.M_LN2;
+import static com.oracle.truffle.r.library.stats.StatsUtil.DBL_MAX_EXP;
+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.RandomNumberNode;
+
+public final class RBeta implements RandFunction2_Double {
+
+    private static final double expmax = (DBL_MAX_EXP * M_LN2); /* = log(DBL_MAX) */
+
+    @Override
+    public double evaluate(int index, double aa, double bb, double random, RandomNumberNode randomNode) {
+        if (Double.isNaN(aa) || Double.isNaN(bb) || aa < 0. || bb < 0.) {
+            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 (randomNode.executeSingleDouble() < 0.5) ? 0. : 1.;
+        }
+        // now, at least one of a, b is finite and positive
+        if (!Double.isFinite(aa) || bb == 0.) {
+            return 1.0;
+        }
+        if (!Double.isFinite(bb) || aa == 0.) {
+            return 0.0;
+        }
+
+        double a;
+        double b;
+        double r;
+        double s;
+        double t;
+        double u1;
+        double u2;
+        double v = 0;
+        double w = 0;
+        double y;
+        double z;
+        double olda = -1.0;
+        double oldb = -1.0;
+
+        double beta = 0;
+        double gamma = 1;
+        double delta;
+        double k1 = 0;
+        double k2 = 0;
+
+        /* Test if we need new "initializing" */
+        boolean qsame = (olda == aa) && (oldb == bb);
+        if (!qsame) {
+            olda = aa;
+            oldb = bb;
+        }
+
+        a = fmin2(aa, bb);
+        b = fmax2(aa, bb); /* a <= b */
+        double alpha = a + b;
+
+        if (a <= 1.0) { /* --- Algorithm BC --- */
+            /* changed notation, now also a <= b (was reversed) */
+            if (!qsame) { /* initialize */
+                beta = 1.0 / a;
+                delta = 1.0 + b - a;
+                k1 = delta * (0.0138889 + 0.0416667 * a) / (b * beta - 0.777778);
+                k2 = 0.25 + (0.5 + 0.25 / delta) * a;
+            }
+            /* FIXME: "do { } while()", but not trivially because of "continue"s: */
+            for (;;) {
+                u1 = randomNode.executeSingleDouble();
+                u2 = randomNode.executeSingleDouble();
+                if (u1 < 0.5) {
+                    y = u1 * u2;
+                    z = u1 * y;
+                    if (0.25 * u2 + z - y >= k1) {
+                        continue;
+                    }
+                } else {
+                    z = u1 * u1 * u2;
+                    if (z <= 0.25) {
+                        v = beta * Math.log(u1 / (1.0 - u1));
+                        w = wFromU1Bet(b, v, w);
+                        break;
+                    }
+                    if (z >= k2) {
+                        continue;
+                    }
+                }
+
+                v = beta * Math.log(u1 / (1.0 - u1));
+                w = wFromU1Bet(b, v, w);
+
+                if (alpha * (Math.log(alpha / (a + w)) + v) - 1.3862944 >= Math.log(z)) {
+                    break;
+                }
+            }
+            return (aa == a) ? a / (a + w) : w / (a + w);
+
+        } else { /* Algorithm BB */
+
+            if (!qsame) { /* initialize */
+                beta = Math.sqrt((alpha - 2.0) / (2.0 * a * b - alpha));
+                gamma = a + 1.0 / beta;
+            }
+            do {
+                u1 = randomNode.executeSingleDouble();
+                u2 = randomNode.executeSingleDouble();
+
+                v = beta * Math.log(u1 / (1.0 - u1));
+                w = wFromU1Bet(a, v, w);
+
+                z = u1 * u1 * u2;
+                r = gamma * v - 1.3862944;
+                s = a + r - w;
+                if (s + 2.609438 >= 5.0 * z) {
+                    break;
+                }
+                t = Math.log(z);
+                if (s > t) {
+                    break;
+                }
+            } while (r + alpha * Math.log(alpha / (b + w)) < t);
+
+            return (aa != a) ? b / (b + w) : w / (b + w);
+        }
+    }
+
+    private static double wFromU1Bet(double aa, double v, double w) {
+        if (v <= expmax) {
+            w = aa * Math.exp(v);
+            if (!Double.isFinite(w)) {
+                w = Double.MAX_VALUE;
+            }
+        } else {
+            w = Double.MAX_VALUE;
+        }
+        return 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
new file mode 100644
index 0000000000000000000000000000000000000000..4ec84f33dd4c9433818f7ebe0919bea71468ffe8
--- /dev/null
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java
@@ -0,0 +1,31 @@
+/*
+ * 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.MathConstants.M_PI;
+
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
+import com.oracle.truffle.r.runtime.rng.RandomNumberNode;
+
+public final class RCauchy implements RandFunction2_Double {
+    @Override
+    public double evaluate(int index, double location, double scale, double random, RandomNumberNode randomNode) {
+        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 * randomNode.executeSingleDouble());
+        }
+    }
+}
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 a176c75521e98ca8e7e4333acef9c87500348287..b0d34cd6095b383d1ea66d9b4f1c103f64065a92 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
@@ -37,11 +37,10 @@ import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 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.ops.na.NACheck;
 import com.oracle.truffle.r.runtime.rng.RRNG;
+import com.oracle.truffle.r.runtime.rng.RandomNumberNode;
 
 public final class RandGenerationFunctions {
-    public static final double ERR_NA = RRuntime.DOUBLE_NA;
     private static final RDouble DUMMY_VECTOR = RDouble.valueOf(1);
 
     private RandGenerationFunctions() {
@@ -50,46 +49,57 @@ public final class RandGenerationFunctions {
 
     // 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);
+    public interface RandFunction {
+        /**
+         * Allows to execute any initialization logic before the main loop that generates the
+         * resulting vector. This is place where the function should generate necessary random
+         * values if possible.
+         */
+        default void init(int resultLength, RandomNumberNode randNode) {
+            RRNG.getRNGState();
+        }
+
+        default void finish() {
+            RRNG.putRNGState();
+        }
+    }
+
+    public interface RandFunction3_Int extends RandFunction {
+        int evaluate(int index, double a, double b, double c, RandomNumberNode randomNode);
     }
 
     public interface RandFunction2_Int extends RandFunction3_Int {
         @Override
-        default int evaluate(double a, double b, double c) {
-            return evaluate(a, b);
+        default int evaluate(int index, double a, double b, double c, RandomNumberNode randomNode) {
+            return evaluate(index, a, b, randomNode);
         }
 
-        int evaluate(double a, double b);
+        int evaluate(int index, double a, double b, RandomNumberNode randomNode);
     }
 
-    public interface RandFunction2_Double {
+    public interface RandFunction2_Double extends RandFunction {
         /**
-         * If returns {@code false}, {@link #evaluate(double, double)} will not be invoked.
+         * Opt-in possibility for random functions returning double: the infrastructure will
+         * preallocate array of random values and reuse it for storing the result. The random values
+         * will be passed to {@link #evaluate(int, double, double, double, RandomNumberNode)} as the
+         * 'random' argument. If this method returns {@code true} (default), the random numbers
+         * generation can be done in {@link #init(int, RandomNumberNode)} and {@link #finish()} or
+         * in {@link #evaluate(int, double, double, double, RandomNumberNode)}.
          */
-        boolean isValid(double a, double b);
+        default boolean hasCustomRandomGeneration() {
+            return true;
+        }
 
         /**
-         * Is guaranteed to be preceded by invocation of {@link #isValid(double, double)} with the
-         * same arguments.
+         * Should generate the value that will be stored to the result vector under given index.
+         * Error is indicated by returning {@link StatsUtil#mlError()}.
          */
-        double evaluate(double a, double b);
-    }
-
-    public abstract static class RandFunction2_DoubleAdapter implements RandFunction2_Double {
-        @Override
-        public boolean isValid(double a, double b) {
-            return true;
-        }
+        double evaluate(int index, double a, double b, double random, RandomNumberNode randomNode);
     }
 
     static final class RandGenerationProfiles {
         final BranchProfile nanResult = BranchProfile.create();
-        final BranchProfile errResult = BranchProfile.create();
         final BranchProfile nan = BranchProfile.create();
-        final NACheck aCheck = NACheck.create();
-        final NACheck bCheck = NACheck.create();
-        final NACheck cCheck = NACheck.create();
         final VectorLengthProfile resultVectorLengthProfile = VectorLengthProfile.create();
         final LoopConditionProfile loopConditionProfile = LoopConditionProfile.createCountingProfile();
 
@@ -99,7 +109,7 @@ public final class RandGenerationFunctions {
     }
 
     private static RAbstractIntVector evaluate3Int(Node node, RandFunction3_Int function, int lengthIn, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c,
-                    RandGenerationProfiles profiles) {
+                    RandGenerationProfiles profiles, RandomNumberNode randNode) {
         int length = profiles.resultVectorLengthProfile.profile(lengthIn);
         int aLength = a.getLength();
         int bLength = b.getLength();
@@ -113,41 +123,30 @@ public final class RandGenerationFunctions {
         }
 
         RNode.reportWork(node, length);
-        boolean complete = true;
         boolean nans = false;
-        profiles.aCheck.enable(a);
-        profiles.bCheck.enable(b);
-        profiles.cCheck.enable(c);
         int[] result = new int[length];
-        RRNG.getRNGState();
+        function.init(length, randNode);
         for (int i = 0; profiles.loopConditionProfile.inject(i < length); i++) {
             double aValue = a.getDataAt(i % aLength);
             double bValue = b.getDataAt(i % bLength);
             double cValue = c.getDataAt(i % cLength);
-            int value;
-            if (Double.isNaN(aValue) || Double.isNaN(bValue) || Double.isNaN(cValue)) {
+            int value = function.evaluate(i, aValue, bValue, cValue, randNode);
+            if (Double.isNaN(value)) {
                 profiles.nan.enter();
-                value = RRuntime.INT_NA;
-                if (profiles.aCheck.check(aValue) || profiles.bCheck.check(bValue) || profiles.cCheck.check(cValue)) {
-                    complete = false;
-                }
-            } else {
-                value = function.evaluate(aValue, bValue, cValue);
-                if (Double.isNaN(value)) {
-                    profiles.nan.enter();
-                    nans = true;
-                }
+                nans = true;
             }
             result[i] = value;
         }
-        RRNG.putRNGState();
+        function.finish();
         if (nans) {
             RError.warning(SHOW_CALLER, RError.Message.NAN_PRODUCED);
         }
-        return RDataFactory.createIntVector(result, complete);
+        return RDataFactory.createIntVector(result, !nans);
     }
 
-    private static RAbstractDoubleVector evaluate2Double(Node node, RandFunction2_Double function, int length, RAbstractDoubleVector a, RAbstractDoubleVector b, RandGenerationProfiles profiles) {
+    private static RAbstractDoubleVector evaluate2Double(Node node, RandFunction2_Double function, int lengthIn, RAbstractDoubleVector a, RAbstractDoubleVector b, RandGenerationProfiles profiles,
+                    RandomNumberNode randNode) {
+        int length = profiles.resultVectorLengthProfile.profile(lengthIn);
         int aLength = a.getLength();
         int bLength = b.getLength();
         if (aLength == 0 || bLength == 0) {
@@ -157,41 +156,33 @@ public final class RandGenerationFunctions {
         }
 
         RNode.reportWork(node, length);
-        boolean complete = true;
         boolean nans = false;
-        profiles.aCheck.enable(a);
-        profiles.bCheck.enable(b);
-        double[] result = new double[length];
-        RRNG.getRNGState();
-        for (int i = 0; i < length; i++) {
+        double[] result;
+        if (function.hasCustomRandomGeneration()) {
+            function.init(length, randNode);
+            result = new double[length];
+        } else {
+            RRNG.getRNGState();
+            result = randNode.executeDouble(length);
+            RRNG.putRNGState();
+        }
+        for (int i = 0; profiles.loopConditionProfile.inject(i < length); i++) {
             double aValue = a.getDataAt(i % aLength);
             double bValue = b.getDataAt(i % bLength);
-            double value;
-            if (Double.isNaN(aValue) || Double.isNaN(bValue)) {
+            double value = function.evaluate(i, aValue, bValue, result[i], randNode);
+            if (Double.isNaN(value)) {
                 profiles.nan.enter();
-                value = RRuntime.INT_NA;
-                if (profiles.aCheck.check(aValue) || profiles.bCheck.check(bValue)) {
-                    complete = false;
-                }
-            } else {
-                if (!function.isValid(aValue, bValue)) {
-                    profiles.errResult.enter();
-                    RError.warning(SHOW_CALLER, RError.Message.NA_PRODUCED);
-                    return createVectorOf(length, Double.NaN);
-                }
-                value = function.evaluate(aValue, bValue);
-                if (Double.isNaN(value)) {
-                    profiles.nan.enter();
-                    nans = true;
-                }
+                nans = true;
             }
             result[i] = value;
         }
-        RRNG.putRNGState();
+        if (function.hasCustomRandomGeneration()) {
+            function.finish();
+        }
         if (nans) {
-            RError.warning(SHOW_CALLER, RError.Message.NAN_PRODUCED);
+            RError.warning(SHOW_CALLER, RError.Message.NA_PRODUCED);
         }
-        return RDataFactory.createDoubleVector(result, complete);
+        return RDataFactory.createDoubleVector(result, !nans);
     }
 
     private static RAbstractDoubleVector createVectorOf(int length, double element) {
@@ -248,8 +239,9 @@ public final class RandGenerationFunctions {
 
         @Specialization
         protected RAbstractIntVector evaluate(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b, RAbstractDoubleVector c,
-                        @Cached("create()") RandGenerationProfiles profiles) {
-            return evaluate3Int(this, function, convertToLength.execute(length), a, b, c, profiles);
+                        @Cached("create()") RandGenerationProfiles profiles,
+                        @Cached("create()") RandomNumberNode randNode) {
+            return evaluate3Int(this, function, convertToLength.execute(length), a, b, c, profiles, randNode);
         }
     }
 
@@ -270,8 +262,9 @@ public final class RandGenerationFunctions {
 
         @Specialization
         protected RAbstractIntVector evaluate(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b,
-                        @Cached("create()") RandGenerationProfiles profiles) {
-            return evaluate3Int(this, function, convertToLength.execute(length), a, b, DUMMY_VECTOR, profiles);
+                        @Cached("create()") RandGenerationProfiles profiles,
+                        @Cached("create()") RandomNumberNode randNode) {
+            return evaluate3Int(this, function, convertToLength.execute(length), a, b, DUMMY_VECTOR, profiles, randNode);
         }
     }
 
@@ -292,8 +285,9 @@ public final class RandGenerationFunctions {
 
         @Specialization
         protected RAbstractDoubleVector evaluate(RAbstractVector length, RAbstractDoubleVector a, RAbstractDoubleVector b,
-                        @Cached("create()") RandGenerationProfiles profiles) {
-            return evaluate2Double(this, function, convertToLength.execute(length), a, b, profiles);
+                        @Cached("create()") RandGenerationProfiles profiles,
+                        @Cached("create()") RandomNumberNode randNode) {
+            return evaluate2Double(this, function, convertToLength.execute(length), a, b, profiles, randNode);
         }
     }
 }
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 e814c90a222325d9ba8f6e91524cbbdd602b2f08..051c0822f9fb40f7f37f85bd232ecca4510e055d 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
@@ -12,10 +12,9 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Int;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.rng.RRNG;
+import com.oracle.truffle.r.runtime.rng.RandomNumberNode;
 
 // transcribed from rbinom.c
 
@@ -23,13 +22,12 @@ public final class Rbinom implements RandFunction2_Int {
 
     private final Qbinom qbinom = new Qbinom();
 
-    @TruffleBoundary
-    private static double unifRand() {
-        return RRNG.unifRand();
+    private static double unifRand(RandomNumberNode randNode) {
+        return randNode.executeDouble(1)[0];
     }
 
     @Override
-    public int evaluate(double nin, double pp) {
+    public int evaluate(int index, double nin, double pp, RandomNumberNode randomNode) {
         double psave = -1.0;
         int nsave = -1;
 
@@ -56,7 +54,7 @@ public final class Rbinom implements RandFunction2_Int {
             /*
              * evade integer overflow, and r == INT_MAX gave only even values
              */
-            return (int) qbinom.evaluate(unifRand(), r, pp, /* lower_tail */false, /* log_p */false);
+            return (int) qbinom.evaluate(unifRand(randomNode), r, pp, /* lower_tail */false, /* log_p */false);
         }
         /* else */
         int n = (int) r;
@@ -137,8 +135,8 @@ public final class Rbinom implements RandFunction2_Int {
 
                 /*-------------------------- np = n*p >= 30 : ------------------- */
                 while (true) {
-                    u = unifRand() * p4;
-                    v = unifRand();
+                    u = unifRand(randomNode) * p4;
+                    v = unifRand(randomNode);
                     /* triangular region */
                     if (u <= p1) {
                         ix = (int) (xm - p1 * v + u);
@@ -225,7 +223,7 @@ public final class Rbinom implements RandFunction2_Int {
             while (true) {
                 ix = 0;
                 f = qn;
-                u = unifRand();
+                u = unifRand(randomNode);
                 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 641b1163688c4117d5b47a94d771ed72cdea9bea..8a55565f261df940882ccef50c475c1111ac21b1 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
@@ -11,17 +11,30 @@
  */
 package com.oracle.truffle.r.library.stats;
 
-import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_DoubleAdapter;
+import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
 import com.oracle.truffle.r.runtime.rng.RRNG;
+import com.oracle.truffle.r.runtime.rng.RandomNumberNode;
 
-public final class Rnorm extends RandFunction2_DoubleAdapter {
+public final class Rnorm implements RandFunction2_Double {
 
     private static final double BIG = 134217728;
+    private double[] randomVals;
 
     @Override
-    public double evaluate(double mu, double sigma) {
+    public void init(int length, RandomNumberNode randNode) {
+        RRNG.getRNGState();
+        randomVals = randNode.executeDouble(length * 2);
+    }
+
+    @Override
+    public void finish() {
+        RRNG.putRNGState();
+    }
+
+    @Override
+    public double evaluate(int index, double mu, double sigma, double random, RandomNumberNode randomNode) {
         // TODO: GnuR invokes norm_rand to get "rand"
-        double u1 = (int) (BIG * RRNG.unifRand()) + RRNG.unifRand();
+        double u1 = (int) (BIG * randomVals[index * 2]) + randomVals[index * 2 + 1];
         double rand = Random2.qnorm5(u1 / BIG, 0.0, 1.0, true, false);
         return rand * sigma + mu;
     }
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 443074c1da94cb62a6c9b028f9b258b32a6e3bbc..c5fb0cdcd9a67cbf042ef4037957042254b5e3ca 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
@@ -24,16 +24,20 @@ package com.oracle.truffle.r.library.stats;
 
 import com.oracle.truffle.r.library.stats.RandGenerationFunctions.RandFunction2_Double;
 import com.oracle.truffle.r.runtime.RRuntime;
-import com.oracle.truffle.r.runtime.rng.RRNG;
+import com.oracle.truffle.r.runtime.rng.RandomNumberNode;
 
 public final class Runif implements RandFunction2_Double {
+
     @Override
-    public boolean isValid(double min, double max) {
-        return RRuntime.isFinite(min) && RRuntime.isFinite(max) && max >= min;
+    public boolean hasCustomRandomGeneration() {
+        return false;
     }
 
     @Override
-    public double evaluate(double min, double max) {
-        return min + RRNG.unifRand() * (max - min);
+    public double evaluate(int index, double min, double max, double random, RandomNumberNode randomNode) {
+        if (!RRuntime.isFinite(min) || !RRuntime.isFinite(max) || max < min) {
+            return StatsUtil.mlError();
+        }
+        return min + random * (max - min);
     }
 }
diff --git a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java
index 5ddb311b43a74aabe28ca2a8547fd2a47ffc3fea..76fe2473335bca7fd404efc89a49945704360171 100644
--- a/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java
+++ b/com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/StatsUtil.java
@@ -21,6 +21,13 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
  */
 public class StatsUtil {
 
+    /**
+     * corresponds to macro {@code ML_ERR_return_NAN} in GnuR.
+     */
+    public static double mlError() {
+        return Double.NaN;
+    }
+
     public static final double DBLEPSILON = 2.2204460492503131e-16;
 
     @TruffleBoundary
@@ -112,6 +119,10 @@ public class StatsUtil {
         return giveLog ? -0.5 * Math.log(f) + x : Math.exp(x) / Math.sqrt(f);
     }
 
+    //
+    // GNUR from fmin2.c and fmax2
+    //
+
     public static double fmax2(double x, double y) {
         if (Double.isNaN(x) || Double.isNaN(y)) {
             return x + y;
@@ -119,6 +130,13 @@ public class StatsUtil {
         return (x < y) ? y : x;
     }
 
+    public static double fmin2(double x, double y) {
+        if (Double.isNaN(x) || Double.isNaN(y)) {
+            return x + y;
+        }
+        return (x < y) ? x : y;
+    }
+
     //
     // GNUR from expm1.c
     //
@@ -150,7 +168,7 @@ public class StatsUtil {
     // GNUR from log1p.c
     //
 
-    @CompilationFinal private static final double[] alnrcs = {+.10378693562743769800686267719098e+1, -.13364301504908918098766041553133e+0, +.19408249135520563357926199374750e-1,
+    @CompilationFinal(dimensions = 1) private static final double[] alnrcs = {+.10378693562743769800686267719098e+1, -.13364301504908918098766041553133e+0, +.19408249135520563357926199374750e-1,
                     -.30107551127535777690376537776592e-2, +.48694614797154850090456366509137e-3, -.81054881893175356066809943008622e-4, +.13778847799559524782938251496059e-4,
                     -.23802210894358970251369992914935e-5, +.41640416213865183476391859901989e-6, -.73595828378075994984266837031998e-7, +.13117611876241674949152294345011e-7,
                     -.23546709317742425136696092330175e-8, +.42522773276034997775638052962567e-9, -.77190894134840796826108107493300e-10, +.14075746481359069909215356472191e-10,
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 9b49dab85d20085b3ddb4ed9dc1916e290d87afe..f059e6c94b411a8a6783712b09d188a26c18a220 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
@@ -51,6 +51,8 @@ import com.oracle.truffle.r.library.stats.Pf;
 import com.oracle.truffle.r.library.stats.Pnorm;
 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.RandGenerationFunctionsFactory;
 import com.oracle.truffle.r.library.stats.Rbinom;
 import com.oracle.truffle.r.library.stats.Rnorm;
@@ -362,6 +364,10 @@ public class ForeignFunctions {
                     return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new Rnorm());
                 case "runif":
                     return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new Runif());
+                case "rbeta":
+                    return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new RBeta());
+                case "rcauchy":
+                    return RandGenerationFunctionsFactory.Function2_DoubleNodeGen.create(new RCauchy());
                 case "qgamma":
                     return StatsFunctionsFactory.Function3_2NodeGen.create(new QgammaFunc());
                 case "dbinom":
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RandomNumberNode.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RandomNumberNode.java
index b02f2ab8da1cbb540c2ecdb891ebaf6fff6a8f03..f77dda2729d47d7406f9bc68719cc8e71a8e2faa 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RandomNumberNode.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/rng/RandomNumberNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -33,4 +33,12 @@ public final class RandomNumberNode extends RBaseNode {
     public double[] executeDouble(int count) {
         return generatorClassProfile.profile(generatorProfile.profile(RRNG.currentGenerator())).genrandDouble(count);
     }
+
+    public double executeSingleDouble() {
+        return generatorClassProfile.profile(generatorProfile.profile(RRNG.currentGenerator())).genrandDouble(1)[0];
+    }
+
+    public static RandomNumberNode create() {
+        return new RandomNumberNode();
+    }
 }
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 998aa5bca342d0d75f878d80a9bc810dc88baa9c..0b6de6c730ad5ae949b375c523f698a62ac608b7 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
@@ -111006,6 +111006,16 @@ 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
@@ -111032,6 +111042,23 @@ 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
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
new file mode 100644
index 0000000000000000000000000000000000000000..f4ab519fd490edcbcb89bb8f9e1f1e6a94b2cf7b
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rbeta.java
@@ -0,0 +1,35 @@
+/*
+ * 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
new file mode 100644
index 0000000000000000000000000000000000000000..f909eb9268bf84271a71a98d47b9a9c536c8e89e
--- /dev/null
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/stats/TestExternal_rcauchy.java
@@ -0,0 +1,36 @@
+/*
+ * 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/mx.fastr/copyrights/overrides b/mx.fastr/copyrights/overrides
index b2774bbe81df2fcdb8776e053ecbdb3aec5e15f4..86dfbf89ffa674a46361a96dbaa700c75bc9174c 100644
--- a/mx.fastr/copyrights/overrides
+++ b/mx.fastr/copyrights/overrides
@@ -29,6 +29,8 @@ com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/grid/GridFunctions
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/MethodsListDispatch.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/methods/Slot.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Arithmetic.java,gnu_r_gentleman_ihaka.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RBeta.java,gnu_r_gentleman_ihaka.copyright
+com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/RCauchy.java,gnu_r_ihaka_core.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/CompleteCases.java,gnu_r_gentleman_ihaka2.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Covcor.java,gnu_r.copyright
 com.oracle.truffle.r.library/src/com/oracle/truffle/r/library/stats/Dbinom.java,gnu_r.copyright