commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aherb...@apache.org
Subject [commons-rng] 02/10: RNG-79: Benchmark methods for producing nextDouble and nextFloat
Date Wed, 06 Mar 2019 15:46:59 GMT
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 ac929bf427059c957ace0ee880d6b6801d153601
Author: Alex Herbert <aherbert@apache.org>
AuthorDate: Mon Mar 4 21:40:17 2019 +0000

    RNG-79: Benchmark methods for producing nextDouble and nextFloat
---
 .../commons/rng/core/util/NumberFactoryTest.java   |  63 +++++----
 .../rng/examples/jmh/NextDoublePerformance.java    | 152 +++++++++++++++++++++
 2 files changed, 189 insertions(+), 26 deletions(-)

diff --git a/commons-rng-core/src/test/java/org/apache/commons/rng/core/util/NumberFactoryTest.java
b/commons-rng-core/src/test/java/org/apache/commons/rng/core/util/NumberFactoryTest.java
index 3088ca4..40e2989 100644
--- a/commons-rng-core/src/test/java/org/apache/commons/rng/core/util/NumberFactoryTest.java
+++ b/commons-rng-core/src/test/java/org/apache/commons/rng/core/util/NumberFactoryTest.java
@@ -29,29 +29,12 @@ public class NumberFactoryTest {
     final int LONG_SIZE = 8;
 
     /** Test values. */
-    private static final long[] LONG_TEST_VALUES = new long[] {
-        0L,
-        1L,
-        -1L,
-        19337L,
-        1234567891011213L,
-        -11109876543211L,
-        Long.valueOf(Integer.MAX_VALUE),
-        Long.valueOf(Integer.MIN_VALUE),
-        Long.MAX_VALUE,
-        Long.MIN_VALUE,
-    };
+    private static final long[] LONG_TEST_VALUES = new long[] { 0L, 1L, -1L, 19337L, 1234567891011213L,
+            -11109876543211L, Long.valueOf(Integer.MAX_VALUE), Long.valueOf(Integer.MIN_VALUE),
Long.MAX_VALUE,
+            Long.MIN_VALUE, };
     /** Test values. */
-    private static final int[] INT_TEST_VALUES = new int[] {
-        0,
-        1,
-        -1,
-        19337,
-        1234567891,
-        -1110987656,
-        Integer.MAX_VALUE,
-        Integer.MIN_VALUE,
-    };
+    private static final int[] INT_TEST_VALUES = new int[] { 0, 1, -1, 19337, 1234567891,
-1110987656,
+            Integer.MAX_VALUE, Integer.MIN_VALUE, };
 
     @Test
     public void testMakeIntFromLong() {
@@ -85,8 +68,7 @@ public class NumberFactoryTest {
     @Test
     public void testLongArrayFromByteArray2LongArray() {
         final byte[] b = NumberFactory.makeByteArray(LONG_TEST_VALUES);
-        Assert.assertArrayEquals(LONG_TEST_VALUES,
-                                 NumberFactory.makeLongArray(b));
+        Assert.assertArrayEquals(LONG_TEST_VALUES, NumberFactory.makeLongArray(b));
     }
 
     @Test
@@ -100,8 +82,7 @@ public class NumberFactoryTest {
     @Test
     public void testIntArrayFromByteArray2IntArray() {
         final byte[] b = NumberFactory.makeByteArray(INT_TEST_VALUES);
-        Assert.assertArrayEquals(INT_TEST_VALUES,
-                                 NumberFactory.makeIntArray(b));
+        Assert.assertArrayEquals(INT_TEST_VALUES, NumberFactory.makeIntArray(b));
     }
 
     @Test
@@ -159,4 +140,34 @@ public class NumberFactoryTest {
             }
         }
     }
+
+    @Test
+    public void testFloatGeneration() {
+        final int allBits = 0xffffffff;
+
+        // Not capable of generating 1
+        Assert.assertEquals(1, (allBits >>> 9) * 0x1.0p-23f, 1e-6);
+        Assert.assertEquals(1, (allBits >>> 8) * 0x1.0p-24f, 1e-6);
+        Assert.assertEquals(1, Float.intBitsToFloat(0x7f << 23 | allBits >>>
9) - 1.0f, 1e-6);
+
+        final int noBits = 0;
+        Assert.assertEquals(0, (noBits >>> 8) * 0x1.0p-24f, 0);
+        Assert.assertEquals(0, (noBits >>> 9) * 0x1.0p-23f, 0);
+        Assert.assertEquals(0, Float.intBitsToFloat(0x7f << 23 | noBits >>>
9) - 1.0f, 0);
+    }
+
+    @Test
+    public void testDoubleGeneration() {
+        final long allBits = 0xffffffffffffffffL;
+
+        // Not capable of generating 1
+        Assert.assertEquals(1, (allBits >>> 12) * 0x1.0p-52d, 1e-10);
+        Assert.assertEquals(1, (allBits >>> 11) * 0x1.0p-53d, 1e-10);
+        Assert.assertEquals(1, Double.longBitsToDouble(0x3ffL << 52 | allBits >>>
12) - 1.0, 1e-10);
+
+        final long noBits = 0;
+        Assert.assertEquals(0, (noBits >>> 12) * 0x1.0p-52d, 0);
+        Assert.assertEquals(0, (noBits >>> 11) * 0x1.0p-53d, 0);
+        Assert.assertEquals(0, Double.longBitsToDouble(0x3ffL << 52 | noBits >>>
12) - 1.0, 0);
+    }
 }
diff --git a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/NextDoublePerformance.java
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/NextDoublePerformance.java
new file mode 100644
index 0000000..f182955
--- /dev/null
+++ b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/NextDoublePerformance.java
@@ -0,0 +1,152 @@
+/*
+ * 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;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.State;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Scope;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Executes benchmark to compare the speed of generation of floating point
+ * numbers from the integer primitives.
+ */
+@BenchmarkMode(Mode.Throughput)
+@OutputTimeUnit(TimeUnit.MICROSECONDS)
+@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 NextDoublePerformance {
+    // Mimic the generation of the SplitMix64 algorithm
+    // and a SplitMix32 algorithm to get a spread of input numbers.
+
+    /**
+     * The 64-bit golden ratio number.
+     */
+    private static final long GOLDEN_64 = 0x9e3779b97f4a7c15L;
+    /**
+     * The 32-bit golden ratio number.
+     */
+    private static final long GOLDEN_32 = 0x9e3779b9;
+
+    /** The long state. */
+    private long longState = ThreadLocalRandom.current().nextLong();
+    /** The int state. */
+    private int intState = ThreadLocalRandom.current().nextInt();
+
+    /**
+     * Get the next long in the sequence.
+     *
+     * @return the long
+     */
+    private long nextLong() {
+        return longState += GOLDEN_64;
+    }
+
+    /**
+     * Get the next int in the sequence.
+     *
+     * @return the int
+     */
+    private int nextInt() {
+        return intState += GOLDEN_32;
+    }
+
+    // Benchmark methods
+
+    /**
+     * @return the long
+     */
+    @Benchmark
+    public long nextDoubleBaseline() {
+        return nextLong();
+    }
+
+    /**
+     * @return the double
+     */
+    @Benchmark
+    public double nextDoubleUsingBitsToDouble() {
+        // Combine 11 bit unsigned exponent with value 1023 (768 + 255) with 52 bit mantissa
+        // 0x300L = 256 + 512 = 768
+        // 0x0ff  = 255
+        // This makes a number in the range 1.0 to 2.0 so subtract 1.0
+        return Double.longBitsToDouble(0x3ffL << 52 | nextLong() >>> 12) -
1.0;
+    }
+
+    /**
+     * @return the double
+     */
+    @Benchmark
+    public double nextDoubleUsingMultiply52bits() {
+        return (nextLong() >>> 12) * 0x1.0p-52d; // 1.0 / (1L << 52)
+    }
+
+    /**
+     * @return the double
+     */
+    @Benchmark
+    public double nextDoubleUsingMultiply53bits() {
+        return (nextLong() >>> 11) * 0x1.0p-53d; // 1.0 / (1L << 53)
+    }
+
+    /**
+     * @return the int
+     */
+    @Benchmark
+    public int nextFloatBaseline() {
+        return nextInt();
+    }
+
+    /**
+     * @return the float
+     */
+    @Benchmark
+    public float nextFloatUsingBitsToFloat() {
+        // Combine 8 bit unsigned exponent with value 127 (112 + 15) with 23 bit mantissa
+        // 0x70 = 64 + 32 + 16 = 112
+        // 0x0f = 15
+        // This makes a number in the range 1.0f to 2.0f so subtract 1.0f
+        return Float.intBitsToFloat(0x7f << 23 | nextInt() >>> 9) - 1.0f;
+    }
+
+    /**
+     * @return the float
+     */
+    @Benchmark
+    public float nextFloatUsingMultiply23bits() {
+        return (nextInt() >>> 9) * 0x1.0p-23f; // 1.0f / (1 << 23)
+    }
+
+    /**
+     * @return the float
+     */
+    @Benchmark
+    public float nextFloatUsingMultiply24bits() {
+        return (nextInt() >>> 8) * 0x1.0p-24f; // 1.0f / (1 << 24)
+    }
+}


Mime
View raw message