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 085ee67661a1e98ff3cb114ab7c4ab47e0c6a05a
Author: Alex Herbert <aherb...@apache.org>
AuthorDate: Mon Jul 5 17:52:22 2021 +0100

    Faster method for a signed double in [-1, 1)
---
 .../sampling/shape/UnitBallSamplerBenchmark.java   | 27 +++++++++++++++++++++-
 .../rng/sampling/shape/UnitBallSampler.java        | 18 ++++++++++-----
 2 files changed, 38 insertions(+), 7 deletions(-)

diff --git 
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/shape/UnitBallSamplerBenchmark.java
 
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/shape/UnitBallSamplerBenchmark.java
index 87b911b..142d75d 100644
--- 
a/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/shape/UnitBallSamplerBenchmark.java
+++ 
b/commons-rng-examples/examples-jmh/src/main/java/org/apache/commons/rng/examples/jmh/sampling/shape/UnitBallSamplerBenchmark.java
@@ -151,13 +151,15 @@ public class UnitBallSamplerBenchmark {
     public static class Sampler1D extends SamplerData {
         /** Name for the signed double method. */
         private static final String SIGNED_DOUBLE = "signedDouble";
+        /** Name for the signed double method, version 2. */
+        private static final String SIGNED_DOUBLE2 = "signedDouble2";
         /** Name for the two doubles method. */
         private static final String TWO_DOUBLES = "twoDoubles";
         /** Name for the boolean double method. */
         private static final String BOOLEAN_DOUBLE = "booleanDouble";
 
         /** The sampler type. */
-        @Param({BASELINE, SIGNED_DOUBLE, TWO_DOUBLES, BOOLEAN_DOUBLE})
+        @Param({BASELINE, SIGNED_DOUBLE, SIGNED_DOUBLE2, TWO_DOUBLES, 
BOOLEAN_DOUBLE})
         private String type;
 
         /** {@inheritDoc} */
@@ -178,6 +180,14 @@ public class UnitBallSamplerBenchmark {
                         return new double[] {makeSignedDouble(rng.nextLong())};
                     }
                 };
+            } else if (SIGNED_DOUBLE2.equals(type)) {
+                return new Sampler() {
+                    @Override
+                    public double[] sample() {
+                        // Sample [-1, 1) uniformly
+                        return new double[] 
{makeSignedDouble2(rng.nextLong())};
+                    }
+                };
             } else if (TWO_DOUBLES.equals(type)) {
                 return new Sampler() {
                     @Override
@@ -739,6 +749,21 @@ public class UnitBallSamplerBenchmark {
      * @return the double
      */
     private static double makeSignedDouble(long bits) {
+        // As per o.a.c.rng.core.utils.NumberFactory.makeDouble(long) but 
using a signed
+        // shift of 10 in place of an unsigned shift of 11.
+        return (bits >> 10) * 0x1.0p-53d;
+    }
+
+    /**
+     * Creates a signed double in the range {@code [-1, 1)}. The magnitude is 
sampled evenly
+     * from the 2<sup>54</sup> dyadic rationals in the range.
+     *
+     * <p>Note: This method will not return samples for both -0.0 and 0.0.
+     *
+     * @param bits the bits
+     * @return the double
+     */
+    private static double makeSignedDouble2(long bits) {
         // Use the upper 54 bits on the assumption they are more random.
         // The sign bit generates a value of 0 or 1 for subtraction.
         // The next 53 bits generates a positive number in the range [0, 1).
diff --git 
a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/shape/UnitBallSampler.java
 
b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/shape/UnitBallSampler.java
index 75b3ded..3096584 100644
--- 
a/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/shape/UnitBallSampler.java
+++ 
b/commons-rng-sampling/src/main/java/org/apache/commons/rng/sampling/shape/UnitBallSampler.java
@@ -42,8 +42,13 @@ public abstract class UnitBallSampler implements 
SharedStateObjectSampler<double
     private static final int TWO_D = 2;
     /** The dimension for 3D sampling. */
     private static final int THREE_D = 3;
-    /** The mask to extract the lower 53-bits from a long. */
-    private static final long LOWER_53_BITS = -1L >>> 11;
+    /**
+     * The multiplier to convert the least significant 53-bits of a {@code 
long} to a {@code double}.
+     * Taken from o.a.c.rng.core.utils.NumberFactory.
+     *
+     * <p>This is equivalent to 1.0 / (1L << 53).
+     */
+    private static final double DOUBLE_MULTIPLIER = 0x1.0p-53d;
 
     /**
      * Sample uniformly from a 1D unit line.
@@ -239,10 +244,11 @@ public abstract class UnitBallSampler implements 
SharedStateObjectSampler<double
      * @return the double
      */
     private static double makeSignedDouble(long bits) {
+        // As per o.a.c.rng.core.utils.NumberFactory.makeDouble(long) but 
using a signed 
+        // shift of 10 in place of an unsigned shift of 11.
         // Use the upper 54 bits on the assumption they are more random.
-        // The sign bit generates a value of 0 or 1 for subtraction.
-        // The next 53 bits generates a positive number in the range [0, 1).
-        // [0, 1) - (0 or 1) => [-1, 1)
-        return (((bits >>> 10) & LOWER_53_BITS) * 0x1.0p-53d) - (bits >>> 63);
+        // The sign bit is maintained by the signed shift.
+        // The next 53 bits generates a magnitude in the range [0, 2^53) or 
[-2^53, 0).
+        return (bits >> 10) * DOUBLE_MULTIPLIER;
     }
 }

Reply via email to