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 80094625cd99bf221b3d616136de694ee32c43c9 Author: Alex Herbert <[email protected]> AuthorDate: Thu Feb 19 16:58:03 2026 +0000 RNG-189: Add arbitrary jump JMH benchmark --- .../rng/examples/jmh/core/JumpBenchmark.java | 89 +++++++++++++++++++++- 1 file changed, 86 insertions(+), 3 deletions(-) diff --git a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java index 0576b89d..20a90563 100644 --- a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java +++ b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/core/JumpBenchmark.java @@ -19,9 +19,12 @@ package org.apache.commons.rng.examples.jmh.core; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; +import java.util.function.ToLongFunction; +import org.apache.commons.rng.ArbitrarilyJumpableUniformRandomProvider; import org.apache.commons.rng.JumpableUniformRandomProvider; import org.apache.commons.rng.LongJumpableUniformRandomProvider; import org.apache.commons.rng.UniformRandomProvider; +import org.apache.commons.rng.core.source32.IntProvider; import org.apache.commons.rng.simple.RandomSource; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; @@ -50,6 +53,13 @@ public class JumpBenchmark { */ @State(Scope.Benchmark) public abstract static class BaseJumpableSource { + /** + * Distance to skip before jumping. + * Used to advance the state of a generator before repeat jumps. + */ + @Param({"0"}) + private int skip; + /** The generator of the next RNG copy from a jump. */ private Supplier<UniformRandomProvider> gen; @@ -70,6 +80,27 @@ public class JumpBenchmark { gen = createJumpFunction(); } + /** + * Creates the RNG. + * + * @param randomSourceName the random source name + * @return the RNG + */ + UniformRandomProvider createRNG(String randomSourceName) { + final UniformRandomProvider rng = RandomSource.valueOf(randomSourceName).create(); + if (skip > 0) { + // Skip the primary output of the generator. + // Assumes either 32-bit or 64-bit output. + final ToLongFunction<UniformRandomProvider> fun = rng instanceof IntProvider ? + UniformRandomProvider::nextInt : + UniformRandomProvider::nextLong; + for (int i = skip; --i >= 0;) { + fun.applyAsLong(rng); + } + } + return rng; + } + /** * Creates the jump function. * The jump will copy the RNG and then move forward the state of the source @@ -124,7 +155,7 @@ public class JumpBenchmark { /** {@inheritDoc} */ @Override protected Supplier<UniformRandomProvider> createJumpFunction() { - final UniformRandomProvider rng = RandomSource.valueOf(randomSourceName).create(); + final UniformRandomProvider rng = createRNG(randomSourceName); if (rng instanceof JumpableUniformRandomProvider) { return ((JumpableUniformRandomProvider) rng)::jump; } @@ -172,7 +203,7 @@ public class JumpBenchmark { /** {@inheritDoc} */ @Override protected Supplier<UniformRandomProvider> createJumpFunction() { - final UniformRandomProvider rng = RandomSource.valueOf(randomSourceName).create(); + final UniformRandomProvider rng = createRNG(randomSourceName); if (rng instanceof LongJumpableUniformRandomProvider) { return ((LongJumpableUniformRandomProvider) rng)::longJump; } @@ -180,6 +211,47 @@ public class JumpBenchmark { } } + /** + * Exercise the {@link ArbitrarilyJumpableUniformRandomProvider#jump(double)} function, + * or the {@link ArbitrarilyJumpableUniformRandomProvider#jumpPowerOfTwo(int)} function. + * + * <p>The power-of-two jump function is called if the distance is an exact {@code int} value. + * + * <p>To jump a small arbitrary amount specify the distance with a fractional component, + * e.g. jump 123 using 123.5, otherwise a power-of-2 jump of 123 will be called. + */ + public static class ArbitrarilyJumpableSource extends BaseJumpableSource { + /** + * Select RNG providers. + */ + @Param({ + "PHILOX_4X32", + "PHILOX_4X64"}) + private String randomSourceName; + + /** Distance to jump. + * Default: 2^99 + 2^49; 2^99 */ + @Param({"6.338253001141153E29", "99"}) + private double distance; + + /** {@inheritDoc} */ + @Override + protected Supplier<UniformRandomProvider> createJumpFunction() { + final UniformRandomProvider rng = createRNG(randomSourceName); + if (rng instanceof ArbitrarilyJumpableUniformRandomProvider) { + final ArbitrarilyJumpableUniformRandomProvider gen = (ArbitrarilyJumpableUniformRandomProvider) rng; + // Switch to a power-of-2 jump if an int + final int logDistance = (int) distance; + if ((double) logDistance == distance) { + return () -> gen.jumpPowerOfTwo(logDistance); + } + final double jumpDistance = Math.floor(distance); + return () -> gen.jump(jumpDistance); + } + throw new IllegalStateException("Invalid arbitrary jump source: " + randomSourceName); + } + } + /** * Jump benchmark. * @@ -194,11 +266,22 @@ public class JumpBenchmark { /** * Long jump benchmark. * - * @param data Source of the long jump + * @param data Source of the jump * @return the copy */ @Benchmark public UniformRandomProvider longJump(LongJumpableSource data) { return data.jump(); } + + /** + * Arbitrary jump benchmark. + * + * @param data Source of the jump + * @return the copy + */ + @Benchmark + public UniformRandomProvider arbitraryJump(ArbitrarilyJumpableSource data) { + return data.jump(); + } }
