Repository: commons-math
Updated Branches:
  refs/heads/master 47ed8d920 -> 2bfd81a2b


MATH-1300

Removed call to the random data generator when it is not necessary.

As a corollary, the change provides the property that, if the number of
requested bytes is a mulitple of 4, consecutive calls to "nextBytes" will
return the same sequence as a single call.


Project: http://git-wip-us.apache.org/repos/asf/commons-math/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-math/commit/1d635088
Tree: http://git-wip-us.apache.org/repos/asf/commons-math/tree/1d635088
Diff: http://git-wip-us.apache.org/repos/asf/commons-math/diff/1d635088

Branch: refs/heads/master
Commit: 1d635088f697178660b6e1c9a89d2b7d3bbe2d29
Parents: 47ed8d9
Author: Gilles <er...@apache.org>
Authored: Sun Dec 20 15:45:02 2015 +0100
Committer: Gilles <er...@apache.org>
Committed: Sun Dec 20 15:45:02 2015 +0100

----------------------------------------------------------------------
 .../math4/random/AbstractRandomGenerator.java   | 22 ++++----
 .../math4/random/BitsStreamGenerator.java       | 10 ++--
 .../random/RandomGeneratorAbstractTest.java     | 54 ++++++++++++++++++++
 3 files changed, 72 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-math/blob/1d635088/src/main/java/org/apache/commons/math4/random/AbstractRandomGenerator.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/math4/random/AbstractRandomGenerator.java 
b/src/main/java/org/apache/commons/math4/random/AbstractRandomGenerator.java
index 1b9cead..173f4ee 100644
--- a/src/main/java/org/apache/commons/math4/random/AbstractRandomGenerator.java
+++ b/src/main/java/org/apache/commons/math4/random/AbstractRandomGenerator.java
@@ -109,16 +109,18 @@ public abstract class AbstractRandomGenerator implements 
RandomGenerator {
     public void nextBytes(byte[] bytes) {
         int bytesOut = 0;
         while (bytesOut < bytes.length) {
-          int randInt = nextInt();
-          for (int i = 0; i < 3; i++) {
-              if ( i > 0) {
-                  randInt >>= 8;
-              }
-              bytes[bytesOut++] = (byte) randInt;
-              if (bytesOut == bytes.length) {
-                  return;
-              }
-          }
+            int randInt = nextInt();
+            for (int i = 0; i < 3; i++) {
+                if (i > 0) {
+                    randInt >>= 8;
+                }
+            }
+            if (bytesOut < bytes.length) {
+                bytes[bytesOut++] = (byte) randInt;
+                if (bytesOut == bytes.length) {
+                    return;
+                }
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/commons-math/blob/1d635088/src/main/java/org/apache/commons/math4/random/BitsStreamGenerator.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/apache/commons/math4/random/BitsStreamGenerator.java 
b/src/main/java/org/apache/commons/math4/random/BitsStreamGenerator.java
index 81968e2..7c89b60 100644
--- a/src/main/java/org/apache/commons/math4/random/BitsStreamGenerator.java
+++ b/src/main/java/org/apache/commons/math4/random/BitsStreamGenerator.java
@@ -82,10 +82,12 @@ public abstract class BitsStreamGenerator
             bytes[i + 3] = (byte) ((random >> 24) & 0xff);
             i += 4;
         }
-        int random = next(32);
-        while (i < bytes.length) {
-            bytes[i++] = (byte) (random & 0xff);
-            random >>= 8;
+        if (i < bytes.length) {
+            int random = next(32);
+            while (i < bytes.length) {
+                bytes[i++] = (byte) (random & 0xff);
+                random >>= 8;
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/commons-math/blob/1d635088/src/test/java/org/apache/commons/math4/random/RandomGeneratorAbstractTest.java
----------------------------------------------------------------------
diff --git 
a/src/test/java/org/apache/commons/math4/random/RandomGeneratorAbstractTest.java
 
b/src/test/java/org/apache/commons/math4/random/RandomGeneratorAbstractTest.java
index fa0a462..42a140e 100644
--- 
a/src/test/java/org/apache/commons/math4/random/RandomGeneratorAbstractTest.java
+++ 
b/src/test/java/org/apache/commons/math4/random/RandomGeneratorAbstractTest.java
@@ -28,6 +28,7 @@ import org.apache.commons.math4.util.FastMath;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.Ignore;
 
 /**
  * Base class for RandomGenerator tests.
@@ -361,6 +362,31 @@ public abstract class RandomGeneratorAbstractTest extends 
RandomDataGeneratorTes
 
     }
 
+    // MATH-1300
+    @Test
+    public void testNextBytesChunks() {
+        final int[] chunkSizes = { 4, 8, 12, 16 };
+        final int[] chunks = { 1, 2, 3, 4, 5 };
+        for (int chunkSize : chunkSizes) {
+            for (int numChunks : chunks) {
+                checkNextBytesChunks(chunkSize, numChunks);
+            }
+        }
+    }
+
+    // MATH-1300: Test is ignored because it will fail due to the array
+    // size not being a multiple of 4.
+    @Ignore@Test
+    public void testNextBytesChunksFail() {
+        final int[] chunkSizes = { 5 };
+        final int[] chunks = { 4 };
+        for (int chunkSize : chunkSizes) {
+            for (int numChunks : chunks) {
+                checkNextBytesChunks(chunkSize, numChunks);
+            }
+        }
+    }
+
     @Test
     public void testSeeding() {
         // makeGenerator initializes with fixed seed
@@ -429,4 +455,32 @@ public abstract class RandomGeneratorAbstractTest extends 
RandomDataGeneratorTes
         Assert.assertTrue(Arrays.equals(values[0], values[1]));
     }
 
+    // MATH-1300
+    private void checkNextBytesChunks(int chunkSize,
+                                      int numChunks) {
+        final RandomGenerator rg = makeGenerator();
+        final long seed = 1234567L;
+
+        final byte[] b1 = new byte[chunkSize * numChunks];
+        final byte[] b2 = new byte[chunkSize];
+
+        // Generate the chunks in a single call.
+        rg.setSeed(seed);
+        rg.nextBytes(b1);
+
+        // Reset.
+        rg.setSeed(seed);
+        // Generate the chunks in consecutive calls.
+        for (int i = 0; i < numChunks; i++) {
+            rg.nextBytes(b2);
+        }
+
+        // Store last 128 bytes chunk of b1 into b3.
+        final byte[] b3 = new byte[chunkSize];
+        System.arraycopy(b1, b1.length - b3.length, b3, 0, b3.length);
+
+        // Sequence of calls must be the same.
+        Assert.assertArrayEquals("chunkSize=" + chunkSize + " numChunks=" + 
numChunks,
+                                 b2, b3);
+    }
 }

Reply via email to