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); + } }