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
The following commit(s) were added to refs/heads/master by this push:
new 74bcee7 Add performance test for exp(x) with x in [-8, 0]
74bcee7 is described below
commit 74bcee71a520c47deabaa24ff7c1af10ac8b16e9
Author: Alex Herbert <[email protected]>
AuthorDate: Sat Aug 28 10:13:04 2021 +0100
Add performance test for exp(x) with x in [-8, 0]
---
.../distribution/ZigguratSamplerPerformance.java | 113 ++++++++++++++++++++-
1 file changed, 111 insertions(+), 2 deletions(-)
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
index 58d7747..44067ad 100644
---
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
@@ -17,6 +17,7 @@
package org.apache.commons.rng.examples.jmh.sampling.distribution;
+import org.apache.commons.math3.util.FastMath;
import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.sampling.distribution.ContinuousSampler;
import org.apache.commons.rng.sampling.distribution.DiscreteSampler;
@@ -402,6 +403,59 @@ public class ZigguratSamplerPerformance {
}
/**
+ * Defines method to use for computing {@code exp(x)} when {@code -8 <= x
<= 0}.
+ */
+ @State(Scope.Benchmark)
+ public static class ExpSources {
+ /** The method to compute exp(x). */
+ @Param({"noop", "Math.exp", "FastMath.exp"})
+ private String method;
+
+ /** The sampler. */
+ private ContinuousSampler sampler;
+
+ /**
+ * @return the sampler.
+ */
+ public ContinuousSampler getSampler() {
+ return sampler;
+ }
+
+ /** Instantiates sampler. */
+ @Setup
+ public void setup() {
+ // Use a fast generator:
+ // Here we use a simple linear congruential generator
+ // which should have constant speed and a random upper bit.
+ final long[] s = {ThreadLocalRandom.current().nextLong()};
+ // From a random long we create a value in (-8, 0] by using the
+ // method to generate [0, 1) and then multiplying by -8:
+ // (x >>> 11) * 0x1.0p-53 * -0x1.0p3
+ if ("noop".equals(method)) {
+ sampler = () -> {
+ final long x = s[0];
+ s[0] = updateLCG(x);
+ return (x >>> 11) * -0x1.0p-50;
+ };
+ } else if ("Math.exp".equals(method)) {
+ sampler = () -> {
+ final long x = s[0];
+ s[0] = updateLCG(x);
+ return Math.exp((x >>> 11) * -0x1.0p-50);
+ };
+ } else if ("FastMath.exp".equals(method)) {
+ sampler = () -> {
+ final long x = s[0];
+ s[0] = updateLCG(x);
+ return FastMath.exp((x >>> 11) * -0x1.0p-50);
+ };
+ } else {
+ throwIllegalStateException(method);
+ }
+ }
+ }
+
+ /**
* Update the state of the linear congruential generator.
* <pre>
* s = m*s + a
@@ -1443,7 +1497,10 @@ public class ZigguratSamplerPerformance {
*
* <p>This implementation uses simple overhangs and does not exploit the
precomputed
* distances of the concave and convex overhangs. The implementation
matches the c-reference
- * compiled using -DSIMPLE_OVERHANGS.
+ * compiled using -DSIMPLE_OVERHANGS for the non-tail overhangs.
+ *
+ * <p>Note: The tail exponential sampler does not use simple overhangs.
This facilitates
+ * performance comparison to the fast overhang method by keeping tail
sampling the same.
*/
static class ModifiedZigguratNormalizedGaussianSamplerSimpleOverhangs
extends ModifiedZigguratNormalizedGaussianSampler {
@@ -1771,7 +1828,10 @@ public class ZigguratSamplerPerformance {
*
* <p>This implementation uses simple overhangs and does not exploit the
precomputed
* distances of the concave and convex overhangs. The implementation
matches the c-reference
- * compiled using -DSIMPLE_OVERHANGS.
+ * compiled using -DSIMPLE_OVERHANGS for the non-tail overhangs.
+ *
+ * <p>Note: The tail exponential sampler does not use simple overhangs.
This facilitates
+ * performance comparison to the fast overhang method by keeping tail
sampling the same.
*/
static class
ModifiedZigguratNormalizedGaussianSamplerInliningSimpleOverhangs
extends ModifiedZigguratNormalizedGaussianSampler {
@@ -3954,6 +4014,55 @@ public class ZigguratSamplerPerformance {
}
/**
+ * Benchmark methods for obtaining {@code exp(z)} when {@code -8 <= z <=
0}.
+ *
+ * <p>Note: This is disabled. On JDK 8 FastMath is faster. On JDK 11
Math.exp is
+ * a hotspot intrinsic and is faster. Example result:
+ *
+ * <pre>
+ * JDK 8 JDK 11
+ * noop 4.523 4.351
+ * Math.exp 61.350 22.552
+ * FastMath.exp 33.858 31.396
+ * </pre>
+ *
+ * <p>The ziggurat sampler avoids calls to Math.exp in the majority of
cases
+ * when using McFarland's fast method for overhangs which exploit the known
+ * maximum difference between pdf(x) and the triangle hypotenuse. Example
data
+ * of the frequency that Math.exp is called per sample from the base
+ * implementations (using n=2^31):
+ *
+ * <pre>
+ * Calls FastOverhangs SimpleOverhangs
+ * Exp exp(-x) 0.00271 0.0307
+ * Normal exp(-0.5*x*x) 0.00359 0.0197*
+ *
+ * * Increases to 0.0198 if the tail exponential sampler uses simple
overhangs
+ * </pre>
+ *
+ * <p>Note that the maximum difference between pdf(x) and the triangle
+ * hypotenuse is smaller for the exponential distribution; thus the fast
method
+ * can avoid using Math.exp more often. In the case of simple overhangs the
+ * normal distribution has more region covered by the ziggurat thus has a
lower
+ * frequency of overhang sampling.
+ *
+ * <p>A significant speed-up of the exp function may improve run-time of
the
+ * simple overhangs method. Any effect on the fast method is less likely
to be
+ * noticed. This is observed in benchmark times which show an improvement
of the
+ * simple overhangs method for the exponential relative to other methods
on JDK
+ * 11 vs 8. However the simple overhangs is still slower as the exponential
+ * distribution is always concave and upper-right triangle samples are
avoided
+ * by the fast overhang method.
+ *
+ * @param sources Source of randomness.
+ * @return the sample value
+ */
+ //@Benchmark
+ public double exp(ExpSources sources) {
+ return sources.getSampler().sample();
+ }
+
+ /**
* Run the sampler.
*
* @param sources Source of randomness.