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