You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2019/06/15 14:07:14 UTC
[commons-rng] 01/02: RNG-106: Ensure SeedFactory produces non-zero
seed arrays.
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 495e178b16a68b9c708d8b54102c4ad4a03631f0
Author: Alex Herbert <ah...@apache.org>
AuthorDate: Wed Jun 12 17:57:06 2019 +0100
RNG-106: Ensure SeedFactory produces non-zero seed arrays.
---
.../commons/rng/simple/internal/SeedFactory.java | 48 ++++++++++++++++-
.../rng/simple/internal/SeedFactoryTest.java | 60 ++++++++++++++++++++++
2 files changed, 106 insertions(+), 2 deletions(-)
diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/SeedFactory.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/SeedFactory.java
index 90084e8..5ebf42f 100644
--- a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/SeedFactory.java
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/internal/SeedFactory.java
@@ -88,7 +88,9 @@ public final class SeedFactory {
* @return an array of {@code n} random numbers.
*/
public static int[] createIntArray(int n) {
- return createIntArray(n, SEED_GENERATOR, new Object());
+ final int[] seed = createIntArray(n, SEED_GENERATOR, new Object());
+ ensureNonZero(seed);
+ return seed;
}
/**
@@ -98,7 +100,9 @@ public final class SeedFactory {
* @return an array of {@code n} random numbers.
*/
public static long[] createLongArray(int n) {
- return createLongArray(n, SEED_GENERATOR, new Object());
+ final long[] seed = createLongArray(n, SEED_GENERATOR, new Object());
+ ensureNonZero(seed);
+ return seed;
}
/**
@@ -263,4 +267,44 @@ public final class SeedFactory {
return source.next() ^ number;
}
}
+
+ /**
+ * Ensure the seed is non-zero at the first position in the array.
+ *
+ * <p>This method will replace a zero at index 0 in the array with
+ * a non-zero random number. The method ensures any length seed
+ * contains non-zero bits. The output seed is suitable for generators
+ * that cannot be seeded with all zeros.</p>
+ *
+ * @param seed Seed array (modified in place).
+ * @see #createInt()
+ */
+ static void ensureNonZero(int[] seed) {
+ // Zero occurs 1 in 2^32
+ if (seed.length != 0 && seed[0] == 0) {
+ do {
+ seed[0] = createInt();
+ } while (seed[0] == 0);
+ }
+ }
+
+ /**
+ * Ensure the seed is non-zero at the first position in the array.
+ *
+ * <p>This method will replace a zero at index 0 in the array with
+ * a non-zero random number. The method ensures any length seed
+ * contains non-zero bits. The output seed is suitable for generators
+ * that cannot be seeded with all zeros.</p>
+ *
+ * @param seed Seed array (modified in place).
+ * @see #createLong()
+ */
+ static void ensureNonZero(long[] seed) {
+ // Zero occurs 1 in 2^64
+ if (seed.length != 0 && seed[0] == 0) {
+ do {
+ seed[0] = createLong();
+ } while (seed[0] == 0);
+ }
+ }
}
diff --git a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/SeedFactoryTest.java b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/SeedFactoryTest.java
index d9ecc4d..d4298f4 100644
--- a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/SeedFactoryTest.java
+++ b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/internal/SeedFactoryTest.java
@@ -110,4 +110,64 @@ public class SeedFactoryTest {
Assert.fail(duplicates + " duplicates\n" + sb);
}
}
+
+ @Test
+ public void testEnsureNonZeroIntArrayIgnoresEmptySeed() {
+ final int[] seed = new int[0];
+ SeedFactory.ensureNonZero(seed);
+ }
+
+ @Test
+ public void testEnsureNonZeroIntArrayIgnoresNonZeroPosition0() {
+ final int position0 = 123;
+ final int[] seed = new int[] {position0, 0, 0, 0};
+ final int[] before = seed.clone();
+ SeedFactory.ensureNonZero(seed);
+ Assert.assertEquals("Non-zero at position 0 should be unmodified", position0, seed[0]);
+ for (int i = 1; i < seed.length; i++) {
+ Assert.assertEquals("Position above 0 should be unmodified", before[i], seed[i]);
+ }
+ }
+
+ @Test
+ public void testEnsureNonZeroIntArrayUpdatesZeroPosition0() {
+ // Test the method replaces position 0 even if the rest of the array is non-zero
+ final int[] seed = new int[] {0, 123, 456, 789};
+ final int[] before = seed.clone();
+ SeedFactory.ensureNonZero(seed);
+ Assert.assertNotEquals("Zero at position 0 should be modified", 0, seed[0]);
+ for (int i = 1; i < seed.length; i++) {
+ Assert.assertEquals("Position above 0 should be unmodified", before[i], seed[i]);
+ }
+ }
+
+ @Test
+ public void testEnsureNonZeroLongArrayIgnoresEmptySeed() {
+ final long[] seed = new long[0];
+ SeedFactory.ensureNonZero(seed);
+ }
+
+ @Test
+ public void testEnsureNonZeroLongArrayIgnoresNonZeroPosition0() {
+ final long position0 = 123;
+ final long[] seed = new long[] {position0, 0, 0, 0};
+ final long[] before = seed.clone();
+ SeedFactory.ensureNonZero(seed);
+ Assert.assertEquals("Non-zero at position 0 should be unmodified", position0, seed[0]);
+ for (int i = 1; i < seed.length; i++) {
+ Assert.assertEquals("Position above 0 should be unmodified", before[i], seed[i]);
+ }
+ }
+
+ @Test
+ public void testEnsureNonZeroLongArrayUpdatesZeroPosition0() {
+ // Test the method replaces position 0 even if the rest of the array is non-zero
+ final long[] seed = new long[] {0, 123, 456, 789};
+ final long[] before = seed.clone();
+ SeedFactory.ensureNonZero(seed);
+ Assert.assertNotEquals("Zero at position 0 should be modified", 0, seed[0]);
+ for (int i = 1; i < seed.length; i++) {
+ Assert.assertEquals("Position above 0 should be unmodified", before[i], seed[i]);
+ }
+ }
}