This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-rng.git

commit 6525ccf566ca2f4d13858b9f0fc4583762e9ad68
Author: aherbert <[email protected]>
AuthorDate: Mon Jul 5 13:08:34 2021 +0100

    RNG-151: Modified ziggurat samplers for exponential and Gaussian
---
 .../ContinuousSamplersPerformance.java             |   13 +-
 .../distribution/ZigguratSamplerPerformance.java   | 1240 ++++++++++++++++++++
 .../rng/sampling/distribution/ZigguratSampler.java |  865 ++++++++++++++
 .../distribution/ContinuousSamplersList.java       |    7 +
 .../sampling/distribution/ZigguratSamplerTest.java |   75 ++
 5 files changed, 2198 insertions(+), 2 deletions(-)

diff --git 
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/distribution/ContinuousSamplersPerformance.java
 
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/distribution/ContinuousSamplersPerformance.java
index 91bb2ee..899e338 100644
--- 
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/distribution/ContinuousSamplersPerformance.java
+++ 
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/distribution/ContinuousSamplersPerformance.java
@@ -29,6 +29,7 @@ import 
org.apache.commons.rng.sampling.distribution.InverseTransformParetoSample
 import org.apache.commons.rng.sampling.distribution.LevySampler;
 import org.apache.commons.rng.sampling.distribution.LogNormalSampler;
 import 
org.apache.commons.rng.sampling.distribution.MarsagliaNormalizedGaussianSampler;
+import org.apache.commons.rng.sampling.distribution.ZigguratSampler;
 import org.apache.commons.rng.sampling.distribution.ZigguratExponentialSampler;
 import 
org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler;
 
@@ -77,7 +78,9 @@ public class ContinuousSamplersPerformance {
         @Param({"BoxMullerNormalizedGaussianSampler",
                 "MarsagliaNormalizedGaussianSampler",
                 "ZigguratNormalizedGaussianSampler",
+                "ZigguratSampler.NormalizedGaussian",
                 "AhrensDieterExponentialSampler",
+                "ZigguratSampler.Exponential",
                 "ZigguratExponentialSampler",
                 "AhrensDieterGammaSampler",
                 "MarsagliaTsangGammaSampler",
@@ -85,10 +88,10 @@ public class ContinuousSamplersPerformance {
                 "LogNormalBoxMullerNormalizedGaussianSampler",
                 "LogNormalMarsagliaNormalizedGaussianSampler",
                 "LogNormalZigguratNormalizedGaussianSampler",
+                "LogNormalSampler.ZigguratSampler.NormalizedGaussian",
                 "ChengBetaSampler",
                 "ContinuousUniformSampler",
-                "InverseTransformParetoSampler",
-                })
+                "InverseTransformParetoSampler"})
         private String samplerType;
 
         /** The sampler. */
@@ -113,8 +116,12 @@ public class ContinuousSamplersPerformance {
                 sampler = MarsagliaNormalizedGaussianSampler.of(rng);
             } else if 
("ZigguratNormalizedGaussianSampler".equals(samplerType)) {
                 sampler = ZigguratNormalizedGaussianSampler.of(rng);
+            } else if 
("ZigguratSampler.NormalizedGaussian".equals(samplerType)) {
+                sampler = ZigguratSampler.NormalizedGaussian.of(rng);
             } else if ("AhrensDieterExponentialSampler".equals(samplerType)) {
                 sampler = AhrensDieterExponentialSampler.of(rng, 4.56);
+            } else if ("ZigguratSampler.Exponential".equals(samplerType)) {
+                sampler = ZigguratSampler.Exponential.of(rng, 4.56);
             } else if ("ZigguratExponentialSampler".equals(samplerType)) {
                 sampler = ZigguratExponentialSampler.of(rng, 4.56);
             } else if ("AhrensDieterGammaSampler".equals(samplerType)) {
@@ -131,6 +138,8 @@ public class ContinuousSamplersPerformance {
                 sampler = 
LogNormalSampler.of(MarsagliaNormalizedGaussianSampler.of(rng), 12.3, 4.6);
             } else if 
("LogNormalZigguratNormalizedGaussianSampler".equals(samplerType)) {
                 sampler = 
LogNormalSampler.of(ZigguratNormalizedGaussianSampler.of(rng), 12.3, 4.6);
+            } else if 
("LogNormalSampler.ZigguratSampler.NormalizedGaussian".equals(samplerType)) {
+                sampler = 
LogNormalSampler.of(ZigguratSampler.NormalizedGaussian.of(rng), 12.3, 4.6);
             } else if ("ChengBetaSampler".equals(samplerType)) {
                 sampler = ChengBetaSampler.of(rng, 0.45, 6.7);
             } else if ("ContinuousUniformSampler".equals(samplerType)) {
diff --git 
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/distribution/ZigguratSamplerPerformance.java
 
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/distribution/ZigguratSamplerPerformance.java
new file mode 100644
index 0000000..dbaf9d0
--- /dev/null
+++ 
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/distribution/ZigguratSamplerPerformance.java
@@ -0,0 +1,1240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.rng.examples.jmh.sampling.distribution;
+
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
+import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
+import org.apache.commons.rng.sampling.distribution.ZigguratSampler;
+import 
org.apache.commons.rng.sampling.distribution.ZigguratNormalizedGaussianSampler;
+import org.apache.commons.rng.simple.RandomSource;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.annotations.Param;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.Setup;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Warmup;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Executes a benchmark to compare the speed of generation of random numbers
+ * using variations of the ziggurat method.
+ */
+@BenchmarkMode(Mode.AverageTime)
+@OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@State(Scope.Benchmark)
+@Fork(value = 1, jvmArgs = {"-server", "-Xms128M", "-Xmx128M"})
+public class ZigguratSamplerPerformance {
+    /**
+     * The value.
+     *
+     * <p>This must NOT be final!</p>
+     */
+    private double value;
+
+    /**
+     * Defines method to use for creating {@code int} index values from a 
random long.
+     */
+    @State(Scope.Benchmark)
+    public static class IndexSources {
+        /** The method to obtain the index. */
+        @Param({"CastMask", "MaskCast"})
+        private String method;
+
+        /** The sampler. */
+        private DiscreteSampler sampler;
+
+        /**
+         * @return the sampler.
+         */
+        public DiscreteSampler getSampler() {
+            return sampler;
+        }
+
+        /** Instantiates sampler. */
+        @Setup
+        public void setup() {
+            // Use a fast generator
+            final UniformRandomProvider rng = 
RandomSource.XO_RO_SHI_RO_128_PP.create();
+            if ("CastMask".equals(method)) {
+                sampler = new DiscreteSampler() {
+                    @Override
+                    public int sample() {
+                        final long x = rng.nextLong();
+                        return ((int) x) & 0xff;
+                    }
+                };
+            } else if ("MaskCast".equals(method)) {
+                sampler = new DiscreteSampler() {
+                    @Override
+                    public int sample() {
+                        final long x = rng.nextLong();
+                        return (int) (x & 0xff);
+                    }
+                };
+            } else {
+                throwIllegalStateException(method);
+            }
+        }
+    }
+
+    /**
+     * Sampler that generates values of type {@code long}.
+     */
+    interface LongSampler {
+        /**
+         * @return a sample.
+         */
+        long sample();
+    }
+
+    /**
+     * Defines method to use for creating unsigned {@code long} values.
+     */
+    @State(Scope.Benchmark)
+    public static class LongSources {
+        /** The method to obtain the long. */
+        @Param({"Mask", "Shift"})
+        private String method;
+
+        /** The sampler. */
+        private LongSampler sampler;
+
+        /**
+         * @return the sampler.
+         */
+        public LongSampler getSampler() {
+            return sampler;
+        }
+
+        /** Instantiates sampler. */
+        @Setup
+        public void setup() {
+            // Use a fast generator
+            final UniformRandomProvider rng = 
RandomSource.XO_RO_SHI_RO_128_PP.create();
+            if ("Mask".equals(method)) {
+                sampler = new LongSampler() {
+                    @Override
+                    public long sample() {
+                        return rng.nextLong() & Long.MAX_VALUE;
+                    }
+                };
+            } else if ("Shift".equals(method)) {
+                sampler = new LongSampler() {
+                    @Override
+                    public long sample() {
+                        return rng.nextLong() >>> 1;
+                    }
+                };
+            } else {
+                throwIllegalStateException(method);
+            }
+        }
+    }
+
+    /**
+     * The samplers to use for testing the ziggurat method.
+     * Defines the RandomSource and the sampler type.
+     */
+    @State(Scope.Benchmark)
+    public static class Sources {
+        /**
+         * RNG providers.
+         *
+         * <p>Use different speeds.</p>
+         *
+         * @see <a 
href="https://commons.apache.org/proper/commons-rng/userguide/rng.html";>
+         *      Commons RNG user guide</a>
+         */
+        @Param({"XO_RO_SHI_RO_128_PP",
+                "MWC_256",
+                "JDK"})
+        private String randomSourceName;
+
+        /**
+         * The sampler type.
+         */
+        @Param({"Gaussian128", "Gaussian256", "Exponential", "ModGaussian", 
"ModExponential",
+                "ModGaussian2", "ModExponential2"})
+        private String type;
+
+        /** The sampler. */
+        private ContinuousSampler sampler;
+
+        /**
+         * @return the sampler.
+         */
+        public ContinuousSampler getSampler() {
+            return sampler;
+        }
+
+        /** Instantiates sampler. */
+        @Setup
+        public void setup() {
+            final RandomSource randomSource = 
RandomSource.valueOf(randomSourceName);
+            final UniformRandomProvider rng = randomSource.create();
+            if ("Gaussian128".equals(type)) {
+                sampler = ZigguratNormalizedGaussianSampler.of(rng);
+            } else if ("Gaussian256".equals(type)) {
+                sampler = new ZigguratNormalizedGaussianSampler256(rng);
+            } else if ("Exponential".equals(type)) {
+                sampler = new ZigguratExponentialSampler(rng);
+            } else if ("ModGaussian".equals(type)) {
+                sampler = ZigguratSampler.NormalizedGaussian.of(rng);
+            } else if ("ModExponential".equals(type)) {
+                sampler = ZigguratSampler.Exponential.of(rng);
+            } else if ("ModGaussian2".equals(type)) {
+                sampler = new ModifiedZigguratNormalizedGaussianSampler(rng);
+            } else if ("ModExponential2".equals(type)) {
+                sampler = new ModifiedZigguratExponentialSampler(rng);
+            } else {
+                throwIllegalStateException(type);
+            }
+        }
+    }
+
+    /**
+     * <a href="https://en.wikipedia.org/wiki/Ziggurat_algorithm";>
+     * Marsaglia and Tsang "Ziggurat" method</a> for sampling from a 
NormalizedGaussian
+     * distribution with mean 0 and standard deviation 1.
+     *
+     * <p>This is a copy of {@link ZigguratNormalizedGaussianSampler} using a 
table size of 256.
+     */
+    static class ZigguratNormalizedGaussianSampler256 implements 
ContinuousSampler {
+        /** Start of tail. */
+        private static final double R = 3.6541528853610088;
+        /** Inverse of R. */
+        private static final double ONE_OVER_R = 1 / R;
+        /** Index of last entry in the tables (which have a size that is a 
power of 2). */
+        private static final int LAST = 255;
+        /** Auxiliary table. */
+        private static final long[] K;
+        /** Auxiliary table. */
+        private static final double[] W;
+        /** Auxiliary table. */
+        private static final double[] F;
+
+        /** Underlying source of randomness. */
+        private final UniformRandomProvider rng;
+
+        static {
+            // Filling the tables.
+            // Rectangle area.
+            final double v = 0.00492867323399;
+            // Direction support uses the sign bit so the maximum magnitude 
from the long is 2^63
+            final double max = Math.pow(2, 63);
+            final double oneOverMax = 1d / max;
+
+            K = new long[LAST + 1];
+            W = new double[LAST + 1];
+            F = new double[LAST + 1];
+
+            double d = R;
+            double t = d;
+            double fd = pdf(d);
+            final double q = v / fd;
+
+            K[0] = (long) ((d / q) * max);
+            K[1] = 0;
+
+            W[0] = q * oneOverMax;
+            W[LAST] = d * oneOverMax;
+
+            F[0] = 1;
+            F[LAST] = fd;
+
+            for (int i = LAST - 1; i >= 1; i--) {
+                d = Math.sqrt(-2 * Math.log(v / d + fd));
+                fd = pdf(d);
+
+                K[i + 1] = (long) ((d / t) * max);
+                t = d;
+
+                F[i] = fd;
+
+                W[i] = d * oneOverMax;
+            }
+        }
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         */
+        ZigguratNormalizedGaussianSampler256(UniformRandomProvider rng) {
+            this.rng = rng;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double sample() {
+            final long j = rng.nextLong();
+            final int i = ((int) j) & LAST;
+            if (Math.abs(j) < K[i]) {
+                return j * W[i];
+            }
+            return fix(j, i);
+        }
+
+        /**
+         * Gets the value from the tail of the distribution.
+         *
+         * @param hz Start random integer.
+         * @param iz Index of cell corresponding to {@code hz}.
+         * @return the requested random value.
+         */
+        private double fix(long hz,
+                           int iz) {
+            if (iz == 0) {
+                // Base strip.
+                // This branch is called about 5.7624515E-4 times per sample.
+                double y;
+                double x;
+                do {
+                    y = -Math.log(rng.nextDouble());
+                    x = -Math.log(rng.nextDouble()) * ONE_OVER_R;
+                } while (y + y < x * x);
+
+                final double out = R + x;
+                return hz > 0 ? out : -out;
+            }
+            // Wedge of other strips.
+            // This branch is called about 0.027323 times per sample.
+            final double x = hz * W[iz];
+            if (F[iz] + rng.nextDouble() * (F[iz - 1] - F[iz]) < pdf(x)) {
+                return x;
+            }
+            // Try again.
+            // This branch is called about 0.012362 times per sample.
+            return sample();
+        }
+
+        /**
+         * Compute the Gaussian probability density function {@code f(x) = 
e^-0.5x^2}.
+         *
+         * @param x Argument.
+         * @return \( e^{-\frac{x^2}{2}} \)
+         */
+        private static double pdf(double x) {
+            return Math.exp(-0.5 * x * x);
+        }
+    }
+
+    /**
+     * <a href="https://en.wikipedia.org/wiki/Ziggurat_algorithm";>
+     * Marsaglia and Tsang "Ziggurat" method</a> for sampling from an 
exponential
+     * distribution.
+     *
+     * <p>The algorithm is explained in this
+     * <a 
href="http://www.jstatsoft.org/article/view/v005i08/ziggurat.pdf";>paper</a>
+     * and this implementation has been adapted from the C code provided 
therein.</p>
+     */
+    static class ZigguratExponentialSampler implements ContinuousSampler {
+        /** Start of tail. */
+        private static final double R = 7.69711747013104972;
+        /** Index of last entry in the tables (which have a size that is a 
power of 2). */
+        private static final int LAST = 255;
+        /** Auxiliary table. */
+        private static final long[] K;
+        /** Auxiliary table. */
+        private static final double[] W;
+        /** Auxiliary table. */
+        private static final double[] F;
+
+        /** Underlying source of randomness. */
+        private final UniformRandomProvider rng;
+
+        static {
+            // Filling the tables.
+            // Rectangle area.
+            final double v = 0.0039496598225815571993;
+            // No support for unsigned long so the upper bound is 2^63
+            final double max = Math.pow(2, 63);
+            final double oneOverMax = 1d / max;
+
+            K = new long[LAST + 1];
+            W = new double[LAST + 1];
+            F = new double[LAST + 1];
+
+            double d = R;
+            double t = d;
+            double fd = pdf(d);
+            final double q = v / fd;
+
+            K[0] = (long) ((d / q) * max);
+            K[1] = 0;
+
+            W[0] = q * oneOverMax;
+            W[LAST] = d * oneOverMax;
+
+            F[0] = 1;
+            F[LAST] = fd;
+
+            for (int i = LAST - 1; i >= 1; i--) {
+                d = -Math.log(v / d + fd);
+                fd = pdf(d);
+
+                K[i + 1] = (long) ((d / t) * max);
+                t = d;
+
+                F[i] = fd;
+
+                W[i] = d * oneOverMax;
+            }
+        }
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         */
+        ZigguratExponentialSampler(UniformRandomProvider rng) {
+            this.rng = rng;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double sample() {
+            // An unsigned long in [0, 2^63)
+            final long j = rng.nextLong() >>> 1;
+            final int i = ((int) j) & LAST;
+            if (j < K[i]) {
+                // This branch is called about 0.977777 times per call into 
createSample.
+                // Note: Frequencies have been empirically measured for the 
first call to
+                // createSample; recursion due to retries have been ignored. 
Frequencies sum to 1.
+                return j * W[i];
+            }
+            return fix(j, i);
+        }
+
+        /**
+         * Gets the value from the tail of the distribution.
+         *
+         * @param jz Start random integer.
+         * @param iz Index of cell corresponding to {@code jz}.
+         * @return the requested random value.
+         */
+        private double fix(long jz,
+                           int iz) {
+            if (iz == 0) {
+                // Base strip.
+                // This branch is called about 0.000448867 times per call into 
createSample.
+                return R - Math.log(rng.nextDouble());
+            }
+            // Wedge of other strips.
+            final double x = jz * W[iz];
+            if (F[iz] + rng.nextDouble() * (F[iz - 1] - F[iz]) < pdf(x)) {
+                // This branch is called about 0.0107820 times per call into 
createSample.
+                return x;
+            }
+            // Try again.
+            // This branch is called about 0.0109920 times per call into 
createSample
+            // i.e. this is the recursion frequency.
+            return sample();
+        }
+
+        /**
+         * Compute the exponential probability density function {@code f(x) = 
e^-x}.
+         *
+         * @param x Argument.
+         * @return {@code e^-x}
+         */
+        private static double pdf(double x) {
+            return Math.exp(-x);
+        }
+    }
+    /**
+     * Modified Ziggurat method for sampling from a Gaussian distribution with 
mean 0 and standard deviation 1.
+     *
+     * <p>Uses the algorithm from:
+     *
+     * <blockquote>
+     * McFarland, C.D. (2016)<br>
+     * "A modified ziggurat algorithm for generating exponentially and 
normally distributed pseudorandom numbers".<br>
+     * <i>Journal of Statistical Computation and Simulation</i> <b>86</b>, 
1281-1294.
+     * </blockquote>
+     *
+     * @see <a 
href="https://www.tandfonline.com/doi/abs/10.1080/00949655.2015.1060234";>
+     * McFarland (2016) JSCS 86, 1281-1294</a>
+     */
+    static class ModifiedZigguratNormalizedGaussianSampler implements 
ContinuousSampler {
+        /** Maximum i value for early exit. */
+        private static final int I_MAX = 253;
+        /** The point where the Gaussian switches from convex to concave. */
+        private static final int J_INFLECTION = 205;
+        /** Mask to create an unsigned long from a signed long. */
+        private static final long MAX_INT64 = 0x7fffffffffffffffL;
+        /** Used for largest deviations of f(x) from y_i. This is negated on 
purpose. */
+        private static final long MAX_IE = -2269182951627975918L;
+        /** Used for largest deviations of f(x) from y_i. */
+        private static final long MIN_IE = 760463704284035181L;
+        /** 2^63. */
+        private static final double TWO_POW_63 = 0x1.0p63;
+        /** Beginning of tail. */
+        private static final double X_0 = 3.6360066255;
+        /** 1/X_0. */
+        private static final double ONE_OVER_X_0 = 1d / X_0;
+
+        /** The alias map. An integer in [0, 255] stored as a byte to save 
space. */
+        private static final byte[] MAP = toBytes(
+            new int[] {0, 0, 239, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 251, 
251, 251, 251, 251, 251, 251, 250, 250, 250,
+                250, 250, 249, 249, 249, 248, 248, 248, 247, 247, 247, 246, 
246, 245, 244, 244, 243, 242, 240, 2, 2, 3,
+                3, 0, 0, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 
250, 251, 252, 253, 1, 0, 0});
+        /** The alias inverse PMF. */
+        private static final long[] IPMF = {9223372036854775807L, 
1100243796532604147L, 7866600928978262881L,
+            6788754710654027089L, 9022865200181691852L, 6522434035205505475L, 
4723064097359993915L,
+            3360495653216419673L, 2289663232373874393L, 1423968905551925104L, 
708364817827802907L, 106102487305606492L,
+            -408333464665790208L, -853239722779020926L, -1242095211825517037L, 
-1585059631105792592L,
+            -1889943050287164616L, -2162852901990665326L, 
-2408637386594506662L, -2631196530262949902L,
+            -2833704942520918738L, -3018774289025815052L, 
-3188573753472182441L, -3344920681707440829L,
+            -3489349705062145773L, -3623166100042174483L, 
-3747487436868330185L, -3863276422712168700L,
+            -3971367044063122321L, -4072485557029853479L, 
-4167267476830907467L, -4256271432240150335L,
+            -4339990541927301065L, -4418861817133796561L, 
-4493273980372371289L, -4563574004462236379L,
+            -4630072609770443287L, -4693048910430993529L, 
-4752754358862853623L, -4809416110052798111L,
+            -4863239903586974371L, -4914412541515869230L, 
-4963104028439154501L, -5009469424769141876L,
+            -5053650458856546947L, -5095776932695070785L, 
-5135967952544950843L, -5174333008451188631L,
+            -5210972924952682065L, -5245980700100453012L, 
-5279442247516290042L, -5311437055462362013L,
+            -5342038772315636138L, -5371315728843324427L, 
-5399331404632497705L, -5426144845493682879L,
+            -5451811038474681565L, -5476381248265612057L, 
-5499903320558330825L, -5522421955752302985L,
+            -5543978956085246988L, -5564613449659052023L, 
-5584362093436129148L, -5603259257517445975L,
+            -5621337193070977432L, -5638626184974114133L, 
-5655154691220924683L, -5670949470294749069L,
+            -5686035697601828417L, -5700437072199142976L, 
-5714175914219797723L, -5727273255295211389L,
+            -5739748920272022600L, -5751621603810396917L, 
-5762908939773930926L, -5773627565914992314L,
+            -5783793183152402325L, -5793420610475612574L, 
-5802523835894645221L, -5811116062947594592L,
+            -5819209754516104281L, -5826816672854561136L, 
-5833947916825296227L, -5840613956570562553L,
+            -5846824665591787384L, -5852589350491064419L, 
-5857916778480708968L, -5862815203334817577L,
+            -5867292388935689664L, -5871355631762300668L, 
-5875011781262872391L, -5878267259039068099L,
+            -5881128076579864607L, -5883599852028866964L, 
-5885687825288587920L, -5887396872144944193L,
+            -5888731517955022366L, -5889695949247708370L, 
-5890294025706661862L, -5890529289910843690L,
+            -5890404977676009159L, -5889924026487152552L, 
-5889089083913561497L, -5887902514965187544L,
+            -5886366408898350160L, -5884482585690660648L, 
-5882252601321067956L, -5879677752995005083L,
+            -5876759083794187244L, -5873497386318817608L, 
-5869893206505495615L, -5865946846617000703L,
+            -5861658367354170141L, -5857027590486142268L, 
-5852054100063403979L, -5846737243971479915L,
+            -5841076134082348607L, -5835069647234555080L, 
-5828716424754558627L, -5822014871949050545L,
+            -5814963157357505615L, -5807559211080035948L, 
-5799800723447248431L, -5791685142338046612L,
+            -5783209670985131963L, -5774371264582507258L, 
-5765166627072198898L, -5755592207057629351L,
+            -5745644193442020886L, -5735318510777140130L, 
-5724610813433637581L, -5713516480385064197L,
+            -5702030608511931905L, -5690148005851000163L, 
-5677863184109376595L, -5665170350903283020L,
+            -5652063400924584736L, -5638535907000098559L, 
-5624581109999495711L, -5610191908627545348L,
+            -5595360848093635657L, -5580080108034221525L, 
-5564341489875517452L, -5548136403221361788L,
+            -5531455851545388194L, -5514290416638313566L, 
-5496630242181647032L, -5478465016761708394L,
+            -5459783954986630496L, -5440575777891763554L, 
-5420828692432362328L, -5400530368638759086L,
+            -5379667916699386572L, -5358227861294079939L, 
-5336196115274289941L, -5313557951078348351L,
+            -5290297970633413513L, -5266400072915204637L, 
-5241847420213976978L, -5216622401043707762L,
+            -5190706591719514516L, -5164080714589163015L, 
-5136724594099061292L, -5108617109269271995L,
+            -5079736143458208314L, -5050058530461699570L, 
-5019559997031867155L, -4988215101008300666L,
+            -4955997165600740840L, -4922878208651982466L, 
-4888828866780310778L, -4853818314258448763L,
+            -4817814175855136221L, -4780782432601640934L, 
-4742687321746673837L, -4703491227581398702L,
+            -4663154564978669839L, -4621635653358718847L, 
-4578890580370737438L, -4534873055659651863L,
+            -4489534251700544707L, -4442822631898778778L, 
-4394683764809052552L, -4345060121983309848L,
+            -4293890858708851568L, -4241111576153757717L, 
-4186654061692562932L, -4130446006804691432L,
+            -4072410698657642967L, -4012466683838341666L, 
-3950527400304957273L, -3886500774061817392L,
+            -3820288777467775968L, -3751786943594814089L, 
-3680883832433444937L, -3607460442623855428L,
+            -3531389562483238811L, -3452535052936037985L, 
-3370751053395794721L, -3285881101589156030L,
+            -3197757155301271700L, -3106198503156390075L, 
-3011010550911843739L, -2911983463883482375L,
+            -2808890647470171482L, -2701487041141041038L, 
-2589507199690499622L, -2472663129329060997L,
+            -2350641842139723534L, -2223102583769914387L, 
-2089673683729348624L, -1949948966045216354L,
+            -1803483646855866339L, -1649789631524907106L, 
-1488330106094837958L, -1318513295725471712L,
+            -1139685236971903433L, -951121376551959675L, -752016768184573709L, 
-541474585687415681L,
+            -318492605680814263L, -81947227248966622L, 169425512568350963L, 
437052607277165029L, 722551297569085274L,
+            1027761939300002045L, 1354787941578333500L, 1706044619204253453L, 
2084319374409947591L,
+            2492846399638817506L, 2935400169348911565L, 3416413484613541924L, 
3941127949861028145L,
+            4515787798749165735L, 5147892401484995974L, 5846529325380992513L, 
6622819682194933019L,
+            7490522659874903812L, 8466869998278641829L, 8216968526368126501L, 
4550693915471153825L,
+            7628019504122306461L, 6605080500893076940L, 7121156327637209657L, 
2484871780365768829L,
+            7179104797069433749L, 7066086283825115773L, 1516500120794063563L, 
216305945442773460L, 6295963418513296140L,
+            2889316805672339623L, -2712587580543026574L, 6562498853519217374L, 
7975754821145999232L,
+            -9223372036854775807L, -9223372036854775807L};
+        /**
+         * The precomputed ziggurat lengths, denoted X_i in the main text. X_i 
= length of
+         * ziggurat layer i.
+         */
+        private static final double[] X = {3.94216628254e-19, 
3.72049450041e-19, 3.58270244806e-19, 3.48074762365e-19,
+            3.39901771719e-19, 3.33037783603e-19, 3.27094388176e-19, 
3.21835771325e-19, 3.17107585418e-19,
+            3.1280307407e-19, 3.08845206558e-19, 3.05176506241e-19, 
3.01752902926e-19, 2.98539834407e-19,
+            2.95509674628e-19, 2.92639979885e-19, 2.899122587e-19, 
2.87311087802e-19, 2.84823463271e-19,
+            2.82438315352e-19, 2.80146139647e-19, 2.77938712618e-19, 
2.75808869214e-19, 2.73750326983e-19,
+            2.71757545434e-19, 2.69825612475e-19, 2.67950151888e-19, 
2.66127247304e-19, 2.6435337928e-19,
+            2.6262537282e-19, 2.60940353352e-19, 2.59295709543e-19, 
2.57689061732e-19, 2.56118234977e-19,
+            2.54581235934e-19, 2.53076232924e-19, 2.51601538678e-19, 
2.50155595336e-19, 2.48736961354e-19,
+            2.47344300031e-19, 2.45976369429e-19, 2.44632013479e-19, 
2.43310154111e-19, 2.42009784271e-19,
+            2.40729961704e-19, 2.39469803409e-19, 2.38228480673e-19, 
2.37005214619e-19, 2.35799272207e-19,
+            2.34609962621e-19, 2.33436634011e-19, 2.32278670547e-19, 
2.31135489743e-19, 2.30006540027e-19,
+            2.28891298528e-19, 2.27789269059e-19, 2.26699980275e-19, 
2.25622983985e-19, 2.24557853607e-19,
+            2.23504182749e-19, 2.22461583905e-19, 2.21429687253e-19, 
2.20408139549e-19, 2.19396603103e-19,
+            2.18394754837e-19, 2.17402285409e-19, 2.164188984e-19, 
2.15444309566e-19, 2.14478246135e-19,
+            2.13520446164e-19, 2.12570657924e-19, 2.11628639347e-19, 
2.10694157491e-19, 2.09766988055e-19,
+            2.08846914916e-19, 2.079337297e-19, 2.0702723138e-19, 
2.06127225897e-19, 2.05233525809e-19,
+            2.04345949953e-19, 2.03464323137e-19, 2.02588475842e-19, 
2.01718243948e-19, 2.00853468469e-19,
+            1.99993995309e-19, 1.9913967503e-19, 1.9829036263e-19, 
1.97445917335e-19, 1.96606202405e-19,
+            1.95771084943e-19, 1.94940435722e-19, 1.9411412902e-19, 
1.93292042452e-19, 1.92474056827e-19,
+            1.91660056003e-19, 1.90849926746e-19, 1.90043558606e-19, 
1.89240843788e-19, 1.88441677035e-19,
+            1.87645955517e-19, 1.86853578721e-19, 1.8606444835e-19, 
1.85278468221e-19, 1.84495544175e-19,
+            1.83715583984e-19, 1.82938497262e-19, 1.82164195388e-19, 
1.81392591419e-19, 1.80623600019e-19,
+            1.7985713738e-19, 1.79093121154e-19, 1.78331470384e-19, 
1.77572105435e-19, 1.76814947933e-19,
+            1.76059920701e-19, 1.753069477e-19, 1.74555953971e-19, 
1.73806865576e-19, 1.73059609547e-19,
+            1.72314113829e-19, 1.71570307233e-19, 1.70828119379e-19, 
1.7008748065e-19, 1.69348322146e-19,
+            1.68610575631e-19, 1.67874173493e-19, 1.67139048692e-19, 
1.66405134721e-19, 1.6567236556e-19,
+            1.64940675631e-19, 1.64209999755e-19, 1.63480273116e-19, 
1.62751431209e-19, 1.62023409806e-19,
+            1.61296144913e-19, 1.60569572726e-19, 1.59843629593e-19, 
1.59118251972e-19, 1.58393376391e-19,
+            1.57668939404e-19, 1.56944877552e-19, 1.56221127324e-19, 
1.55497625108e-19, 1.54774307158e-19,
+            1.54051109542e-19, 1.53327968107e-19, 1.52604818431e-19, 
1.51881595777e-19, 1.51158235054e-19,
+            1.50434670764e-19, 1.49710836959e-19, 1.48986667191e-19, 
1.48262094465e-19, 1.47537051186e-19,
+            1.46811469107e-19, 1.46085279278e-19, 1.4535841199e-19, 
1.44630796717e-19, 1.43902362058e-19,
+            1.43173035676e-19, 1.42442744238e-19, 1.41711413344e-19, 
1.40978967466e-19, 1.40245329873e-19,
+            1.39510422558e-19, 1.38774166165e-19, 1.38036479905e-19, 
1.37297281475e-19, 1.36556486972e-19,
+            1.35814010798e-19, 1.35069765568e-19, 1.34323662007e-19, 
1.33575608847e-19, 1.32825512715e-19,
+            1.32073278015e-19, 1.31318806805e-19, 1.30561998669e-19, 
1.29802750579e-19, 1.29040956749e-19,
+            1.28276508483e-19, 1.2750929401e-19, 1.26739198313e-19, 
1.25966102948e-19, 1.25189885844e-19,
+            1.24410421101e-19, 1.23627578765e-19, 1.22841224598e-19, 
1.2205121982e-19, 1.21257420848e-19,
+            1.20459679002e-19, 1.19657840201e-19, 1.18851744634e-19, 
1.18041226403e-19, 1.17226113142e-19,
+            1.16406225609e-19, 1.15581377245e-19, 1.14751373693e-19, 
1.13916012285e-19, 1.13075081485e-19,
+            1.12228360281e-19, 1.11375617531e-19, 1.10516611251e-19, 
1.09651087832e-19, 1.08778781199e-19,
+            1.07899411881e-19, 1.07012685997e-19, 1.06118294148e-19, 
1.05215910191e-19, 1.043051899e-19,
+            1.0338576948e-19, 1.02457263929e-19, 1.01519265222e-19, 
1.00571340295e-19, 9.96130287997e-20,
+            9.86438405995e-20, 9.76632529648e-20, 9.66707074276e-20, 
9.56656062409e-20, 9.46473083804e-20,
+            9.36151250173e-20, 9.25683143709e-20, 9.15060758376e-20, 
9.04275432677e-20, 8.93317772338e-20,
+            8.82177561023e-20, 8.70843656749e-20, 8.59303871096e-20, 
8.47544827642e-20, 8.35551795085e-20,
+            8.23308489336e-20, 8.10796837291e-20, 7.97996692841e-20, 
7.84885492861e-20, 7.71437837009e-20,
+            7.57624969795e-20, 7.43414135785e-20, 7.28767768074e-20, 
7.13642454435e-20, 6.97987602408e-20,
+            6.81743689448e-20, 6.64839929862e-20, 6.47191103452e-20, 
6.28693148131e-20, 6.09216875483e-20,
+            5.88598735756e-20, 5.66626751161e-20, 5.43018136309e-20, 
5.17381717445e-20, 4.89150317224e-20,
+            4.57447418908e-20, 4.20788025686e-20, 3.76259867224e-20, 
3.16285898059e-20, 0.0};
+        /** Overhang table. Y_i = f(X_i). */
+        private static final double[] Y = {1.45984107966e-22, 
3.00666134279e-22, 4.61297288151e-22, 6.26633500492e-22,
+            7.95945247619e-22, 9.68746550217e-22, 1.14468770024e-21, 
1.32350363044e-21, 1.50498576921e-21,
+            1.68896530007e-21, 1.87530253827e-21, 2.06387984237e-21, 
2.25459669136e-21, 2.44736615188e-21,
+            2.64211227278e-21, 2.83876811879e-21, 3.03727425675e-21, 
3.23757757e-21, 3.43963031579e-21,
+            3.6433893658e-21, 3.84881558689e-21, 4.05587333095e-21, 
4.26453001043e-21, 4.47475574223e-21,
+            4.68652304654e-21, 4.89980659028e-21, 5.11458296721e-21, 
5.3308305082e-21, 5.5485291167e-21,
+            5.76766012527e-21, 5.98820616992e-21, 6.21015107954e-21, 
6.43347977823e-21, 6.65817819857e-21,
+            6.88423320459e-21, 7.1116325228e-21, 7.34036468049e-21, 
7.57041895029e-21, 7.80178530014e-21,
+            8.03445434816e-21, 8.26841732173e-21, 8.50366602039e-21, 
8.74019278201e-21, 8.97799045203e-21,
+            9.21705235531e-21, 9.45737227039e-21, 9.69894440593e-21, 
9.94176337898e-21, 1.01858241951e-20,
+            1.04311222301e-20, 1.0677653213e-20, 1.09254132104e-20, 
1.11743986124e-20, 1.14246061187e-20,
+            1.16760327269e-20, 1.19286757204e-20, 1.21825326583e-20, 
1.24376013654e-20, 1.2693879923e-20,
+            1.29513666605e-20, 1.32100601473e-20, 1.34699591858e-20, 
1.37310628045e-20, 1.39933702514e-20,
+            1.42568809885e-20, 1.4521594686e-20, 1.47875112175e-20, 
1.50546306552e-20, 1.53229532653e-20,
+            1.55924795044e-20, 1.58632100153e-20, 1.61351456238e-20, 
1.64082873355e-20, 1.66826363327e-20,
+            1.69581939719e-20, 1.72349617811e-20, 1.75129414576e-20, 
1.77921348663e-20, 1.80725440373e-20,
+            1.83541711644e-20, 1.86370186038e-20, 1.89210888728e-20, 
1.92063846482e-20, 1.94929087658e-20,
+            1.97806642193e-20, 2.00696541597e-20, 2.03598818948e-20, 
2.06513508884e-20, 2.09440647607e-20,
+            2.12380272876e-20, 2.15332424009e-20, 2.18297141884e-20, 
2.21274468943e-20, 2.24264449191e-20,
+            2.27267128206e-20, 2.30282553143e-20, 2.33310772738e-20, 
2.36351837324e-20, 2.39405798832e-20,
+            2.42472710808e-20, 2.45552628422e-20, 2.48645608479e-20, 
2.5175170944e-20, 2.54870991431e-20,
+            2.58003516259e-20, 2.61149347436e-20, 2.64308550193e-20, 
2.67481191499e-20, 2.70667340088e-20,
+            2.73867066474e-20, 2.77080442982e-20, 2.80307543767e-20, 
2.83548444847e-20, 2.86803224123e-20,
+            2.90071961414e-20, 2.93354738484e-20, 2.96651639078e-20, 
2.99962748948e-20, 3.03288155897e-20,
+            3.06627949809e-20, 3.09982222687e-20, 3.13351068696e-20, 
3.16734584202e-20, 3.20132867816e-20,
+            3.23546020438e-20, 3.26974145302e-20, 3.30417348029e-20, 
3.33875736673e-20, 3.37349421775e-20,
+            3.40838516421e-20, 3.44343136293e-20, 3.4786339973e-20, 
3.51399427794e-20, 3.54951344328e-20,
+            3.58519276026e-20, 3.62103352501e-20, 3.65703706358e-20, 
3.69320473266e-20, 3.7295379204e-20,
+            3.76603804721e-20, 3.80270656658e-20, 3.83954496597e-20, 
3.87655476775e-20, 3.91373753011e-20,
+            3.95109484807e-20, 3.98862835454e-20, 4.02633972133e-20, 
4.06423066034e-20, 4.10230292468e-20,
+            4.14055830991e-20, 4.1789986553e-20, 4.21762584518e-20, 
4.25644181026e-20, 4.29544852916e-20,
+            4.33464802983e-20, 4.3740423912e-20, 4.41363374476e-20, 
4.45342427632e-20, 4.49341622781e-20,
+            4.53361189911e-20, 4.5740136501e-20, 4.61462390263e-20, 
4.65544514274e-20, 4.69647992292e-20,
+            4.73773086444e-20, 4.77920065987e-20, 4.82089207569e-20, 
4.86280795501e-20, 4.90495122048e-20,
+            4.94732487728e-20, 4.98993201633e-20, 5.03277581761e-20, 
5.07585955372e-20, 5.11918659356e-20,
+            5.16276040629e-20, 5.20658456539e-20, 5.25066275307e-20, 
5.29499876488e-20, 5.33959651452e-20,
+            5.38446003902e-20, 5.42959350421e-20, 5.47500121042e-20, 
5.52068759864e-20, 5.566657257e-20,
+            5.61291492763e-20, 5.65946551399e-20, 5.70631408865e-20, 
5.75346590156e-20, 5.80092638886e-20,
+            5.8487011823e-20, 5.89679611927e-20, 5.94521725351e-20, 
5.99397086661e-20, 6.04306348026e-20,
+            6.09250186942e-20, 6.14229307644e-20, 6.19244442624e-20, 
6.24296354262e-20, 6.29385836583e-20,
+            6.34513717154e-20, 6.39680859128e-20, 6.44888163458e-20, 
6.5013657129e-20, 6.55427066567e-20,
+            6.60760678847e-20, 6.66138486374e-20, 6.71561619424e-20, 
6.7703126396e-20, 6.82548665622e-20,
+            6.88115134113e-20, 6.93732047997e-20, 6.9940085999e-20, 
7.05123102793e-20, 7.10900395534e-20,
+            7.16734450906e-20, 7.22627083097e-20, 7.28580216611e-20, 
7.3459589613e-20, 7.4067629755e-20,
+            7.46823740371e-20, 7.53040701672e-20, 7.59329831907e-20, 
7.65693972825e-20, 7.72136177895e-20,
+            7.78659735664e-20, 7.85268196595e-20, 7.91965404039e-20, 
7.9875553017e-20, 8.05643117889e-20,
+            8.12633129964e-20, 8.19731007037e-20, 8.26942736526e-20, 
8.34274935088e-20, 8.41734948075e-20,
+            8.49330970528e-20, 8.57072195782e-20, 8.64968999859e-20, 
8.73033172957e-20, 8.81278213789e-20,
+            8.89719709282e-20, 8.98375832393e-20, 9.07268006979e-20, 
9.16421814841e-20, 9.25868264067e-20,
+            9.35645614803e-20, 9.45802100126e-20, 9.56400155509e-20, 
9.67523347705e-20, 9.79288516978e-20,
+            9.91869058575e-20, 1.00554562713e-19, 1.02084073773e-19, 
1.03903609932e-19, 1.08420217249e-19};
+
+        /** Underlying source of randomness. */
+        private final UniformRandomProvider rng;
+        /** Exponential sampler used for the long tail. */
+        private final ContinuousSampler exponential;
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         */
+        ModifiedZigguratNormalizedGaussianSampler(UniformRandomProvider rng) {
+            this.rng = rng;
+            exponential = new ModifiedZigguratExponentialSampler(rng);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double sample() {
+            final long xx = rng.nextLong();
+            // Float multiplication squashes these last 8 bits, so they can be 
used to sample i
+            final int i = ((int) xx) & 0xff;
+
+            if (i < I_MAX) {
+                // Early exit.
+                // Branch frequency: 0.988280
+                return X[i] * xx;
+            }
+
+            long u1 = randomInt63();
+            // Another squashed, recyclable bit
+            // double sign_bit = u1 & 0x100 ? 1. : -1.
+            // Use 2 - 1 or 0 - 1
+            final double signBit = ((u1 >>> 7) & 0x2) - 1.0;
+            final int j = normSampleA();
+            // Four kinds of overhangs:
+            //  j = 0                :  Sample from tail
+            //  0 < j < J_INFLECTION :  Overhang is concave; only sample from 
Lower-Left triangle
+            //  j = J_INFLECTION     :  Must sample from entire overhang 
rectangle
+            //  j > J_INFLECTION     :  Overhangs are convex; implicitly 
accept point in Lower-Left triangle
+            //
+            // Conditional statements are arranged such that the more likely 
outcomes are first.
+            double x;
+            if (j > J_INFLECTION) {
+                // Convex overhang
+                // Branch frequency: 0.00891413
+                for (;;) {
+                    x = fastPrngSampleX(j, u1);
+                    final long uDiff = randomInt63() - u1;
+                    if (uDiff > MIN_IE) {
+                        break;
+                    }
+                    if (uDiff < MAX_IE) {
+                        continue;
+                    }
+                    // Long.MIN_VALUE is used as an unsigned int with value 
2^63:
+                    // uy = Long.MIN_VALUE - (ux + uDiff)
+                    if (fastPrngSampleY(j, Long.MIN_VALUE - (u1 + uDiff)) < 
Math.exp(-0.5 * x * x)) {
+                        break;
+                    }
+                    u1 = randomInt63();
+                }
+            } else if (j == 0) {
+                // Tail
+                // Branch frequency: 0.000277067
+                do {
+                    x = ONE_OVER_X_0 * exponential.sample();
+                } while (exponential.sample() < 0.5 * x * x);
+                x += X_0;
+            } else if (j < J_INFLECTION) {
+                // Concave overhang
+                // Branch frequency: 0.00251223
+                for (;;) {
+                    // U_x <- min(U_1, U_2)
+                    // distance <- | U_1 - U_2 |
+                    // U_y <- 1 - (U_x + distance)
+                    long uDiff = randomInt63() - u1;
+                    if (uDiff < 0) {
+                        uDiff = -uDiff;
+                        u1 -= uDiff;
+                    }
+                    x = fastPrngSampleX(j, u1);
+                    if (uDiff > MIN_IE)  {
+                        break;
+                    }
+                    if (fastPrngSampleY(j, Long.MIN_VALUE - (u1 + uDiff)) < 
Math.exp(-0.5 * x * x)) {
+                        break;
+                    }
+                    u1 = randomInt63();
+                }
+            } else {
+                // Inflection point
+                // Branch frequency: 0.0000161147
+                for (;;) {
+                    x = fastPrngSampleX(j, u1);
+                    if (fastPrngSampleY(j, randomInt63()) < Math.exp(-0.5 * x 
* x)) {
+                        break;
+                    }
+                    u1 = randomInt63();
+                }
+            }
+            return signBit * x;
+        }
+
+        /**
+         * Alias sampling.
+         * See http://scorevoting.net/WarrenSmithPages/homepage/sampling.abs
+         *
+         * @return the alias
+         */
+        private int normSampleA() {
+            final long x = rng.nextLong();
+            // j <- I(0, 256)
+            final int j = ((int) x) & 0xff;
+            return x >= IPMF[j] ? MAP[j] & 0xff : j;
+        }
+
+        /**
+         * Return a positive long in {@code [0, 2^63)}.
+         *
+         * @return the long
+         */
+        private long randomInt63() {
+            return rng.nextLong() & MAX_INT64;
+        }
+
+        /**
+         * Auxilary function to see if rejection sampling is required in the 
overhang.
+         * See Fig. 2 in the main text.
+         *
+         * @param j j
+         * @param ux ux
+         * @return the sample
+         */
+        private static double fastPrngSampleX(int j, long ux) {
+            return X[j] * TWO_POW_63 + (X[j - 1] - X[j]) * ux;
+        }
+
+        /**
+         * Auxilary function to see if rejection sampling is required in the 
overhang.
+         * See Fig. 2 in the main text.
+         *
+         * @param i i
+         * @param uy uy
+         * @return the sample
+         */
+        private static double fastPrngSampleY(int i, long uy) {
+            return Y[i - 1] * TWO_POW_63 + (Y[i] - Y[i - 1]) * uy;
+        }
+
+        /**
+         * Helper function to convert {@code int} values to bytes using a 
narrowing primitive conversion.
+         *
+         * @param values Integer values.
+         * @return the bytes
+         */
+        private static byte[] toBytes(int[] values) {
+            final byte[] bytes = new byte[values.length];
+            for (int i = 0; i < bytes.length; i++) {
+                bytes[i] = (byte) values[i];
+            }
+            return bytes;
+        }
+    }
+
+    /**
+     * Modified Ziggurat method for sampling from an exponential distribution.
+     *
+     * <p>Uses the algorithm from:
+     *
+     * <blockquote>
+     * McFarland, C.D. (2016)<br>
+     * "A modified ziggurat algorithm for generating exponentially and 
normally distributed pseudorandom numbers".<br>
+     * <i>Journal of Statistical Computation and Simulation</i> <b>86</b>, 
1281-1294.
+     * </blockquote>
+     *
+     * @see <a 
href="https://www.tandfonline.com/doi/abs/10.1080/00949655.2015.1060234";>
+     * McFarland (2016) JSCS 86, 1281-1294</a>
+     */
+    static class ModifiedZigguratExponentialSampler implements 
ContinuousSampler {
+        /** Maximum i value for early exit. */
+        private static final int I_MAX = 252;
+        /** Mask to create an unsigned long from a signed long. */
+        private static final long MAX_INT64 = 0x7fffffffffffffffL;
+        /** Maximum distance value for early exit. */
+        private static final long IE_MAX = 513303011048449572L;
+        /** 2^53. */
+        private static final double TWO_POW_63 = 0x1.0p63;
+        /** Beginning of tail. */
+        private static final double X_0 = 7.56927469415;
+
+        /** The alias map. An integer in [0, 255] stored as a byte to save 
space. */
+        private static final byte[] MAP = toBytes(new int[] {0, 0, 1, 235, 3, 
4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+            1, 1, 1, 2, 2, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 251, 251, 251, 251, 
251, 251, 251, 251, 251, 251, 251, 251,
+            251, 250, 250, 250, 250, 250, 250, 250, 249, 249, 249, 249, 249, 
249, 248, 248, 248, 248, 247, 247, 247,
+            247, 246, 246, 246, 245, 245, 244, 244, 243, 243, 242, 241, 241, 
240, 239, 237, 3, 3, 4, 4, 6, 0, 0, 0, 0,
+            236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 
249, 250, 251, 252, 2, 0, 0, 0});
+        /** The alias inverse PMF. */
+        private static final long[] IPMF = {9223372036854775328L, 
1623796909450838420L, 2664290944894293715L,
+            7387971354164060121L, 6515064486552739054L, 8840508362680717952L, 
6099647593382935246L,
+            7673130333659513959L, 6220332867583438265L, 5045979640552813853L, 
4075305837223955667L,
+            3258413672162525563L, 2560664887087762661L, 1957224924672899759L, 
1429800935350577626L, 964606309710808357L,
+            551043923599587249L, 180827629096890397L, -152619738120023526L, 
-454588624410291449L, -729385126147774875L,
+            -980551509819446846L, -1211029700667463872L, 
-1423284293868547154L, -1619396356369050292L,
+            -1801135830956212822L, -1970018048575618008L, 
-2127348289059705241L, -2274257249303686299L,
+            -2411729520096655228L, -2540626634159182525L, 
-2661705860113406462L, -2775635634532448735L,
+            -2883008316030465121L, -2984350790383654722L, 
-3080133339198118434L, -3170777096303091107L,
+            -3256660348483804932L, -3338123885075152741L, 
-3415475560473282822L, -3488994201966444710L,
+            -3558932970354470759L, -3625522261068041096L, 
-3688972217741992040L, -3749474917563782729L,
+            -3807206277531056234L, -3862327722496827274L, 
-3914987649156779787L, -3965322714631865323L,
+            -4013458973776912076L, -4059512885612767084L, 
-4103592206186241133L, -4145796782586128173L,
+            -4186219260694363437L, -4224945717447258894L, 
-4262056226866285614L, -4297625367836519694L,
+            -4331722680528537423L, -4364413077437472623L, 
-4395757214229418223L, -4425811824915119504L,
+            -4454630025296932688L, -4482261588141311280L, 
-4508753193105271888L, -4534148654077804689L,
+            -4558489126279970065L, -4581813295192216657L, 
-4604157549138257681L, -4625556137145250418L,
+            -4646041313519109426L, -4665643470413305970L, 
-4684391259530326642L, -4702311703971761747L,
+            -4719430301145086931L, -4735771117539946355L, 
-4751356876102103699L, -4766209036859128403L,
+            -4780347871386013331L, -4793792531638892019L, 
-4806561113635122292L, -4818670716409312756L,
+            -4830137496634465780L, -4840976719260854452L, 
-4851202804490332660L, -4860829371376460084L,
+            -4869869278311657652L, -4878334660640771092L, 
-4886236965617427412L, -4893586984900802772L,
+            -4900394884772702964L, -4906670234238885493L, 
-4912422031164489589L, -4917658726580136309L,
+            -4922388247283532373L, -4926618016851059029L, 
-4930354975163335189L, -4933605596540651285L,
+            -4936375906575303797L, -4938671497741365845L, 
-4940497543854575637L, -4941858813449629493L,
+            -4942759682136114997L, -4943204143989086773L, 
-4943195822025527893L, -4942737977813206357L,
+            -4941833520255033237L, -4940485013586738773L, 
-4938694684624359381L, -4936464429291795925L,
+            -4933795818458825557L, -4930690103114057941L, 
-4927148218896868949L, -4923170790008275925L,
+            -4918758132519202261L, -4913910257091645845L, 
-4908626871126550421L, -4902907380349522964L,
+            -4896750889844289364L, -4890156204540514772L, 
-4883121829162554452L, -4875645967641803284L,
+            -4867726521994894420L, -4859361090668136340L, 
-4850546966345097428L, -4841281133215539220L,
+            -4831560263698486164L, -4821380714613453652L, 
-4810738522790066260L, -4799629400105482131L,
+            -4788048727936313747L, -4775991551010508883L, 
-4763452570642098131L, -4750426137329511059L,
+            -4736906242696389331L, -4722886510751361491L, 
-4708360188440098835L, -4693320135461437394L,
+            -4677758813316075410L, -4661668273553512594L, 
-4645040145179234642L, -4627865621182772242L,
+            -4610135444140937425L, -4591839890849345681L, 
-4572968755929937937L, -4553511334358205905L,
+            -4533456402849118097L, -4512792200036279121L, 
-4491506405372581072L, -4469586116675402576L,
+            -4447017826233108176L, -4423787395382268560L, 
-4399880027458432847L, -4375280239014115151L,
+            -4349971829190464271L, -4323937847117722127L, 
-4297160557210950158L, -4269621402214950094L,
+            -4241300963840749518L, -4212178920821845518L, 
-4182234004204468173L, -4151443949668868493L,
+            -4119785446662289613L, -4087234084103201932L, 
-4053764292396157324L, -4019349281473091724L,
+            -3983960974549676683L, -3947569937258407435L, 
-3910145301787369227L, -3871654685619016074L,
+            -3832064104425399050L, -3791337878631545353L, 
-3749438533114317833L, -3706326689447995081L,
+            -3661960950051848712L, -3616297773528535240L, 
-3569291340409179143L, -3520893408440946503L,
+            -3471053156460654726L, -3419717015797782918L, 
-3366828488034800645L, -3312327947826472069L,
+            -3256152429334011012L, -3198235394669703364L, 
-3138506482563184963L, -3076891235255163586L,
+            -3013310801389731586L, -2947681612411375617L, 
-2879915029671665601L, -2809916959107518656L,
+            -2737587429961872959L, -2662820133571326270L, 
-2585501917733374398L, -2505512231579382333L,
+            -2422722515205206076L, -2336995527534112187L, 
-2248184604988688954L, -2156132842510798521L,
+            -2060672187261006776L, -1961622433929382455L, 
-1858790108950092598L, -1751967229002903349L,
+            -1640929916937143604L, -1525436855617592627L, 
-1405227557075244850L, -1280020420662660017L,
+            -1149510549536587824L, -1013367289578705710L, 
-871231448632088621L, -722712146453685035L,
+            -567383236774420522L, -404779231966955560L, -234390647591522471L, 
-55658667960120229L, 132030985907824093L,
+            329355128892810847L, 537061298001092449L, 755977262693571427L, 
987022116608031845L, 1231219266829421544L,
+            1489711711346525930L, 1763780090187560429L, 2054864117341776240L, 
2364588157623792755L,
+            2694791916990483702L, 3047567482883492729L, 3425304305830814717L, 
3830744187097279873L,
+            4267048975685831301L, 4737884547990035082L, 5247525842198997007L, 
5800989391535354004L,
+            6404202162993293978L, 7064218894258529185L, 7789505049452340392L, 
8590309807749443504L,
+            7643763810684498323L, 8891950541491447639L, 5457384281016226081L, 
9083704440929275131L,
+            7976211653914439517L, 8178631350487107662L, 2821287825726743868L, 
6322989683301723979L,
+            4309503753387603546L, 4685170734960182655L, 8404845967535219911L, 
7330522972447586582L,
+            1960945799077017972L, 4742910674644930459L, -751799822533465632L, 
7023456603741994979L,
+            3843116882594690323L, 3927231442413903597L, -9223372036854775807L, 
-9223372036854775807L,
+            -9223372036854775807L};
+        /** The precomputed ziggurat lengths, denoted X_i in the main text. */
+        private static final double[] X_I = {8.20662406753e-19, 
7.39737323516e-19, 6.91333133779e-19, 6.5647358821e-19,
+            6.29125399598e-19, 6.06572241296e-19, 5.87352761037e-19, 
5.70588505285e-19, 5.55709456916e-19,
+            5.42324389037e-19, 5.30152976965e-19, 5.18987392577e-19, 
5.0866922618e-19, 4.99074929388e-19,
+            4.90106258944e-19, 4.81683790106e-19, 4.73742386536e-19, 
4.66227958072e-19, 4.59095090178e-19,
+            4.52305277907e-19, 4.45825588164e-19, 4.39627631264e-19, 
4.33686759671e-19, 4.27981436185e-19,
+            4.22492730271e-19, 4.17203912535e-19, 4.12100125225e-19, 
4.07168112259e-19, 4.0239599631e-19,
+            3.97773093429e-19, 3.93289757853e-19, 3.88937251293e-19, 
3.84707632187e-19, 3.80593661382e-19,
+            3.76588721385e-19, 3.7268674692e-19, 3.68882164922e-19, 
3.65169842488e-19, 3.61545041533e-19,
+            3.58003379153e-19, 3.54540792845e-19, 3.51153509888e-19, 
3.478380203e-19, 3.44591052889e-19,
+            3.41409553966e-19, 3.38290668387e-19, 3.35231722623e-19, 
3.32230209587e-19, 3.29283775028e-19,
+            3.26390205282e-19, 3.23547416228e-19, 3.20753443311e-19, 
3.18006432505e-19, 3.15304632118e-19,
+            3.12646385343e-19, 3.10030123469e-19, 3.07454359701e-19, 
3.049176835e-19, 3.02418755411e-19,
+            2.99956302321e-19, 2.97529113107e-19, 2.95136034631e-19, 
2.92775968057e-19, 2.90447865454e-19,
+            2.88150726664e-19, 2.85883596399e-19, 2.83645561563e-19, 
2.81435748768e-19, 2.79253322026e-19,
+            2.77097480612e-19, 2.74967457073e-19, 2.72862515379e-19, 
2.70781949192e-19, 2.68725080264e-19,
+            2.66691256932e-19, 2.64679852713e-19, 2.62690264997e-19, 
2.60721913814e-19, 2.58774240685e-19,
+            2.56846707542e-19, 2.54938795718e-19, 2.53050004991e-19, 
2.51179852691e-19, 2.49327872862e-19,
+            2.47493615466e-19, 2.45676645638e-19, 2.43876542983e-19, 
2.42092900908e-19, 2.40325326001e-19,
+            2.38573437435e-19, 2.36836866406e-19, 2.35115255607e-19, 
2.33408258722e-19, 2.31715539953e-19,
+            2.3003677357e-19, 2.28371643478e-19, 2.2671984282e-19, 
2.2508107358e-19, 2.23455046227e-19,
+            2.21841479361e-19, 2.20240099382e-19, 2.18650640175e-19, 
2.17072842808e-19, 2.15506455249e-19,
+            2.13951232087e-19, 2.12406934276e-19, 2.10873328882e-19, 
2.09350188851e-19, 2.07837292773e-19,
+            2.06334424671e-19, 2.04841373792e-19, 2.03357934403e-19, 
2.01883905608e-19, 2.00419091156e-19,
+            1.98963299272e-19, 1.97516342486e-19, 1.96078037473e-19, 
1.94648204892e-19, 1.93226669243e-19,
+            1.9181325872e-19, 1.90407805074e-19, 1.89010143478e-19, 
1.87620112397e-19, 1.86237553469e-19,
+            1.8486231138e-19, 1.83494233754e-19, 1.82133171034e-19, 
1.80778976379e-19, 1.79431505561e-19,
+            1.78090616856e-19, 1.76756170954e-19, 1.75428030858e-19, 
1.74106061794e-19, 1.7279013112e-19,
+            1.71480108238e-19, 1.7017586451e-19, 1.68877273172e-19, 
1.67584209255e-19, 1.66296549505e-19,
+            1.65014172306e-19, 1.63736957602e-19, 1.62464786823e-19, 
1.61197542813e-19, 1.59935109756e-19,
+            1.58677373107e-19, 1.57424219521e-19, 1.56175536784e-19, 
1.54931213746e-19, 1.5369114025e-19,
+            1.52455207068e-19, 1.51223305837e-19, 1.49995328986e-19, 
1.48771169674e-19, 1.47550721726e-19,
+            1.46333879563e-19, 1.4512053814e-19, 1.43910592874e-19, 
1.42703939586e-19, 1.41500474425e-19,
+            1.40300093807e-19, 1.39102694344e-19, 1.37908172772e-19, 
1.36716425886e-19, 1.35527350466e-19,
+            1.34340843201e-19, 1.3315680062e-19, 1.31975119012e-19, 
1.3079569435e-19, 1.29618422208e-19,
+            1.28443197683e-19, 1.27269915307e-19, 1.26098468959e-19, 
1.24928751776e-19, 1.23760656057e-19,
+            1.22594073168e-19, 1.21428893439e-19, 1.20265006056e-19, 
1.19102298955e-19, 1.17940658704e-19,
+            1.16779970383e-19, 1.15620117456e-19, 1.14460981638e-19, 
1.13302442758e-19, 1.12144378607e-19,
+            1.10986664787e-19, 1.0982917454e-19, 1.08671778581e-19, 
1.07514344905e-19, 1.06356738599e-19,
+            1.05198821625e-19, 1.04040452605e-19, 1.02881486575e-19, 
1.01721774741e-19, 1.00561164199e-19,
+            9.93994976483e-20, 9.82366130767e-20, 9.70723434263e-20, 
9.59065162307e-20, 9.47389532242e-20,
+            9.35694699202e-20, 9.23978751546e-20, 9.12239705906e-20, 
9.00475501809e-20, 8.88683995826e-20,
+            8.76862955198e-20, 8.65010050861e-20, 8.53122849831e-20, 
8.41198806844e-20, 8.29235255165e-20,
+            8.1722939648e-20, 8.05178289728e-20, 7.93078838751e-20, 
7.80927778595e-20, 7.68721660284e-20,
+            7.5645683384e-20, 7.44129429302e-20, 7.31735335451e-20, 
7.19270175876e-20, 7.06729281977e-20,
+            6.94107662395e-20, 6.81399968293e-20, 6.68600453746e-20, 
6.55702930402e-20, 6.42700715334e-20,
+            6.29586570809e-20, 6.16352634381e-20, 6.02990337322e-20, 
5.89490308929e-20, 5.75842263599e-20,
+            5.62034866696e-20, 5.48055574135e-20, 5.3389043909e-20, 
5.1952387718e-20, 5.04938378663e-20,
+            4.90114152226e-20, 4.75028679334e-20, 4.59656150013e-20, 
4.4396673898e-20, 4.27925663021e-20,
+            4.11491932734e-20, 3.94616667626e-20, 3.77240771314e-20, 
3.59291640862e-20, 3.40678366911e-20,
+            3.21284476416e-20, 3.00956469164e-20, 2.79484694556e-20, 
2.56569130487e-20, 2.31752097568e-20,
+            2.04266952283e-20, 1.72617703302e-20, 1.32818892594e-20, 0.0};
+        /** Overhang table. */
+        private static final double[] Y = {5.59520549511e-23, 
1.18025099827e-22, 1.84444233867e-22, 2.54390304667e-22,
+            3.27376943115e-22, 4.03077321327e-22, 4.81254783195e-22, 
5.61729148966e-22, 6.44358205404e-22,
+            7.29026623435e-22, 8.15638884563e-22, 9.04114536835e-22, 
9.94384884864e-22, 1.0863906046e-21,
+            1.18007997755e-21, 1.27540755348e-21, 1.37233311764e-21, 
1.47082087944e-21, 1.57083882574e-21,
+            1.67235819844e-21, 1.7753530675e-21, 1.87979997851e-21, 
1.98567765878e-21, 2.09296677041e-21,
+            2.201649701e-21, 2.31171038523e-21, 2.42313415161e-21, 
2.53590759014e-21, 2.65001843742e-21,
+            2.76545547637e-21, 2.88220844835e-21, 3.00026797575e-21, 
3.11962549361e-21, 3.24027318888e-21,
+            3.36220394642e-21, 3.48541130074e-21, 3.60988939279e-21, 
3.7356329311e-21, 3.86263715686e-21,
+            3.99089781236e-21, 4.12041111239e-21, 4.25117371845e-21, 
4.38318271516e-21, 4.51643558895e-21,
+            4.65093020852e-21, 4.78666480711e-21, 4.92363796621e-21, 
5.06184860075e-21, 5.20129594544e-21,
+            5.34197954236e-21, 5.48389922948e-21, 5.62705513018e-21, 
5.77144764362e-21, 5.9170774359e-21,
+            6.06394543192e-21, 6.21205280795e-21, 6.36140098478e-21, 
6.51199162141e-21, 6.66382660935e-21,
+            6.81690806729e-21, 6.97123833635e-21, 7.12681997563e-21, 
7.28365575824e-21, 7.44174866764e-21,
+            7.60110189437e-21, 7.76171883308e-21, 7.92360307983e-21, 
8.08675842978e-21, 8.25118887504e-21,
+            8.41689860281e-21, 8.58389199384e-21, 8.752173621e-21, 
8.92174824817e-21, 9.0926208293e-21,
+            9.26479650768e-21, 9.43828061539e-21, 9.61307867302e-21, 
9.78919638943e-21, 9.96663966183e-21,
+            1.01454145759e-20, 1.03255274063e-20, 1.05069846171e-20, 
1.06897928622e-20, 1.08739589867e-20,
+            1.10594900275e-20, 1.12463932147e-20, 1.14346759725e-20, 
1.16243459211e-20, 1.18154108781e-20,
+            1.20078788602e-20, 1.22017580851e-20, 1.23970569735e-20, 
1.25937841516e-20, 1.27919484529e-20,
+            1.29915589212e-20, 1.31926248126e-20, 1.33951555991e-20, 
1.35991609708e-20, 1.38046508394e-20,
+            1.40116353411e-20, 1.42201248406e-20, 1.44301299338e-20, 
1.46416614524e-20, 1.48547304671e-20,
+            1.50693482921e-20, 1.5285526489e-20, 1.55032768718e-20, 
1.57226115107e-20, 1.59435427376e-20,
+            1.61660831506e-20, 1.63902456195e-20, 1.6616043291e-20, 
1.68434895946e-20, 1.70725982479e-20,
+            1.73033832633e-20, 1.75358589536e-20, 1.77700399393e-20, 
1.80059411545e-20, 1.82435778548e-20,
+            1.84829656238e-20, 1.87241203814e-20, 1.89670583912e-20, 
1.92117962687e-20, 1.94583509899e-20,
+            1.97067399002e-20, 1.99569807232e-20, 2.02090915706e-20, 
2.04630909515e-20, 2.07189977831e-20,
+            2.09768314011e-20, 2.12366115708e-20, 2.14983584983e-20, 
2.17620928428e-20, 2.20278357286e-20,
+            2.2295608758e-20, 2.2565434025e-20, 2.28373341287e-20, 
2.31113321878e-20, 2.33874518561e-20,
+            2.36657173374e-20, 2.39461534023e-20, 2.42287854051e-20, 
2.4513639301e-20, 2.48007416649e-20,
+            2.50901197103e-20, 2.53818013093e-20, 2.56758150136e-20, 
2.59721900756e-20, 2.62709564716e-20,
+            2.65721449254e-20, 2.68757869323e-20, 2.71819147857e-20, 
2.74905616033e-20, 2.78017613558e-20,
+            2.81155488957e-20, 2.84319599887e-20, 2.87510313451e-20, 
2.90728006545e-20, 2.939730662e-20,
+            2.97245889962e-20, 3.00546886272e-20, 3.03876474879e-20, 
3.07235087261e-20, 3.10623167078e-20,
+            3.14041170641e-20, 3.17489567409e-20, 3.20968840504e-20, 
3.24479487265e-20, 3.28022019823e-20,
+            3.31596965706e-20, 3.35204868483e-20, 3.38846288435e-20, 
3.42521803272e-20, 3.46232008885e-20,
+            3.4997752014e-20, 3.53758971719e-20, 3.57577019011e-20, 
3.61432339058e-20, 3.65325631548e-20,
+            3.69257619879e-20, 3.73229052281e-20, 3.77240703013e-20, 
3.81293373632e-20, 3.85387894342e-20,
+            3.89525125438e-20, 3.93705958834e-20, 3.97931319704e-20, 
4.02202168223e-20, 4.06519501444e-20,
+            4.10884355286e-20, 4.15297806682e-20, 4.19760975869e-20, 
4.24275028853e-20, 4.28841180055e-20,
+            4.3346069516e-20, 4.38134894182e-20, 4.42865154775e-20, 
4.47652915804e-20, 4.52499681207e-20,
+            4.57407024181e-20, 4.62376591717e-20, 4.67410109528e-20, 
4.72509387408e-20, 4.77676325071e-20,
+            4.82912918521e-20, 4.88221267023e-20, 4.93603580729e-20, 
4.99062189052e-20, 5.04599549866e-20,
+            5.10218259653e-20, 5.15921064692e-20, 5.21710873452e-20, 
5.2759077033e-20, 5.33564030933e-20,
+            5.39634139104e-20, 5.45804805963e-20, 5.52079991245e-20, 
5.58463927299e-20, 5.64961146142e-20,
+            5.71576510093e-20, 5.7831524655e-20, 5.85182987638e-20, 
5.92185815588e-20, 5.99330314883e-20,
+            6.06623632468e-20, 6.14073547584e-20, 6.21688553205e-20, 
6.29477951501e-20, 6.37451966432e-20,
+            6.45621877375e-20, 6.54000178819e-20, 6.62600772633e-20, 
6.71439201451e-20, 6.80532934473e-20,
+            6.89901720881e-20, 6.99568031586e-20, 7.09557617949e-20, 
7.19900227889e-20, 7.30630537391e-20,
+            7.41789382663e-20, 7.53425421342e-20, 7.65597421711e-20, 
7.78377498634e-20, 7.9185582674e-20,
+            8.06147755374e-20, 8.21405027698e-20, 8.37834459783e-20, 
8.55731292497e-20, 8.75544596696e-20,
+            8.98023880577e-20, 9.24624714212e-20, 9.5919641345e-20, 
1.08420217249e-19};
+
+        /** Underlying source of randomness. */
+        private final UniformRandomProvider rng;
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         */
+        ModifiedZigguratExponentialSampler(UniformRandomProvider rng) {
+            this.rng = rng;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double sample() {
+            final long x = rng.nextLong();
+            // Float multiplication squashes these last 8 bits, so they can be 
used to sample i
+            final int i = ((int) x) & 0xff;
+
+            if (i < I_MAX) {
+                // Early exit.
+                // This branch is called about 0.984374 times per call into 
createSample.
+                // Note: Frequencies have been empirically measured for the 
first call to
+                // createSample; recursion due to retries have been ignored. 
Frequencies sum to 1.
+                return X_I[i] * (x & MAX_INT64);
+            }
+            // For the first call into createSample:
+            // Recursion frequency = 0.000515560
+            // Overhang frequency  = 0.0151109
+            final int j = expSampleA();
+            return j == 0 ? X_0 + sample() : expOverhang(j);
+        }
+
+        /**
+         * Alias sampling.
+         * See http://scorevoting.net/WarrenSmithPages/homepage/sampling.abs
+         *
+         * @return the alias
+         */
+        private int expSampleA() {
+            final long x = rng.nextLong();
+            // j <- I(0, 256)
+            final int j = ((int) x) & 0xff;
+            return x >= IPMF[j] ? MAP[j] & 0xff : j;
+        }
+
+        /**
+         * Draws a PRN from overhang.
+         *
+         * @param j Index j (must be {@code > 0})
+         * @return the sample
+         */
+        private double expOverhang(int j) {
+            // To sample a unit right-triangle:
+            // U_x <- min(U_1, U_2)
+            // distance <- | U_1 - U_2 |
+            // U_y <- 1 - (U_x + distance)
+            long ux = randomInt63();
+            long uDistance = randomInt63() - ux;
+            if (uDistance < 0) {
+                uDistance = -uDistance;
+                ux -= uDistance;
+            }
+            // _FAST_PRNG_SAMPLE_X(xj, ux)
+            final double x = fastPrngSampleX(j, ux);
+            if (uDistance >= IE_MAX) {
+                // Frequency (per call into createSample): 0.0136732
+                // Frequency (per call into expOverhang):  0.904857
+                // Early Exit: x < y - epsilon
+                return x;
+            }
+            // Frequency per call into createSample:
+            // Return    = 0.00143769
+            // Recursion = 1e-8
+            // Frequency per call into expOverhang:
+            // Return    = 0.0951426
+            // Recursion = 6.61774e-07
+
+            // _FAST_PRNG_SAMPLE_Y(j, pow(2, 63) - (ux + uDistance))
+            // Long.MIN_VALUE is used as an unsigned int with value 2^63:
+            // uy = Long.MIN_VALUE - (ux + uDistance)
+            return fastPrngSampleY(j, Long.MIN_VALUE - (ux + uDistance)) <= 
Math.exp(-x) ? x : expOverhang(j);
+        }
+
+        /**
+         * Return a positive long in {@code [0, 2^63)}.
+         *
+         * @return the long
+         */
+        private long randomInt63() {
+            return rng.nextLong() & MAX_INT64;
+        }
+
+        /**
+         * Auxilary function to see if rejection sampling is required in the 
overhang.
+         * See Fig. 2 in the main text.
+         *
+         * @param j j
+         * @param ux ux
+         * @return the sample
+         */
+        private static double fastPrngSampleX(int j, long ux) {
+            return X_I[j] * TWO_POW_63 + (X_I[j - 1] - X_I[j]) * ux;
+        }
+
+        /**
+         * Auxilary function to see if rejection sampling is required in the 
overhang.
+         * See Fig. 2 in the main text.
+         *
+         * @param i i
+         * @param uy uy
+         * @return the sample
+         */
+        private static double fastPrngSampleY(int i, long uy) {
+            return Y[i - 1] * TWO_POW_63 + (Y[i] - Y[i - 1]) * uy;
+        }
+
+        /**
+         * Helper function to convert {@code int} values to bytes using a 
narrowing primitive conversion.
+         *
+         * @param values Integer values.
+         * @return the bytes
+         */
+        private static byte[] toBytes(int[] values) {
+            final byte[] bytes = new byte[values.length];
+            for (int i = 0; i < bytes.length; i++) {
+                bytes[i] = (byte) values[i];
+            }
+            return bytes;
+        }
+    }
+
+    /**
+     * Throw an illegal state exception for the unknown parameter.
+     *
+     * @param parameter Parameter name
+     */
+    private static void throwIllegalStateException(String parameter) {
+        throw new IllegalStateException("Unknown: " + parameter);
+    }
+
+    /**
+     * Baseline for the JMH timing overhead for production of an {@code 
double} value.
+     *
+     * @return the {@code double} value
+     */
+    @Benchmark
+    public double baseline() {
+        return value;
+    }
+
+    /**
+     * Benchmark methods for obtaining an index from the lower bits of a long.
+     *
+     * <p>Note: This is disabled as there is no measurable difference between 
methods.
+     *
+     * @param sources Source of randomness.
+     * @return the sample value
+     */
+    //@Benchmark
+    public int getIndex(IndexSources sources) {
+        return sources.getSampler().sample();
+    }
+
+    /**
+     * Benchmark methods for obtaining an unsigned long.
+     *
+     * <p>Note: This is disabled as there is no measurable difference between 
methods.
+     *
+     * @param sources Source of randomness.
+     * @return the sample value
+     */
+    //@Benchmark
+    public long getUnsignedLong(LongSources sources) {
+        return sources.getSampler().sample();
+    }
+
+    /**
+     * Run the sampler.
+     *
+     * @param sources Source of randomness.
+     * @return the sample value
+     */
+    @Benchmark
+    public double sample(Sources sources) {
+        return sources.getSampler().sample();
+    }
+}
diff --git 
a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/ZigguratSampler.java
 
b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/ZigguratSampler.java
new file mode 100644
index 0000000..9e8833f
--- /dev/null
+++ 
b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/distribution/ZigguratSampler.java
@@ -0,0 +1,865 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.rng.sampling.distribution;
+
+import org.apache.commons.rng.UniformRandomProvider;
+
+/**
+ * Modified ziggurat method for sampling from Gaussian and exponential 
distributions.
+ *
+ * <p>Uses the algorithm from:
+ *
+ * <blockquote>
+ * McFarland, C.D. (2016)<br>
+ * "A modified ziggurat algorithm for generating exponentially and normally 
distributed pseudorandom numbers".<br>
+ * <i>Journal of Statistical Computation and Simulation</i> <b>86</b>, 
1281-1294.
+ * </blockquote>
+ *
+ * <p>Note: The algorithm is a modification of the
+ * {@link ZigguratNormalizedGaussianSampler Marsaglia and Tsang "Ziggurat" 
method}.
+ * The modification improves performance of the rejection method used to 
generate
+ * samples at the edge of the ziggurat; this is the part of the area under the
+ * distribution PDF that cannot be represented using rectangles of the stepped 
ziggurat,
+ * e.g. area A:
+ *
+ * <pre>
+ *           \
+ * ----------+\
+ *           | \
+ *           |A \
+ * -------------+\
+ *              | \
+ * </pre>
+ *
+ * <p>Sampling uses {@link UniformRandomProvider#nextLong()}.
+ *
+ * @see <a 
href="https://www.tandfonline.com/doi/abs/10.1080/00949655.2015.1060234";>
+ * McFarland (2016) JSCS 86, 1281-1294</a>
+ * @since 1.4
+ */
+public abstract class ZigguratSampler implements SharedStateContinuousSampler {
+    /** Mask to extract the lowest 8-bits from an integer. */
+    private static final int MASK_INT8 = 0xff;
+    /** Mask to create an unsigned long from a signed long. This is the 
maximum value of a 64-bit long. */
+    private static final long MAX_INT64 = Long.MAX_VALUE;
+    /** 2^63. */
+    private static final double TWO_POW_63 = 0x1.0p63;
+
+    /** Underlying source of randomness. */
+    private final UniformRandomProvider rng;
+
+    // 
=========================================================================
+    // Implementation note:
+    //
+    // This has been adapted from the reference c implementation provided
+    // by C.D. McFarland:
+    //
+    // https://github.com/cd-mcfarland/fast_prng
+    //
+    // The adaption was faithful to the original as of July-2021.
+    // The code uses the naming conventions from the exponential.h and normal.h
+    // reference. Comments from the c source have been included.
+    // When the c reference was updated to use an underlying RNG
+    // available in Commons RNG the c and java code output the same random
+    // deviates over 2^30 cycles if identically seeded. Branch frequencies have
+    // been measured and added as comments.
+    // 
=========================================================================
+
+    /**
+     * Modified ziggurat method for sampling from an exponential distributions.
+     */
+    public static class Exponential extends ZigguratSampler {
+        /** Maximum i value for early exit. */
+        private static final int I_MAX = 252;
+        /** Maximum distance value for early exit. */
+        private static final long IE_MAX = 513303011048449572L;
+        /** Beginning of tail. */
+        private static final double X_0 = 7.56927469415;
+
+        /** The alias map. An integer in [0, 255] stored as a byte to save 
space. */
+        private static final byte[] MAP = toBytes(new int[] {0, 0, 1, 235, 3, 
4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+            1, 1, 1, 2, 2, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 
252, 252, 252, 252, 252, 252, 252, 252,
+            252, 252, 252, 252, 252, 252, 252, 252, 252, 251, 251, 251, 251, 
251, 251, 251, 251, 251, 251, 251, 251,
+            251, 250, 250, 250, 250, 250, 250, 250, 249, 249, 249, 249, 249, 
249, 248, 248, 248, 248, 247, 247, 247,
+            247, 246, 246, 246, 245, 245, 244, 244, 243, 243, 242, 241, 241, 
240, 239, 237, 3, 3, 4, 4, 6, 0, 0, 0, 0,
+            236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 
249, 250, 251, 252, 2, 0, 0, 0});
+        /** The alias inverse PMF. */
+        private static final long[] IPMF = {9223372036854775328L, 
1623796909450838420L, 2664290944894293715L,
+            7387971354164060121L, 6515064486552739054L, 8840508362680717952L, 
6099647593382935246L,
+            7673130333659513959L, 6220332867583438265L, 5045979640552813853L, 
4075305837223955667L,
+            3258413672162525563L, 2560664887087762661L, 1957224924672899759L, 
1429800935350577626L, 964606309710808357L,
+            551043923599587249L, 180827629096890397L, -152619738120023526L, 
-454588624410291449L, -729385126147774875L,
+            -980551509819446846L, -1211029700667463872L, 
-1423284293868547154L, -1619396356369050292L,
+            -1801135830956212822L, -1970018048575618008L, 
-2127348289059705241L, -2274257249303686299L,
+            -2411729520096655228L, -2540626634159182525L, 
-2661705860113406462L, -2775635634532448735L,
+            -2883008316030465121L, -2984350790383654722L, 
-3080133339198118434L, -3170777096303091107L,
+            -3256660348483804932L, -3338123885075152741L, 
-3415475560473282822L, -3488994201966444710L,
+            -3558932970354470759L, -3625522261068041096L, 
-3688972217741992040L, -3749474917563782729L,
+            -3807206277531056234L, -3862327722496827274L, 
-3914987649156779787L, -3965322714631865323L,
+            -4013458973776912076L, -4059512885612767084L, 
-4103592206186241133L, -4145796782586128173L,
+            -4186219260694363437L, -4224945717447258894L, 
-4262056226866285614L, -4297625367836519694L,
+            -4331722680528537423L, -4364413077437472623L, 
-4395757214229418223L, -4425811824915119504L,
+            -4454630025296932688L, -4482261588141311280L, 
-4508753193105271888L, -4534148654077804689L,
+            -4558489126279970065L, -4581813295192216657L, 
-4604157549138257681L, -4625556137145250418L,
+            -4646041313519109426L, -4665643470413305970L, 
-4684391259530326642L, -4702311703971761747L,
+            -4719430301145086931L, -4735771117539946355L, 
-4751356876102103699L, -4766209036859128403L,
+            -4780347871386013331L, -4793792531638892019L, 
-4806561113635122292L, -4818670716409312756L,
+            -4830137496634465780L, -4840976719260854452L, 
-4851202804490332660L, -4860829371376460084L,
+            -4869869278311657652L, -4878334660640771092L, 
-4886236965617427412L, -4893586984900802772L,
+            -4900394884772702964L, -4906670234238885493L, 
-4912422031164489589L, -4917658726580136309L,
+            -4922388247283532373L, -4926618016851059029L, 
-4930354975163335189L, -4933605596540651285L,
+            -4936375906575303797L, -4938671497741365845L, 
-4940497543854575637L, -4941858813449629493L,
+            -4942759682136114997L, -4943204143989086773L, 
-4943195822025527893L, -4942737977813206357L,
+            -4941833520255033237L, -4940485013586738773L, 
-4938694684624359381L, -4936464429291795925L,
+            -4933795818458825557L, -4930690103114057941L, 
-4927148218896868949L, -4923170790008275925L,
+            -4918758132519202261L, -4913910257091645845L, 
-4908626871126550421L, -4902907380349522964L,
+            -4896750889844289364L, -4890156204540514772L, 
-4883121829162554452L, -4875645967641803284L,
+            -4867726521994894420L, -4859361090668136340L, 
-4850546966345097428L, -4841281133215539220L,
+            -4831560263698486164L, -4821380714613453652L, 
-4810738522790066260L, -4799629400105482131L,
+            -4788048727936313747L, -4775991551010508883L, 
-4763452570642098131L, -4750426137329511059L,
+            -4736906242696389331L, -4722886510751361491L, 
-4708360188440098835L, -4693320135461437394L,
+            -4677758813316075410L, -4661668273553512594L, 
-4645040145179234642L, -4627865621182772242L,
+            -4610135444140937425L, -4591839890849345681L, 
-4572968755929937937L, -4553511334358205905L,
+            -4533456402849118097L, -4512792200036279121L, 
-4491506405372581072L, -4469586116675402576L,
+            -4447017826233108176L, -4423787395382268560L, 
-4399880027458432847L, -4375280239014115151L,
+            -4349971829190464271L, -4323937847117722127L, 
-4297160557210950158L, -4269621402214950094L,
+            -4241300963840749518L, -4212178920821845518L, 
-4182234004204468173L, -4151443949668868493L,
+            -4119785446662289613L, -4087234084103201932L, 
-4053764292396157324L, -4019349281473091724L,
+            -3983960974549676683L, -3947569937258407435L, 
-3910145301787369227L, -3871654685619016074L,
+            -3832064104425399050L, -3791337878631545353L, 
-3749438533114317833L, -3706326689447995081L,
+            -3661960950051848712L, -3616297773528535240L, 
-3569291340409179143L, -3520893408440946503L,
+            -3471053156460654726L, -3419717015797782918L, 
-3366828488034800645L, -3312327947826472069L,
+            -3256152429334011012L, -3198235394669703364L, 
-3138506482563184963L, -3076891235255163586L,
+            -3013310801389731586L, -2947681612411375617L, 
-2879915029671665601L, -2809916959107518656L,
+            -2737587429961872959L, -2662820133571326270L, 
-2585501917733374398L, -2505512231579382333L,
+            -2422722515205206076L, -2336995527534112187L, 
-2248184604988688954L, -2156132842510798521L,
+            -2060672187261006776L, -1961622433929382455L, 
-1858790108950092598L, -1751967229002903349L,
+            -1640929916937143604L, -1525436855617592627L, 
-1405227557075244850L, -1280020420662660017L,
+            -1149510549536587824L, -1013367289578705710L, 
-871231448632088621L, -722712146453685035L,
+            -567383236774420522L, -404779231966955560L, -234390647591522471L, 
-55658667960120229L, 132030985907824093L,
+            329355128892810847L, 537061298001092449L, 755977262693571427L, 
987022116608031845L, 1231219266829421544L,
+            1489711711346525930L, 1763780090187560429L, 2054864117341776240L, 
2364588157623792755L,
+            2694791916990483702L, 3047567482883492729L, 3425304305830814717L, 
3830744187097279873L,
+            4267048975685831301L, 4737884547990035082L, 5247525842198997007L, 
5800989391535354004L,
+            6404202162993293978L, 7064218894258529185L, 7789505049452340392L, 
8590309807749443504L,
+            7643763810684498323L, 8891950541491447639L, 5457384281016226081L, 
9083704440929275131L,
+            7976211653914439517L, 8178631350487107662L, 2821287825726743868L, 
6322989683301723979L,
+            4309503753387603546L, 4685170734960182655L, 8404845967535219911L, 
7330522972447586582L,
+            1960945799077017972L, 4742910674644930459L, -751799822533465632L, 
7023456603741994979L,
+            3843116882594690323L, 3927231442413903597L, -9223372036854775807L, 
-9223372036854775807L,
+            -9223372036854775807L};
+        /** The precomputed ziggurat lengths, denoted X_i in the main text. 
X_i = length of ziggurat layer i. */
+        private static final double[] X = {8.20662406753e-19, 
7.39737323516e-19, 6.91333133779e-19, 6.5647358821e-19,
+            6.29125399598e-19, 6.06572241296e-19, 5.87352761037e-19, 
5.70588505285e-19, 5.55709456916e-19,
+            5.42324389037e-19, 5.30152976965e-19, 5.18987392577e-19, 
5.0866922618e-19, 4.99074929388e-19,
+            4.90106258944e-19, 4.81683790106e-19, 4.73742386536e-19, 
4.66227958072e-19, 4.59095090178e-19,
+            4.52305277907e-19, 4.45825588164e-19, 4.39627631264e-19, 
4.33686759671e-19, 4.27981436185e-19,
+            4.22492730271e-19, 4.17203912535e-19, 4.12100125225e-19, 
4.07168112259e-19, 4.0239599631e-19,
+            3.97773093429e-19, 3.93289757853e-19, 3.88937251293e-19, 
3.84707632187e-19, 3.80593661382e-19,
+            3.76588721385e-19, 3.7268674692e-19, 3.68882164922e-19, 
3.65169842488e-19, 3.61545041533e-19,
+            3.58003379153e-19, 3.54540792845e-19, 3.51153509888e-19, 
3.478380203e-19, 3.44591052889e-19,
+            3.41409553966e-19, 3.38290668387e-19, 3.35231722623e-19, 
3.32230209587e-19, 3.29283775028e-19,
+            3.26390205282e-19, 3.23547416228e-19, 3.20753443311e-19, 
3.18006432505e-19, 3.15304632118e-19,
+            3.12646385343e-19, 3.10030123469e-19, 3.07454359701e-19, 
3.049176835e-19, 3.02418755411e-19,
+            2.99956302321e-19, 2.97529113107e-19, 2.95136034631e-19, 
2.92775968057e-19, 2.90447865454e-19,
+            2.88150726664e-19, 2.85883596399e-19, 2.83645561563e-19, 
2.81435748768e-19, 2.79253322026e-19,
+            2.77097480612e-19, 2.74967457073e-19, 2.72862515379e-19, 
2.70781949192e-19, 2.68725080264e-19,
+            2.66691256932e-19, 2.64679852713e-19, 2.62690264997e-19, 
2.60721913814e-19, 2.58774240685e-19,
+            2.56846707542e-19, 2.54938795718e-19, 2.53050004991e-19, 
2.51179852691e-19, 2.49327872862e-19,
+            2.47493615466e-19, 2.45676645638e-19, 2.43876542983e-19, 
2.42092900908e-19, 2.40325326001e-19,
+            2.38573437435e-19, 2.36836866406e-19, 2.35115255607e-19, 
2.33408258722e-19, 2.31715539953e-19,
+            2.3003677357e-19, 2.28371643478e-19, 2.2671984282e-19, 
2.2508107358e-19, 2.23455046227e-19,
+            2.21841479361e-19, 2.20240099382e-19, 2.18650640175e-19, 
2.17072842808e-19, 2.15506455249e-19,
+            2.13951232087e-19, 2.12406934276e-19, 2.10873328882e-19, 
2.09350188851e-19, 2.07837292773e-19,
+            2.06334424671e-19, 2.04841373792e-19, 2.03357934403e-19, 
2.01883905608e-19, 2.00419091156e-19,
+            1.98963299272e-19, 1.97516342486e-19, 1.96078037473e-19, 
1.94648204892e-19, 1.93226669243e-19,
+            1.9181325872e-19, 1.90407805074e-19, 1.89010143478e-19, 
1.87620112397e-19, 1.86237553469e-19,
+            1.8486231138e-19, 1.83494233754e-19, 1.82133171034e-19, 
1.80778976379e-19, 1.79431505561e-19,
+            1.78090616856e-19, 1.76756170954e-19, 1.75428030858e-19, 
1.74106061794e-19, 1.7279013112e-19,
+            1.71480108238e-19, 1.7017586451e-19, 1.68877273172e-19, 
1.67584209255e-19, 1.66296549505e-19,
+            1.65014172306e-19, 1.63736957602e-19, 1.62464786823e-19, 
1.61197542813e-19, 1.59935109756e-19,
+            1.58677373107e-19, 1.57424219521e-19, 1.56175536784e-19, 
1.54931213746e-19, 1.5369114025e-19,
+            1.52455207068e-19, 1.51223305837e-19, 1.49995328986e-19, 
1.48771169674e-19, 1.47550721726e-19,
+            1.46333879563e-19, 1.4512053814e-19, 1.43910592874e-19, 
1.42703939586e-19, 1.41500474425e-19,
+            1.40300093807e-19, 1.39102694344e-19, 1.37908172772e-19, 
1.36716425886e-19, 1.35527350466e-19,
+            1.34340843201e-19, 1.3315680062e-19, 1.31975119012e-19, 
1.3079569435e-19, 1.29618422208e-19,
+            1.28443197683e-19, 1.27269915307e-19, 1.26098468959e-19, 
1.24928751776e-19, 1.23760656057e-19,
+            1.22594073168e-19, 1.21428893439e-19, 1.20265006056e-19, 
1.19102298955e-19, 1.17940658704e-19,
+            1.16779970383e-19, 1.15620117456e-19, 1.14460981638e-19, 
1.13302442758e-19, 1.12144378607e-19,
+            1.10986664787e-19, 1.0982917454e-19, 1.08671778581e-19, 
1.07514344905e-19, 1.06356738599e-19,
+            1.05198821625e-19, 1.04040452605e-19, 1.02881486575e-19, 
1.01721774741e-19, 1.00561164199e-19,
+            9.93994976483e-20, 9.82366130767e-20, 9.70723434263e-20, 
9.59065162307e-20, 9.47389532242e-20,
+            9.35694699202e-20, 9.23978751546e-20, 9.12239705906e-20, 
9.00475501809e-20, 8.88683995826e-20,
+            8.76862955198e-20, 8.65010050861e-20, 8.53122849831e-20, 
8.41198806844e-20, 8.29235255165e-20,
+            8.1722939648e-20, 8.05178289728e-20, 7.93078838751e-20, 
7.80927778595e-20, 7.68721660284e-20,
+            7.5645683384e-20, 7.44129429302e-20, 7.31735335451e-20, 
7.19270175876e-20, 7.06729281977e-20,
+            6.94107662395e-20, 6.81399968293e-20, 6.68600453746e-20, 
6.55702930402e-20, 6.42700715334e-20,
+            6.29586570809e-20, 6.16352634381e-20, 6.02990337322e-20, 
5.89490308929e-20, 5.75842263599e-20,
+            5.62034866696e-20, 5.48055574135e-20, 5.3389043909e-20, 
5.1952387718e-20, 5.04938378663e-20,
+            4.90114152226e-20, 4.75028679334e-20, 4.59656150013e-20, 
4.4396673898e-20, 4.27925663021e-20,
+            4.11491932734e-20, 3.94616667626e-20, 3.77240771314e-20, 
3.59291640862e-20, 3.40678366911e-20,
+            3.21284476416e-20, 3.00956469164e-20, 2.79484694556e-20, 
2.56569130487e-20, 2.31752097568e-20,
+            2.04266952283e-20, 1.72617703302e-20, 1.32818892594e-20, 0.0};
+        /** Overhang table. Y_i = f(X_i). */
+        private static final double[] Y = {5.59520549511e-23, 
1.18025099827e-22, 1.84444233867e-22, 2.54390304667e-22,
+            3.27376943115e-22, 4.03077321327e-22, 4.81254783195e-22, 
5.61729148966e-22, 6.44358205404e-22,
+            7.29026623435e-22, 8.15638884563e-22, 9.04114536835e-22, 
9.94384884864e-22, 1.0863906046e-21,
+            1.18007997755e-21, 1.27540755348e-21, 1.37233311764e-21, 
1.47082087944e-21, 1.57083882574e-21,
+            1.67235819844e-21, 1.7753530675e-21, 1.87979997851e-21, 
1.98567765878e-21, 2.09296677041e-21,
+            2.201649701e-21, 2.31171038523e-21, 2.42313415161e-21, 
2.53590759014e-21, 2.65001843742e-21,
+            2.76545547637e-21, 2.88220844835e-21, 3.00026797575e-21, 
3.11962549361e-21, 3.24027318888e-21,
+            3.36220394642e-21, 3.48541130074e-21, 3.60988939279e-21, 
3.7356329311e-21, 3.86263715686e-21,
+            3.99089781236e-21, 4.12041111239e-21, 4.25117371845e-21, 
4.38318271516e-21, 4.51643558895e-21,
+            4.65093020852e-21, 4.78666480711e-21, 4.92363796621e-21, 
5.06184860075e-21, 5.20129594544e-21,
+            5.34197954236e-21, 5.48389922948e-21, 5.62705513018e-21, 
5.77144764362e-21, 5.9170774359e-21,
+            6.06394543192e-21, 6.21205280795e-21, 6.36140098478e-21, 
6.51199162141e-21, 6.66382660935e-21,
+            6.81690806729e-21, 6.97123833635e-21, 7.12681997563e-21, 
7.28365575824e-21, 7.44174866764e-21,
+            7.60110189437e-21, 7.76171883308e-21, 7.92360307983e-21, 
8.08675842978e-21, 8.25118887504e-21,
+            8.41689860281e-21, 8.58389199384e-21, 8.752173621e-21, 
8.92174824817e-21, 9.0926208293e-21,
+            9.26479650768e-21, 9.43828061539e-21, 9.61307867302e-21, 
9.78919638943e-21, 9.96663966183e-21,
+            1.01454145759e-20, 1.03255274063e-20, 1.05069846171e-20, 
1.06897928622e-20, 1.08739589867e-20,
+            1.10594900275e-20, 1.12463932147e-20, 1.14346759725e-20, 
1.16243459211e-20, 1.18154108781e-20,
+            1.20078788602e-20, 1.22017580851e-20, 1.23970569735e-20, 
1.25937841516e-20, 1.27919484529e-20,
+            1.29915589212e-20, 1.31926248126e-20, 1.33951555991e-20, 
1.35991609708e-20, 1.38046508394e-20,
+            1.40116353411e-20, 1.42201248406e-20, 1.44301299338e-20, 
1.46416614524e-20, 1.48547304671e-20,
+            1.50693482921e-20, 1.5285526489e-20, 1.55032768718e-20, 
1.57226115107e-20, 1.59435427376e-20,
+            1.61660831506e-20, 1.63902456195e-20, 1.6616043291e-20, 
1.68434895946e-20, 1.70725982479e-20,
+            1.73033832633e-20, 1.75358589536e-20, 1.77700399393e-20, 
1.80059411545e-20, 1.82435778548e-20,
+            1.84829656238e-20, 1.87241203814e-20, 1.89670583912e-20, 
1.92117962687e-20, 1.94583509899e-20,
+            1.97067399002e-20, 1.99569807232e-20, 2.02090915706e-20, 
2.04630909515e-20, 2.07189977831e-20,
+            2.09768314011e-20, 2.12366115708e-20, 2.14983584983e-20, 
2.17620928428e-20, 2.20278357286e-20,
+            2.2295608758e-20, 2.2565434025e-20, 2.28373341287e-20, 
2.31113321878e-20, 2.33874518561e-20,
+            2.36657173374e-20, 2.39461534023e-20, 2.42287854051e-20, 
2.4513639301e-20, 2.48007416649e-20,
+            2.50901197103e-20, 2.53818013093e-20, 2.56758150136e-20, 
2.59721900756e-20, 2.62709564716e-20,
+            2.65721449254e-20, 2.68757869323e-20, 2.71819147857e-20, 
2.74905616033e-20, 2.78017613558e-20,
+            2.81155488957e-20, 2.84319599887e-20, 2.87510313451e-20, 
2.90728006545e-20, 2.939730662e-20,
+            2.97245889962e-20, 3.00546886272e-20, 3.03876474879e-20, 
3.07235087261e-20, 3.10623167078e-20,
+            3.14041170641e-20, 3.17489567409e-20, 3.20968840504e-20, 
3.24479487265e-20, 3.28022019823e-20,
+            3.31596965706e-20, 3.35204868483e-20, 3.38846288435e-20, 
3.42521803272e-20, 3.46232008885e-20,
+            3.4997752014e-20, 3.53758971719e-20, 3.57577019011e-20, 
3.61432339058e-20, 3.65325631548e-20,
+            3.69257619879e-20, 3.73229052281e-20, 3.77240703013e-20, 
3.81293373632e-20, 3.85387894342e-20,
+            3.89525125438e-20, 3.93705958834e-20, 3.97931319704e-20, 
4.02202168223e-20, 4.06519501444e-20,
+            4.10884355286e-20, 4.15297806682e-20, 4.19760975869e-20, 
4.24275028853e-20, 4.28841180055e-20,
+            4.3346069516e-20, 4.38134894182e-20, 4.42865154775e-20, 
4.47652915804e-20, 4.52499681207e-20,
+            4.57407024181e-20, 4.62376591717e-20, 4.67410109528e-20, 
4.72509387408e-20, 4.77676325071e-20,
+            4.82912918521e-20, 4.88221267023e-20, 4.93603580729e-20, 
4.99062189052e-20, 5.04599549866e-20,
+            5.10218259653e-20, 5.15921064692e-20, 5.21710873452e-20, 
5.2759077033e-20, 5.33564030933e-20,
+            5.39634139104e-20, 5.45804805963e-20, 5.52079991245e-20, 
5.58463927299e-20, 5.64961146142e-20,
+            5.71576510093e-20, 5.7831524655e-20, 5.85182987638e-20, 
5.92185815588e-20, 5.99330314883e-20,
+            6.06623632468e-20, 6.14073547584e-20, 6.21688553205e-20, 
6.29477951501e-20, 6.37451966432e-20,
+            6.45621877375e-20, 6.54000178819e-20, 6.62600772633e-20, 
6.71439201451e-20, 6.80532934473e-20,
+            6.89901720881e-20, 6.99568031586e-20, 7.09557617949e-20, 
7.19900227889e-20, 7.30630537391e-20,
+            7.41789382663e-20, 7.53425421342e-20, 7.65597421711e-20, 
7.78377498634e-20, 7.9185582674e-20,
+            8.06147755374e-20, 8.21405027698e-20, 8.37834459783e-20, 
8.55731292497e-20, 8.75544596696e-20,
+            8.98023880577e-20, 9.24624714212e-20, 9.5919641345e-20, 
1.08420217249e-19};
+
+        /**
+         * Specialisation which multiplies the standard exponential result by 
a specified mean.
+         */
+        private static class ExponentialMean extends Exponential {
+            /** Mean. */
+            private final double mean;
+
+            /**
+             * @param rng Generator of uniformly distributed random numbers.
+             * @param mean Mean.
+             */
+            ExponentialMean(UniformRandomProvider rng, double mean) {
+                super(rng);
+                this.mean = mean;
+            }
+
+            @Override
+            public double sample() {
+                return createSample() * mean;
+            }
+
+            @Override
+            public ExponentialMean 
withUniformRandomProvider(UniformRandomProvider rng) {
+                return new ExponentialMean(rng, this.mean);
+            }
+        }
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         */
+        private Exponential(UniformRandomProvider rng) {
+            super(rng);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public String toString() {
+            return toString("exponential");
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double sample() {
+            return createSample();
+        }
+
+        /**
+         * Creates the exponential sample with {@code mean = 1}.
+         *
+         * <p>Note: This has been extracted to a separate method so that the 
recursive call
+         * when sampling tries again targets this function. Otherwise the 
sub-class
+         * {@code ExponentialMean.sample()} method will recursively call
+         * the overloaded sample() method when trying again which creates a 
bad sample due
+         * to compound multiplication of the mean.
+         *
+         * @return the sample
+         */
+        final double createSample() {
+            final long x = nextLong();
+            // Float multiplication squashes these last 8 bits, so they can be 
used to sample i
+            final int i = ((int) x) & MASK_INT8;
+
+            if (i < I_MAX) {
+                // Early exit.
+                // This branch is called about 0.984374 times per call into 
createSample.
+                // Note: Frequencies have been empirically measured for the 
first call to
+                // createSample; recursion due to retries have been ignored. 
Frequencies sum to 1.
+                return X[i] * (x & MAX_INT64);
+            }
+            // For the first call into createSample:
+            // Recursion frequency = 0.000515560
+            // Overhang frequency  = 0.0151109
+            final int j = expSampleA();
+            return j == 0 ? X_0 + createSample() : expOverhang(j);
+        }
+
+        /**
+         * Alias sampling.
+         * See http://scorevoting.net/WarrenSmithPages/homepage/sampling.abs
+         *
+         * @return the alias
+         */
+        private int expSampleA() {
+            final long x = nextLong();
+            // j <- I(0, 256)
+            final int j = ((int) x) & MASK_INT8;
+            return x >= IPMF[j] ? MAP[j] & MASK_INT8 : j;
+        }
+
+        /**
+         * Draws a PRN from overhang.
+         *
+         * @param j Index j (must be {@code > 0})
+         * @return the sample
+         */
+        private double expOverhang(int j) {
+            // To sample a unit right-triangle:
+            // U_x <- min(U_1, U_2)
+            // distance <- | U_1 - U_2 |
+            // U_y <- 1 - (U_x + distance)
+            long ux = randomInt63();
+            long uDistance = randomInt63() - ux;
+            if (uDistance < 0) {
+                uDistance = -uDistance;
+                ux -= uDistance;
+            }
+            // _FAST_PRNG_SAMPLE_X(xj, ux)
+            final double x = fastPrngSampleX(X, j, ux);
+            if (uDistance >= IE_MAX) {
+                // Frequency (per call into createSample): 0.0136732
+                // Frequency (per call into expOverhang):  0.904857
+                // Early Exit: x < y - epsilon
+                return x;
+            }
+            // Frequency per call into createSample:
+            // Return    = 0.00143769
+            // Recursion = 1e-8
+            // Frequency per call into expOverhang:
+            // Return    = 0.0951426
+            // Recursion = 6.61774e-07
+
+            // _FAST_PRNG_SAMPLE_Y(j, pow(2, 63) - (ux + uDistance))
+            // Long.MIN_VALUE is used as an unsigned int with value 2^63:
+            // uy = Long.MIN_VALUE - (ux + uDistance)
+            return fastPrngSampleY(Y, j, Long.MIN_VALUE - (ux + uDistance)) <= 
Math.exp(-x) ?
+                x : expOverhang(j);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public Exponential withUniformRandomProvider(UniformRandomProvider 
rng) {
+            return new Exponential(rng);
+        }
+
+        /**
+         * Create a new exponential sampler with {@code mean = 1}.
+         *
+         * @param rng Generator of uniformly distributed random numbers.
+         * @return the sampler
+         */
+        public static Exponential of(UniformRandomProvider rng) {
+            return new Exponential(rng);
+        }
+
+        /**
+         * Create a new exponential sampler with the specified {@code mean}.
+         *
+         * @param rng Generator of uniformly distributed random numbers.
+         * @param mean Mean.
+         * @return the sampler
+         * @throws IllegalArgumentException if the mean is not strictly 
positive ({@code mean <= 0})
+         */
+        public static Exponential of(UniformRandomProvider rng, double mean) {
+            if (mean > 0) {
+                return new ExponentialMean(rng, mean);
+            }
+            throw new IllegalArgumentException("Mean is not strictly positive: 
" + mean);
+        }
+    }
+
+    /**
+     * Modified ziggurat method for sampling from a Gaussian distribution with
+     * mean 0 and standard deviation 1.
+     *
+     * <p>Note: The algorithm is a modification of the
+     * {@link ZigguratNormalizedGaussianSampler Marsaglia and Tsang "Ziggurat" 
method}.
+     * The modification improves performance of the rejection method used to 
generate
+     * samples at the edge of the ziggurat.
+     *
+     * @see NormalizedGaussianSampler
+     * @see GaussianSampler
+     */
+    public static final class NormalizedGaussian extends ZigguratSampler
+        implements NormalizedGaussianSampler, SharedStateContinuousSampler {
+        /** Maximum i value for early exit. */
+        private static final int I_MAX = 253;
+        /** The point where the Gaussian switches from convex to concave. */
+        private static final int J_INFLECTION = 205;
+        /** Used for largest deviations of f(x) from y_i. This is negated on 
purpose. */
+        private static final long MAX_IE = -2269182951627975918L;
+        /** Used for largest deviations of f(x) from y_i. */
+        private static final long MIN_IE = 760463704284035181L;
+        /** Beginning of tail. */
+        private static final double X_0 = 3.6360066255;
+        /** 1/X_0. */
+        private static final double ONE_OVER_X_0 = 1d / X_0;
+
+        /** The alias map. An integer in [0, 255] stored as a byte to save 
space. */
+        private static final byte[] MAP = toBytes(
+            new int[] {0, 0, 239, 2, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 
253, 253, 253, 253, 253, 253, 253, 253, 253,
+                253, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 251, 
251, 251, 251, 251, 251, 251, 250, 250, 250,
+                250, 250, 249, 249, 249, 248, 248, 248, 247, 247, 247, 246, 
246, 245, 244, 244, 243, 242, 240, 2, 2, 3,
+                3, 0, 0, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 
250, 251, 252, 253, 1, 0, 0});
+        /** The alias inverse PMF. */
+        private static final long[] IPMF = {9223372036854775807L, 
1100243796532604147L, 7866600928978262881L,
+            6788754710654027089L, 9022865200181691852L, 6522434035205505475L, 
4723064097359993915L,
+            3360495653216419673L, 2289663232373874393L, 1423968905551925104L, 
708364817827802907L, 106102487305606492L,
+            -408333464665790208L, -853239722779020926L, -1242095211825517037L, 
-1585059631105792592L,
+            -1889943050287164616L, -2162852901990665326L, 
-2408637386594506662L, -2631196530262949902L,
+            -2833704942520918738L, -3018774289025815052L, 
-3188573753472182441L, -3344920681707440829L,
+            -3489349705062145773L, -3623166100042174483L, 
-3747487436868330185L, -3863276422712168700L,
+            -3971367044063122321L, -4072485557029853479L, 
-4167267476830907467L, -4256271432240150335L,
+            -4339990541927301065L, -4418861817133796561L, 
-4493273980372371289L, -4563574004462236379L,
+            -4630072609770443287L, -4693048910430993529L, 
-4752754358862853623L, -4809416110052798111L,
+            -4863239903586974371L, -4914412541515869230L, 
-4963104028439154501L, -5009469424769141876L,
+            -5053650458856546947L, -5095776932695070785L, 
-5135967952544950843L, -5174333008451188631L,
+            -5210972924952682065L, -5245980700100453012L, 
-5279442247516290042L, -5311437055462362013L,
+            -5342038772315636138L, -5371315728843324427L, 
-5399331404632497705L, -5426144845493682879L,
+            -5451811038474681565L, -5476381248265612057L, 
-5499903320558330825L, -5522421955752302985L,
+            -5543978956085246988L, -5564613449659052023L, 
-5584362093436129148L, -5603259257517445975L,
+            -5621337193070977432L, -5638626184974114133L, 
-5655154691220924683L, -5670949470294749069L,
+            -5686035697601828417L, -5700437072199142976L, 
-5714175914219797723L, -5727273255295211389L,
+            -5739748920272022600L, -5751621603810396917L, 
-5762908939773930926L, -5773627565914992314L,
+            -5783793183152402325L, -5793420610475612574L, 
-5802523835894645221L, -5811116062947594592L,
+            -5819209754516104281L, -5826816672854561136L, 
-5833947916825296227L, -5840613956570562553L,
+            -5846824665591787384L, -5852589350491064419L, 
-5857916778480708968L, -5862815203334817577L,
+            -5867292388935689664L, -5871355631762300668L, 
-5875011781262872391L, -5878267259039068099L,
+            -5881128076579864607L, -5883599852028866964L, 
-5885687825288587920L, -5887396872144944193L,
+            -5888731517955022366L, -5889695949247708370L, 
-5890294025706661862L, -5890529289910843690L,
+            -5890404977676009159L, -5889924026487152552L, 
-5889089083913561497L, -5887902514965187544L,
+            -5886366408898350160L, -5884482585690660648L, 
-5882252601321067956L, -5879677752995005083L,
+            -5876759083794187244L, -5873497386318817608L, 
-5869893206505495615L, -5865946846617000703L,
+            -5861658367354170141L, -5857027590486142268L, 
-5852054100063403979L, -5846737243971479915L,
+            -5841076134082348607L, -5835069647234555080L, 
-5828716424754558627L, -5822014871949050545L,
+            -5814963157357505615L, -5807559211080035948L, 
-5799800723447248431L, -5791685142338046612L,
+            -5783209670985131963L, -5774371264582507258L, 
-5765166627072198898L, -5755592207057629351L,
+            -5745644193442020886L, -5735318510777140130L, 
-5724610813433637581L, -5713516480385064197L,
+            -5702030608511931905L, -5690148005851000163L, 
-5677863184109376595L, -5665170350903283020L,
+            -5652063400924584736L, -5638535907000098559L, 
-5624581109999495711L, -5610191908627545348L,
+            -5595360848093635657L, -5580080108034221525L, 
-5564341489875517452L, -5548136403221361788L,
+            -5531455851545388194L, -5514290416638313566L, 
-5496630242181647032L, -5478465016761708394L,
+            -5459783954986630496L, -5440575777891763554L, 
-5420828692432362328L, -5400530368638759086L,
+            -5379667916699386572L, -5358227861294079939L, 
-5336196115274289941L, -5313557951078348351L,
+            -5290297970633413513L, -5266400072915204637L, 
-5241847420213976978L, -5216622401043707762L,
+            -5190706591719514516L, -5164080714589163015L, 
-5136724594099061292L, -5108617109269271995L,
+            -5079736143458208314L, -5050058530461699570L, 
-5019559997031867155L, -4988215101008300666L,
+            -4955997165600740840L, -4922878208651982466L, 
-4888828866780310778L, -4853818314258448763L,
+            -4817814175855136221L, -4780782432601640934L, 
-4742687321746673837L, -4703491227581398702L,
+            -4663154564978669839L, -4621635653358718847L, 
-4578890580370737438L, -4534873055659651863L,
+            -4489534251700544707L, -4442822631898778778L, 
-4394683764809052552L, -4345060121983309848L,
+            -4293890858708851568L, -4241111576153757717L, 
-4186654061692562932L, -4130446006804691432L,
+            -4072410698657642967L, -4012466683838341666L, 
-3950527400304957273L, -3886500774061817392L,
+            -3820288777467775968L, -3751786943594814089L, 
-3680883832433444937L, -3607460442623855428L,
+            -3531389562483238811L, -3452535052936037985L, 
-3370751053395794721L, -3285881101589156030L,
+            -3197757155301271700L, -3106198503156390075L, 
-3011010550911843739L, -2911983463883482375L,
+            -2808890647470171482L, -2701487041141041038L, 
-2589507199690499622L, -2472663129329060997L,
+            -2350641842139723534L, -2223102583769914387L, 
-2089673683729348624L, -1949948966045216354L,
+            -1803483646855866339L, -1649789631524907106L, 
-1488330106094837958L, -1318513295725471712L,
+            -1139685236971903433L, -951121376551959675L, -752016768184573709L, 
-541474585687415681L,
+            -318492605680814263L, -81947227248966622L, 169425512568350963L, 
437052607277165029L, 722551297569085274L,
+            1027761939300002045L, 1354787941578333500L, 1706044619204253453L, 
2084319374409947591L,
+            2492846399638817506L, 2935400169348911565L, 3416413484613541924L, 
3941127949861028145L,
+            4515787798749165735L, 5147892401484995974L, 5846529325380992513L, 
6622819682194933019L,
+            7490522659874903812L, 8466869998278641829L, 8216968526368126501L, 
4550693915471153825L,
+            7628019504122306461L, 6605080500893076940L, 7121156327637209657L, 
2484871780365768829L,
+            7179104797069433749L, 7066086283825115773L, 1516500120794063563L, 
216305945442773460L, 6295963418513296140L,
+            2889316805672339623L, -2712587580543026574L, 6562498853519217374L, 
7975754821145999232L,
+            -9223372036854775807L, -9223372036854775807L};
+        /** The precomputed ziggurat lengths, denoted X_i in the main text. 
X_i = length of ziggurat layer i. */
+        private static final double[] X = {3.94216628254e-19, 
3.72049450041e-19, 3.58270244806e-19, 3.48074762365e-19,
+            3.39901771719e-19, 3.33037783603e-19, 3.27094388176e-19, 
3.21835771325e-19, 3.17107585418e-19,
+            3.1280307407e-19, 3.08845206558e-19, 3.05176506241e-19, 
3.01752902926e-19, 2.98539834407e-19,
+            2.95509674628e-19, 2.92639979885e-19, 2.899122587e-19, 
2.87311087802e-19, 2.84823463271e-19,
+            2.82438315352e-19, 2.80146139647e-19, 2.77938712618e-19, 
2.75808869214e-19, 2.73750326983e-19,
+            2.71757545434e-19, 2.69825612475e-19, 2.67950151888e-19, 
2.66127247304e-19, 2.6435337928e-19,
+            2.6262537282e-19, 2.60940353352e-19, 2.59295709543e-19, 
2.57689061732e-19, 2.56118234977e-19,
+            2.54581235934e-19, 2.53076232924e-19, 2.51601538678e-19, 
2.50155595336e-19, 2.48736961354e-19,
+            2.47344300031e-19, 2.45976369429e-19, 2.44632013479e-19, 
2.43310154111e-19, 2.42009784271e-19,
+            2.40729961704e-19, 2.39469803409e-19, 2.38228480673e-19, 
2.37005214619e-19, 2.35799272207e-19,
+            2.34609962621e-19, 2.33436634011e-19, 2.32278670547e-19, 
2.31135489743e-19, 2.30006540027e-19,
+            2.28891298528e-19, 2.27789269059e-19, 2.26699980275e-19, 
2.25622983985e-19, 2.24557853607e-19,
+            2.23504182749e-19, 2.22461583905e-19, 2.21429687253e-19, 
2.20408139549e-19, 2.19396603103e-19,
+            2.18394754837e-19, 2.17402285409e-19, 2.164188984e-19, 
2.15444309566e-19, 2.14478246135e-19,
+            2.13520446164e-19, 2.12570657924e-19, 2.11628639347e-19, 
2.10694157491e-19, 2.09766988055e-19,
+            2.08846914916e-19, 2.079337297e-19, 2.0702723138e-19, 
2.06127225897e-19, 2.05233525809e-19,
+            2.04345949953e-19, 2.03464323137e-19, 2.02588475842e-19, 
2.01718243948e-19, 2.00853468469e-19,
+            1.99993995309e-19, 1.9913967503e-19, 1.9829036263e-19, 
1.97445917335e-19, 1.96606202405e-19,
+            1.95771084943e-19, 1.94940435722e-19, 1.9411412902e-19, 
1.93292042452e-19, 1.92474056827e-19,
+            1.91660056003e-19, 1.90849926746e-19, 1.90043558606e-19, 
1.89240843788e-19, 1.88441677035e-19,
+            1.87645955517e-19, 1.86853578721e-19, 1.8606444835e-19, 
1.85278468221e-19, 1.84495544175e-19,
+            1.83715583984e-19, 1.82938497262e-19, 1.82164195388e-19, 
1.81392591419e-19, 1.80623600019e-19,
+            1.7985713738e-19, 1.79093121154e-19, 1.78331470384e-19, 
1.77572105435e-19, 1.76814947933e-19,
+            1.76059920701e-19, 1.753069477e-19, 1.74555953971e-19, 
1.73806865576e-19, 1.73059609547e-19,
+            1.72314113829e-19, 1.71570307233e-19, 1.70828119379e-19, 
1.7008748065e-19, 1.69348322146e-19,
+            1.68610575631e-19, 1.67874173493e-19, 1.67139048692e-19, 
1.66405134721e-19, 1.6567236556e-19,
+            1.64940675631e-19, 1.64209999755e-19, 1.63480273116e-19, 
1.62751431209e-19, 1.62023409806e-19,
+            1.61296144913e-19, 1.60569572726e-19, 1.59843629593e-19, 
1.59118251972e-19, 1.58393376391e-19,
+            1.57668939404e-19, 1.56944877552e-19, 1.56221127324e-19, 
1.55497625108e-19, 1.54774307158e-19,
+            1.54051109542e-19, 1.53327968107e-19, 1.52604818431e-19, 
1.51881595777e-19, 1.51158235054e-19,
+            1.50434670764e-19, 1.49710836959e-19, 1.48986667191e-19, 
1.48262094465e-19, 1.47537051186e-19,
+            1.46811469107e-19, 1.46085279278e-19, 1.4535841199e-19, 
1.44630796717e-19, 1.43902362058e-19,
+            1.43173035676e-19, 1.42442744238e-19, 1.41711413344e-19, 
1.40978967466e-19, 1.40245329873e-19,
+            1.39510422558e-19, 1.38774166165e-19, 1.38036479905e-19, 
1.37297281475e-19, 1.36556486972e-19,
+            1.35814010798e-19, 1.35069765568e-19, 1.34323662007e-19, 
1.33575608847e-19, 1.32825512715e-19,
+            1.32073278015e-19, 1.31318806805e-19, 1.30561998669e-19, 
1.29802750579e-19, 1.29040956749e-19,
+            1.28276508483e-19, 1.2750929401e-19, 1.26739198313e-19, 
1.25966102948e-19, 1.25189885844e-19,
+            1.24410421101e-19, 1.23627578765e-19, 1.22841224598e-19, 
1.2205121982e-19, 1.21257420848e-19,
+            1.20459679002e-19, 1.19657840201e-19, 1.18851744634e-19, 
1.18041226403e-19, 1.17226113142e-19,
+            1.16406225609e-19, 1.15581377245e-19, 1.14751373693e-19, 
1.13916012285e-19, 1.13075081485e-19,
+            1.12228360281e-19, 1.11375617531e-19, 1.10516611251e-19, 
1.09651087832e-19, 1.08778781199e-19,
+            1.07899411881e-19, 1.07012685997e-19, 1.06118294148e-19, 
1.05215910191e-19, 1.043051899e-19,
+            1.0338576948e-19, 1.02457263929e-19, 1.01519265222e-19, 
1.00571340295e-19, 9.96130287997e-20,
+            9.86438405995e-20, 9.76632529648e-20, 9.66707074276e-20, 
9.56656062409e-20, 9.46473083804e-20,
+            9.36151250173e-20, 9.25683143709e-20, 9.15060758376e-20, 
9.04275432677e-20, 8.93317772338e-20,
+            8.82177561023e-20, 8.70843656749e-20, 8.59303871096e-20, 
8.47544827642e-20, 8.35551795085e-20,
+            8.23308489336e-20, 8.10796837291e-20, 7.97996692841e-20, 
7.84885492861e-20, 7.71437837009e-20,
+            7.57624969795e-20, 7.43414135785e-20, 7.28767768074e-20, 
7.13642454435e-20, 6.97987602408e-20,
+            6.81743689448e-20, 6.64839929862e-20, 6.47191103452e-20, 
6.28693148131e-20, 6.09216875483e-20,
+            5.88598735756e-20, 5.66626751161e-20, 5.43018136309e-20, 
5.17381717445e-20, 4.89150317224e-20,
+            4.57447418908e-20, 4.20788025686e-20, 3.76259867224e-20, 
3.16285898059e-20, 0.0};
+        /** Overhang table. Y_i = f(X_i). */
+        private static final double[] Y = {1.45984107966e-22, 
3.00666134279e-22, 4.61297288151e-22, 6.26633500492e-22,
+            7.95945247619e-22, 9.68746550217e-22, 1.14468770024e-21, 
1.32350363044e-21, 1.50498576921e-21,
+            1.68896530007e-21, 1.87530253827e-21, 2.06387984237e-21, 
2.25459669136e-21, 2.44736615188e-21,
+            2.64211227278e-21, 2.83876811879e-21, 3.03727425675e-21, 
3.23757757e-21, 3.43963031579e-21,
+            3.6433893658e-21, 3.84881558689e-21, 4.05587333095e-21, 
4.26453001043e-21, 4.47475574223e-21,
+            4.68652304654e-21, 4.89980659028e-21, 5.11458296721e-21, 
5.3308305082e-21, 5.5485291167e-21,
+            5.76766012527e-21, 5.98820616992e-21, 6.21015107954e-21, 
6.43347977823e-21, 6.65817819857e-21,
+            6.88423320459e-21, 7.1116325228e-21, 7.34036468049e-21, 
7.57041895029e-21, 7.80178530014e-21,
+            8.03445434816e-21, 8.26841732173e-21, 8.50366602039e-21, 
8.74019278201e-21, 8.97799045203e-21,
+            9.21705235531e-21, 9.45737227039e-21, 9.69894440593e-21, 
9.94176337898e-21, 1.01858241951e-20,
+            1.04311222301e-20, 1.0677653213e-20, 1.09254132104e-20, 
1.11743986124e-20, 1.14246061187e-20,
+            1.16760327269e-20, 1.19286757204e-20, 1.21825326583e-20, 
1.24376013654e-20, 1.2693879923e-20,
+            1.29513666605e-20, 1.32100601473e-20, 1.34699591858e-20, 
1.37310628045e-20, 1.39933702514e-20,
+            1.42568809885e-20, 1.4521594686e-20, 1.47875112175e-20, 
1.50546306552e-20, 1.53229532653e-20,
+            1.55924795044e-20, 1.58632100153e-20, 1.61351456238e-20, 
1.64082873355e-20, 1.66826363327e-20,
+            1.69581939719e-20, 1.72349617811e-20, 1.75129414576e-20, 
1.77921348663e-20, 1.80725440373e-20,
+            1.83541711644e-20, 1.86370186038e-20, 1.89210888728e-20, 
1.92063846482e-20, 1.94929087658e-20,
+            1.97806642193e-20, 2.00696541597e-20, 2.03598818948e-20, 
2.06513508884e-20, 2.09440647607e-20,
+            2.12380272876e-20, 2.15332424009e-20, 2.18297141884e-20, 
2.21274468943e-20, 2.24264449191e-20,
+            2.27267128206e-20, 2.30282553143e-20, 2.33310772738e-20, 
2.36351837324e-20, 2.39405798832e-20,
+            2.42472710808e-20, 2.45552628422e-20, 2.48645608479e-20, 
2.5175170944e-20, 2.54870991431e-20,
+            2.58003516259e-20, 2.61149347436e-20, 2.64308550193e-20, 
2.67481191499e-20, 2.70667340088e-20,
+            2.73867066474e-20, 2.77080442982e-20, 2.80307543767e-20, 
2.83548444847e-20, 2.86803224123e-20,
+            2.90071961414e-20, 2.93354738484e-20, 2.96651639078e-20, 
2.99962748948e-20, 3.03288155897e-20,
+            3.06627949809e-20, 3.09982222687e-20, 3.13351068696e-20, 
3.16734584202e-20, 3.20132867816e-20,
+            3.23546020438e-20, 3.26974145302e-20, 3.30417348029e-20, 
3.33875736673e-20, 3.37349421775e-20,
+            3.40838516421e-20, 3.44343136293e-20, 3.4786339973e-20, 
3.51399427794e-20, 3.54951344328e-20,
+            3.58519276026e-20, 3.62103352501e-20, 3.65703706358e-20, 
3.69320473266e-20, 3.7295379204e-20,
+            3.76603804721e-20, 3.80270656658e-20, 3.83954496597e-20, 
3.87655476775e-20, 3.91373753011e-20,
+            3.95109484807e-20, 3.98862835454e-20, 4.02633972133e-20, 
4.06423066034e-20, 4.10230292468e-20,
+            4.14055830991e-20, 4.1789986553e-20, 4.21762584518e-20, 
4.25644181026e-20, 4.29544852916e-20,
+            4.33464802983e-20, 4.3740423912e-20, 4.41363374476e-20, 
4.45342427632e-20, 4.49341622781e-20,
+            4.53361189911e-20, 4.5740136501e-20, 4.61462390263e-20, 
4.65544514274e-20, 4.69647992292e-20,
+            4.73773086444e-20, 4.77920065987e-20, 4.82089207569e-20, 
4.86280795501e-20, 4.90495122048e-20,
+            4.94732487728e-20, 4.98993201633e-20, 5.03277581761e-20, 
5.07585955372e-20, 5.11918659356e-20,
+            5.16276040629e-20, 5.20658456539e-20, 5.25066275307e-20, 
5.29499876488e-20, 5.33959651452e-20,
+            5.38446003902e-20, 5.42959350421e-20, 5.47500121042e-20, 
5.52068759864e-20, 5.566657257e-20,
+            5.61291492763e-20, 5.65946551399e-20, 5.70631408865e-20, 
5.75346590156e-20, 5.80092638886e-20,
+            5.8487011823e-20, 5.89679611927e-20, 5.94521725351e-20, 
5.99397086661e-20, 6.04306348026e-20,
+            6.09250186942e-20, 6.14229307644e-20, 6.19244442624e-20, 
6.24296354262e-20, 6.29385836583e-20,
+            6.34513717154e-20, 6.39680859128e-20, 6.44888163458e-20, 
6.5013657129e-20, 6.55427066567e-20,
+            6.60760678847e-20, 6.66138486374e-20, 6.71561619424e-20, 
6.7703126396e-20, 6.82548665622e-20,
+            6.88115134113e-20, 6.93732047997e-20, 6.9940085999e-20, 
7.05123102793e-20, 7.10900395534e-20,
+            7.16734450906e-20, 7.22627083097e-20, 7.28580216611e-20, 
7.3459589613e-20, 7.4067629755e-20,
+            7.46823740371e-20, 7.53040701672e-20, 7.59329831907e-20, 
7.65693972825e-20, 7.72136177895e-20,
+            7.78659735664e-20, 7.85268196595e-20, 7.91965404039e-20, 
7.9875553017e-20, 8.05643117889e-20,
+            8.12633129964e-20, 8.19731007037e-20, 8.26942736526e-20, 
8.34274935088e-20, 8.41734948075e-20,
+            8.49330970528e-20, 8.57072195782e-20, 8.64968999859e-20, 
8.73033172957e-20, 8.81278213789e-20,
+            8.89719709282e-20, 8.98375832393e-20, 9.07268006979e-20, 
9.16421814841e-20, 9.25868264067e-20,
+            9.35645614803e-20, 9.45802100126e-20, 9.56400155509e-20, 
9.67523347705e-20, 9.79288516978e-20,
+            9.91869058575e-20, 1.00554562713e-19, 1.02084073773e-19, 
1.03903609932e-19, 1.08420217249e-19};
+
+        /** Exponential sampler used for the long tail. */
+        private final SharedStateContinuousSampler exponential;
+
+        /**
+         * @param rng Generator of uniformly distributed random numbers.
+         */
+        private NormalizedGaussian(UniformRandomProvider rng) {
+            super(rng);
+            exponential = ZigguratSampler.Exponential.of(rng);
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public String toString() {
+            return toString("normalized Gaussian");
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public double sample() {
+            final long xx = nextLong();
+            // Float multiplication squashes these last 8 bits, so they can be 
used to sample i
+            final int i = ((int) xx) & MASK_INT8;
+
+            if (i < I_MAX) {
+                // Early exit.
+                // Branch frequency: 0.988280
+                return X[i] * xx;
+            }
+
+            long u1 = randomInt63();
+            // Another squashed, recyclable bit
+            // double sign_bit = u1 & 0x100 ? 1. : -1.
+            // Use 2 - 1 or 0 - 1
+            final double signBit = ((u1 >>> 7) & 0x2) - 1.0;
+            final int j = normSampleA();
+            // Four kinds of overhangs:
+            //  j = 0                :  Sample from tail
+            //  0 < j < J_INFLECTION :  Overhang is concave; only sample from 
Lower-Left triangle
+            //  j = J_INFLECTION     :  Must sample from entire overhang 
rectangle
+            //  j > J_INFLECTION     :  Overhangs are convex; implicitly 
accept point in Lower-Left triangle
+            //
+            // Conditional statements are arranged such that the more likely 
outcomes are first.
+            double x;
+            if (j > J_INFLECTION) {
+                // Convex overhang
+                // Branch frequency: 0.00891413
+                for (;;) {
+                    x = fastPrngSampleX(X, j, u1);
+                    final long uDiff = randomInt63() - u1;
+                    if (uDiff > MIN_IE) {
+                        break;
+                    }
+                    if (uDiff < MAX_IE) {
+                        continue;
+                    }
+                    // Long.MIN_VALUE is used as an unsigned int with value 
2^63:
+                    // uy = Long.MIN_VALUE - (ux + uDiff)
+                    if (fastPrngSampleY(Y, j, Long.MIN_VALUE - (u1 + uDiff)) < 
Math.exp(-0.5 * x * x)) {
+                        break;
+                    }
+                    u1 = randomInt63();
+                }
+            } else if (j == 0) {
+                // Tail
+                // Branch frequency: 0.000277067
+                // Note: Although less frequent than the next branch, j == 0 
is a subset of
+                // j < J_INFLECTION and must be first.
+                do {
+                    x = ONE_OVER_X_0 * exponential.sample();
+                } while (exponential.sample() < 0.5 * x * x);
+                x += X_0;
+            } else if (j < J_INFLECTION) {
+                // Concave overhang
+                // Branch frequency: 0.00251223
+                for (;;) {
+                    // U_x <- min(U_1, U_2)
+                    // distance <- | U_1 - U_2 |
+                    // U_y <- 1 - (U_x + distance)
+                    long uDiff = randomInt63() - u1;
+                    if (uDiff < 0) {
+                        uDiff = -uDiff;
+                        u1 -= uDiff;
+                    }
+                    x = fastPrngSampleX(X, j, u1);
+                    if (uDiff > MIN_IE)  {
+                        break;
+                    }
+                    if (fastPrngSampleY(Y, j, Long.MIN_VALUE - (u1 + uDiff)) < 
Math.exp(-0.5 * x * x)) {
+                        break;
+                    }
+                    u1 = randomInt63();
+                }
+            } else {
+                // Inflection point
+                // Branch frequency: 0.0000161147
+                for (;;) {
+                    x = fastPrngSampleX(X, j, u1);
+                    if (fastPrngSampleY(Y, j, randomInt63()) < Math.exp(-0.5 * 
x * x)) {
+                        break;
+                    }
+                    u1 = randomInt63();
+                }
+            }
+            return signBit * x;
+        }
+
+        /**
+         * Alias sampling.
+         * See http://scorevoting.net/WarrenSmithPages/homepage/sampling.abs
+         *
+         * @return the alias
+         */
+        private int normSampleA() {
+            final long x = nextLong();
+            // j <- I(0, 256)
+            final int j = ((int) x) & MASK_INT8;
+            return x >= IPMF[j] ? MAP[j] & MASK_INT8 : j;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        public NormalizedGaussian 
withUniformRandomProvider(UniformRandomProvider rng) {
+            return new NormalizedGaussian(rng);
+        }
+
+        /**
+         * Create a new normalised Gaussian sampler.
+         *
+         * @param rng Generator of uniformly distributed random numbers.
+         * @return the sampler
+         */
+        public static NormalizedGaussian of(UniformRandomProvider rng) {
+            return new NormalizedGaussian(rng);
+        }
+    }
+
+    /**
+     * @param rng Generator of uniformly distributed random numbers.
+     */
+    ZigguratSampler(UniformRandomProvider rng) {
+        this.rng = rng;
+    }
+
+    /**
+     * Generate a string to represent the sampler.
+     *
+     * @param type Sampler type (e.g. "exponential").
+     * @return the string
+     */
+    String toString(String type) {
+        return "Modified ziggurat " + type + " deviate [" + rng.toString() + 
"]";
+    }
+
+    /**
+     * Generates a {@code long}.
+     *
+     * @return the long
+     */
+    long nextLong() {
+        return rng.nextLong();
+    }
+
+    /**
+     * Generates a positive {@code long} in {@code [0, 2^63)}.
+     *
+     * @return the long
+     */
+    long randomInt63() {
+        return rng.nextLong() & MAX_INT64;
+    }
+
+    /**
+     * Auxiliary function to see if rejection sampling is required in the 
overhang. See
+     * Fig. 2 in the main text.
+     *
+     * @param x Precomputed ziggurat lengths, denoted X_i in the main text.
+     *          X_i = length of ziggurat layer i.
+     * @param j j
+     * @param ux ux
+     * @return the sample
+     */
+    static double fastPrngSampleX(double[] x, int j, long ux) {
+        return x[j] * TWO_POW_63 + (x[j - 1] - x[j]) * ux;
+    }
+
+    /**
+     * Auxiliary function to see if rejection sampling is required in the 
overhang. See
+     * Fig. 2 in the main text.
+     *
+     * @param y Overhang table. Y_i = f(X_i).
+     * @param i i
+     * @param uy uy
+     * @return the sample
+     */
+    static double fastPrngSampleY(double[] y, int i, long uy) {
+        return y[i - 1] * TWO_POW_63 + (y[i] - y[i - 1]) * uy;
+    }
+
+    /**
+     * Helper function to convert {@code int} values to bytes using a 
narrowing primitive conversion.
+     *
+     * <pre>
+     * int i = ...
+     * byte b = (byte) i;
+     * </pre>
+     *
+     * @param values Integer values.
+     * @return the bytes
+     */
+    static byte[] toBytes(int[] values) {
+        final byte[] bytes = new byte[values.length];
+        for (int i = 0; i < bytes.length; i++) {
+            bytes[i] = (byte) values[i];
+        }
+        return bytes;
+    }
+}
diff --git 
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
index 94c6e3c..4cd4f3c 100644
--- 
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
+++ 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ContinuousSamplersList.java
@@ -62,6 +62,10 @@ public final class ContinuousSamplersList {
             add(LIST, new 
org.apache.commons.math3.distribution.NormalDistribution(unusedRng, meanNormal, 
sigmaNormal),
                 GaussianSampler.of(new 
ZigguratNormalizedGaussianSampler(RandomSource.MT.create()),
                                    meanNormal, sigmaNormal));
+            // Gaussian ("Modified ziggurat").
+            add(LIST, new 
org.apache.commons.math3.distribution.NormalDistribution(unusedRng, meanNormal, 
sigmaNormal),
+                
GaussianSampler.of(ZigguratSampler.NormalizedGaussian.of(RandomSource.MT.create()),
+                                   meanNormal, sigmaNormal));
 
             // Beta ("inverse method").
             final double alphaBeta = 4.3;
@@ -102,6 +106,9 @@ public final class ContinuousSamplersList {
             // Exponential ("Ziggurat").
             add(LIST, new 
org.apache.commons.math3.distribution.ExponentialDistribution(unusedRng, 
meanExp),
                 ZigguratExponentialSampler.of(RandomSource.KISS.create(), 
meanExp));
+            // Exponential ("Modified ziggurat").
+            add(LIST, new 
org.apache.commons.math3.distribution.ExponentialDistribution(unusedRng, 
meanExp),
+                
ZigguratSampler.Exponential.of(RandomSource.XO_RO_SHI_RO_128_SS.create(), 
meanExp));
 
             // F ("inverse method").
             final int numDofF = 4;
diff --git 
a/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ZigguratSamplerTest.java
 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ZigguratSamplerTest.java
new file mode 100644
index 0000000..7275387
--- /dev/null
+++ 
b/commons-rng-sampling/src/test/java/org/apache/commons/rng/sampling/distribution/ZigguratSamplerTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.sampling.distribution;
+
+import org.junit.Test;
+import org.apache.commons.rng.RestorableUniformRandomProvider;
+import org.apache.commons.rng.UniformRandomProvider;
+import org.apache.commons.rng.sampling.RandomAssert;
+import org.apache.commons.rng.simple.RandomSource;
+
+/**
+ * Test for {@link ZigguratSampler}.
+ */
+public class ZigguratSamplerTest {
+    /**
+     * Test the exponential constructor with a bad mean.
+     */
+    @Test(expected = IllegalArgumentException.class)
+    public void testExponentialConstructorThrowsWithZeroMean() {
+        final RestorableUniformRandomProvider rng = 
RandomSource.SPLIT_MIX_64.create(0L);
+        final double mean = 0;
+        ZigguratSampler.Exponential.of(rng, mean);
+    }
+
+    /**
+     * Test the exponential SharedStateSampler implementation.
+     */
+    @Test
+    public void testExponentialSharedStateSampler() {
+        final UniformRandomProvider rng1 = 
RandomSource.SPLIT_MIX_64.create(0L);
+        final UniformRandomProvider rng2 = 
RandomSource.SPLIT_MIX_64.create(0L);
+        final ZigguratSampler.Exponential sampler1 = 
ZigguratSampler.Exponential.of(rng1);
+        final ZigguratSampler.Exponential sampler2 = 
sampler1.withUniformRandomProvider(rng2);
+        RandomAssert.assertProduceSameSequence(sampler1, sampler2);
+    }
+
+    /**
+     * Test the exponential SharedStateSampler implementation with a mean.
+     */
+    @Test
+    public void testExponentialSharedStateSamplerWithMean() {
+        final UniformRandomProvider rng1 = 
RandomSource.SPLIT_MIX_64.create(0L);
+        final UniformRandomProvider rng2 = 
RandomSource.SPLIT_MIX_64.create(0L);
+        final double mean = 1.23;
+        final ZigguratSampler.Exponential sampler1 = 
ZigguratSampler.Exponential.of(rng1, mean);
+        final ZigguratSampler.Exponential sampler2 = 
sampler1.withUniformRandomProvider(rng2);
+        RandomAssert.assertProduceSameSequence(sampler1, sampler2);
+    }
+
+    /**
+     * Test the Gaussian SharedStateSampler implementation.
+     */
+    @Test
+    public void testGaussianSharedStateSampler() {
+        final UniformRandomProvider rng1 = 
RandomSource.SPLIT_MIX_64.create(0L);
+        final UniformRandomProvider rng2 = 
RandomSource.SPLIT_MIX_64.create(0L);
+        final ZigguratSampler.NormalizedGaussian sampler1 = 
ZigguratSampler.NormalizedGaussian.of(rng1);
+        final ZigguratSampler.NormalizedGaussian sampler2 = 
sampler1.withUniformRandomProvider(rng2);
+        RandomAssert.assertProduceSameSequence(sampler1, sampler2);
+    }
+}

Reply via email to