You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2016/11/09 12:44:47 UTC
commons-rng git commit: RNG-24: Bridge to "java.util.Random".
Repository: commons-rng
Updated Branches:
refs/heads/multimodule 7e12202ac -> 79fcc8c29
RNG-24: Bridge to "java.util.Random".
Project: http://git-wip-us.apache.org/repos/asf/commons-rng/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-rng/commit/79fcc8c2
Tree: http://git-wip-us.apache.org/repos/asf/commons-rng/tree/79fcc8c2
Diff: http://git-wip-us.apache.org/repos/asf/commons-rng/diff/79fcc8c2
Branch: refs/heads/multimodule
Commit: 79fcc8c29017bbeaaf88dc228c32f446efd845c5
Parents: 7e12202
Author: Gilles <er...@apache.org>
Authored: Wed Nov 9 13:41:51 2016 +0100
Committer: Gilles <er...@apache.org>
Committed: Wed Nov 9 13:41:51 2016 +0100
----------------------------------------------------------------------
.../commons/rng/simple/JDKRandomBridge.java | 125 +++++++++++++++++++
.../commons/rng/simple/JDKRandomBridgeTest.java | 121 ++++++++++++++++++
2 files changed, 246 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-rng/blob/79fcc8c2/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java
----------------------------------------------------------------------
diff --git a/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java
new file mode 100644
index 0000000..b2831db
--- /dev/null
+++ b/commons-rng-simple/src/main/java/org/apache/commons/rng/simple/JDKRandomBridge.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.simple;
+
+import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.util.Random;
+import org.apache.commons.rng.RestorableUniformRandomProvider;
+import org.apache.commons.rng.core.RandomProviderDefaultState;
+
+/**
+ * Subclass of {@link Random} that {@link #next(int) delegates} to a
+ * {@link RestorableUniformRandomProvider} instance but will otherwise
+ * rely on the base class for generating all the random types.
+ * </p>
+ *
+ * <p>
+ * Legacy applications coded against the JDK's API could use this subclass
+ * of {@link Random} in order to replace its linear congruential generator
+ * by any {@link RandomSource}.
+ * Use of this class is however <em>not</em> recommended for new applications.
+ * </p>
+ *
+ * @since 1.0
+ */
+public final class JDKRandomBridge extends Random {
+ /** Serializable version identifier. */
+ private static final long serialVersionUID = 20161107L;
+ /** Source. */
+ private final RandomSource source;
+ /** Delegate. */
+ private transient RestorableUniformRandomProvider delegate;
+ /** Workaround JDK's "Random" bug: https://bugs.openjdk.java.net/browse/JDK-8154225 */
+ private final boolean isInitialized;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param source Source of randomness.
+ * @param seed Seed. Can be {@code null}.
+ */
+ public JDKRandomBridge(RandomSource source,
+ Object seed) {
+ this.source = source;
+ delegate = RandomSource.create(source, seed);
+ isInitialized = true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public synchronized void setSeed(long seed) {
+ if (isInitialized) {
+ delegate = RandomSource.create(source, seed);
+
+ // Force the clearing of the "haveNextNextGaussian" flag
+ // (cf. Javadoc of the base class); the value passed here
+ // is irrelevant (since it will not be used).
+ super.setSeed(0L);
+ }
+ }
+
+ /**
+ * Delegates the generation of 32 random bits to the
+ * {@code RandomSource} argument provided at
+ * {@link #JDKRandomBridge(RandomSource,Object) construction}.
+ * The returned value is such that if the source of randomness is
+ * {@link RandomSource#JDK}, all the generated values will be identical
+ * to those produced by the same sequence of calls on a {@link Random}
+ * instance initialized with the same seed.
+ *
+ * @param n Number of random bits which the requested value must contain.
+ * @return the value represented by the {@code n} high-order bits of a
+ * pseudo-random 32-bits integer.
+ */
+ @Override
+ protected synchronized int next(int n) {
+ return delegate.nextInt() >>> (32 - n);
+ }
+
+ /**
+ * @param out Output stream.
+ * @throws IOException if an error occurs.
+ */
+ private synchronized void writeObject(ObjectOutputStream out)
+ throws IOException {
+ // Write non-transient fields.
+ out.defaultWriteObject();
+
+ // Save current state.
+ out.writeObject(((RandomProviderDefaultState) delegate.saveState()).getState());
+ }
+
+ /**
+ * @param in Input stream.
+ * @throws IOException if an error occurs.
+ * @throws ClassNotFoundException if an error occurs.
+ */
+ private synchronized void readObject(ObjectInputStream in)
+ throws IOException,
+ ClassNotFoundException {
+ // Read non-transient fields.
+ in.defaultReadObject();
+
+ // Recreate the "delegate" from serialized info.
+ delegate = RandomSource.create(source);
+ // And restore its state.
+ delegate.restoreState(new RandomProviderDefaultState((byte[]) in.readObject()));
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-rng/blob/79fcc8c2/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java
----------------------------------------------------------------------
diff --git a/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java
new file mode 100644
index 0000000..70fa450
--- /dev/null
+++ b/commons-rng-simple/src/test/java/org/apache/commons/rng/simple/JDKRandomBridgeTest.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.rng.simple;
+
+import java.io.IOException;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ByteArrayInputStream;
+import java.util.Random;
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link JDKRandomBridge} adaptor class.
+ */
+public class JDKRandomBridgeTest {
+ @Test
+ public void testJDKRandomEquivalence() {
+ // Initialize.
+ final long seed = RandomSource.createLong();
+ final Random rng1 = new Random(seed);
+ final Random rng2 = new JDKRandomBridge(RandomSource.JDK, seed);
+ checkSameSequence(rng1, rng2);
+
+ // Reseed.
+ final long newSeed = RandomSource.createLong();
+ Assert.assertNotEquals(seed, newSeed);
+ rng1.setSeed(newSeed);
+ rng2.setSeed(newSeed);
+ checkSameSequence(rng1, rng2);
+ }
+
+ @Test
+ public void testSerialization()
+ throws IOException,
+ ClassNotFoundException {
+ // Initialize.
+ final long seed = RandomSource.createLong();
+ final Random rng = new JDKRandomBridge(RandomSource.SPLIT_MIX_64, seed);
+
+ // Serialize.
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = new ObjectOutputStream(bos);
+ oos.writeObject(rng);
+
+ // Retrieve from serialized stream.
+ ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ ObjectInputStream ois = new ObjectInputStream(bis);
+ final Random serialRng = (Random) (ois.readObject());
+
+ // Check that the serialized data recreated the orginal state.
+ checkSameSequence(rng, serialRng);
+ }
+
+ /**
+ * Ensure that both generators produce the same sequences.
+ *
+ * @param rng1 RNG.
+ * @param rng2 RNG.
+ */
+ private void checkSameSequence(Random rng1,
+ Random rng2) {
+ for (int i = 0; i < 4; i++) {
+ Assert.assertEquals(rng1.nextInt(),
+ rng2.nextInt());
+ }
+ for (int i = 0; i < 7; i++) {
+ Assert.assertEquals(rng1.nextLong(),
+ rng2.nextLong());
+ }
+ for (int i = 0; i < 9; i++) {
+ Assert.assertEquals(rng1.nextFloat(),
+ rng2.nextFloat(),
+ 0f);
+ }
+ for (int i = 0; i < 12; i++) {
+ Assert.assertEquals(rng1.nextDouble(),
+ rng2.nextDouble(),
+ 0d);
+ }
+ for (int i = 0; i < 17; i++) {
+ Assert.assertEquals(rng1.nextGaussian(),
+ rng2.nextGaussian(),
+ 0d);
+ }
+ for (int i = 0; i < 18; i++) {
+ Assert.assertEquals(rng1.nextBoolean(),
+ rng2.nextBoolean());
+ }
+ for (int i = 0; i < 19; i++) {
+ final int max = i + 123456;
+ Assert.assertEquals(rng1.nextInt(max),
+ rng2.nextInt(max));
+ }
+
+ final int len = 233;
+ final byte[] store1 = new byte[len];
+ final byte[] store2 = new byte[len];
+ rng1.nextBytes(store1);
+ rng2.nextBytes(store2);
+ for (int i = 0; i < len; i++) {
+ Assert.assertEquals(store1[i],
+ store2[i]);
+ }
+ }
+}