Author: sebb
Date: Sat Feb  6 02:36:55 2010
New Revision: 907160

URL: http://svn.apache.org/viewvc?rev=907160&view=rev
Log:
Revert nextInt() and nextLong() to 2.4 behaviour, i.e MAX_VALUE is not included
Rewrite nextLong(long) based on Harmony's implementation of nextInt(int)

Modified:
    
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/math/JVMRandom.java

Modified: 
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/math/JVMRandom.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/math/JVMRandom.java?rev=907160&r1=907159&r2=907160&view=diff
==============================================================================
--- 
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/math/JVMRandom.java
 (original)
+++ 
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/math/JVMRandom.java
 Sat Feb  6 02:36:55 2010
@@ -24,10 +24,15 @@
  * <p><code>JVMRandom</code> is a wrapper that supports all possible 
  * Random methods via the {...@link java.lang.Math#random()} method
  * and its system-wide {...@link Random} object.</p>
- *
+ * <p>
  * It does this to allow for a Random class in which the seed is
  * shared between all members of the class - a better name would
  * have been SharedSeedRandom.
+ * <p>
+ * <b>N.B.</b> the current implementation overrides the methods
+ * {...@link Random#nextInt(int)} and {...@link Random#nextLong()}
+ * to produce positive numbers ranging from 0 (inclusive)
+ * to MAX_VALUE (exclusive).
  * 
  * @since 2.0
  * @version $Id$
@@ -90,15 +95,14 @@
     /**
      * <p>Returns the next pseudorandom, uniformly distributed int value
      * from the Math.random() sequence.</p>
+     * Identical to <code>nextInt(Integer.MAX_VALUE)</code>
+     * <p>
      * <b>N.B. All values are >= 0.<b>
+     * </p>
      * @return the random int
      */
     public int nextInt() {
-        int value = Math.abs(SHARED_RANDOM.nextInt());
-        if (value < 0){ // Integer.MIN_VALUE
-            value = 0; // ensures 0 occurs equally often as other +ve values
-        }
-        return value;
+        return nextInt(Integer.MAX_VALUE);
     }
 
     /**
@@ -117,15 +121,14 @@
     /**
      * <p>Returns the next pseudorandom, uniformly distributed long value
      * from the Math.random() sequence.</p>
+     * Identical to <code>nextLong(Long.MAX_VALUE)</code>
+     * <p>
      * <b>N.B. All values are >= 0.<b>
+     * </p>
      * @return the random long
      */
     public long nextLong() {
-        long value = Math.abs(SHARED_RANDOM.nextLong());
-        if (value < 0){ // Long.MIN_VALUE
-            value = 0; // ensures 0 occurs equally often as other +ve values
-        }
-        return value;
+        return nextLong(Long.MAX_VALUE);
     }
 
 
@@ -144,8 +147,20 @@
                 "Upper bound for nextInt must be positive"
             );
         }
-        // TODO: check this cannot return 'n'
-        return (long)(SHARED_RANDOM.nextDouble() * n);
+        // Code adapted from Harmony Random#nextInt(int)
+        if ((n & -n) == n) { // n is power of 2
+            // dropping lower order bits improves behaviour for low values of n
+            return next63bits() >> 63 // drop all the bits 
+                 - bitsRequired(n-1); // except the ones we need
+        }
+        // Not a power of two
+        long val;
+        long bits;
+        do { // reject some values to improve distribution
+            bits = next63bits();
+            val = bits % n;
+        } while (bits - val + (n - 1) < 0);
+        return val;
      }
 
     /**
@@ -157,6 +172,7 @@
     public boolean nextBoolean() {
         return SHARED_RANDOM.nextBoolean();
     }
+
     /**
      * <p>Returns the next pseudorandom, uniformly distributed float value
      * between <code>0.0</code> and <code>1.0</code> from the Math.random()
@@ -167,6 +183,7 @@
     public float nextFloat() {
         return SHARED_RANDOM.nextFloat();
     }
+
     /**
      * <p>Synonymous to the Math.random() call.</p>
      *
@@ -176,4 +193,32 @@
         return SHARED_RANDOM.nextDouble();
     }
     
+    /**
+     * Get the next unsigned random long
+     * @return unsigned random long
+     */
+    private static long next63bits(){
+        // drop the sign bit to leave 63 random bits
+        return SHARED_RANDOM.nextLong() & 0x7fffffffffffffffL;
+    }
+
+    /**
+     * Count the number of bits required to represent a long number.
+     * 
+     * @param num long number
+     * @return number of bits required
+     */
+    private static int bitsRequired(long num){
+        // Derived from Hacker's Delight, Figure 5-9
+        long y=num; // for checking right bits
+        int n=0; // number of leading zeros found
+        while(true){
+            // 64 = number of bits in a long
+            if (num < 0) return 64-n; // no leading zeroes left
+            if (y == 0) return n; // no bits left to check
+            n++;
+            num=num << 1; // check leading bits
+            y=y >> 1; // check trailing bits
+        }
+    }
 }


Reply via email to