--- jsr166/src/main/java/util/SplittableRandom.java 2013/09/20 09:38:07 1.22 +++ jsr166/src/main/java/util/SplittableRandom.java 2014/12/31 07:54:13 1.26 @@ -25,17 +25,14 @@ package java.util; -import java.security.SecureRandom; -import java.net.NetworkInterface; -import java.util.Enumeration; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.DoubleConsumer; import java.util.function.IntConsumer; import java.util.function.LongConsumer; -import java.util.function.DoubleConsumer; -import java.util.stream.StreamSupport; +import java.util.stream.DoubleStream; import java.util.stream.IntStream; import java.util.stream.LongStream; -import java.util.stream.DoubleStream; +import java.util.stream.StreamSupport; /** * A generator of uniform pseudorandom values applicable for use in @@ -89,7 +86,7 @@ import java.util.stream.DoubleStream; * @author Doug Lea * @since 1.8 */ -public class SplittableRandom { +public final class SplittableRandom { /* * Implementation Overview. @@ -112,8 +109,8 @@ public class SplittableRandom { * For nextLong, the mix64 function is based on David Stafford's * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html) * "Mix13" variant of the "64-bit finalizer" function in Austin - * Appleby's MurmurHash3 algorithm See - * http://code.google.com/p/smhasher/wiki/MurmurHash3 . The mix32 + * Appleby's MurmurHash3 algorithm (see + * http://code.google.com/p/smhasher/wiki/MurmurHash3). The mix32 * function is based on Stafford's Mix04 mix function, but returns * the upper 32 bits cast as int. * @@ -142,11 +139,10 @@ public class SplittableRandom { * other cases, this split must be performed in a thread-safe * manner, so we use an AtomicLong to represent the seed rather * than use an explicit SplittableRandom. To bootstrap the - * defaultGen, we start off using a seed based on current time and - * network interface address unless the java.util.secureRandomSeed - * property is set. This serves as a slimmed-down (and insecure) - * variant of SecureRandom that also avoids stalls that may occur - * when using /dev/random. + * defaultGen, we start off using a seed based on current time + * unless the java.util.secureRandomSeed property is set. This + * serves as a slimmed-down (and insecure) variant of SecureRandom + * that also avoids stalls that may occur when using /dev/random. * * It is a relatively simple matter to apply the basic design here * to use 128 bit seeds. However, emulating 128bit arithmetic and @@ -168,7 +164,7 @@ public class SplittableRandom { * The least non-zero value returned by nextDouble(). This value * is scaled by a random value of 53 bits to produce a result. */ - private static final double DOUBLE_ULP = 1.0 / (1L << 53); + private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53); /** * The seed. Updated only via method nextSeed. @@ -192,16 +188,16 @@ public class SplittableRandom { * Computes Stafford variant 13 of 64bit mix function. */ private static long mix64(long z) { - z *= 0xbf58476d1ce4e5b9L; - z = (z ^ (z >>> 32)) * 0x94d049bb133111ebL; - return z ^ (z >>> 32); + z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L; + z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL; + return z ^ (z >>> 31); } /** * Returns the 32 high bits of Stafford variant 4 mix64 function as int. */ private static int mix32(long z) { - z *= 0x62a9d9ed799705f5L; + z = (z ^ (z >>> 33)) * 0x62a9d9ed799705f5L; return (int)(((z ^ (z >>> 28)) * 0xcb24d0a5c88c35b3L) >>> 32); } @@ -209,7 +205,7 @@ public class SplittableRandom { * Returns the gamma value to use for a new split instance. */ private static long mixGamma(long z) { - z *= 0xff51afd7ed558ccdL; // MurmurHash3 mix constants + z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL; // MurmurHash3 mix constants z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L; z = (z ^ (z >>> 33)) | 1L; // force to be odd int n = Long.bitCount(z ^ (z >>> 1)); // ensure enough transitions @@ -239,34 +235,7 @@ public class SplittableRandom { s = (s << 8) | ((long)(seedBytes[i]) & 0xffL); return s; } - long h = 0L; - try { - Enumeration ifcs = - NetworkInterface.getNetworkInterfaces(); - boolean retry = false; // retry once if getHardwareAddress is null - while (ifcs.hasMoreElements()) { - NetworkInterface ifc = ifcs.nextElement(); - if (!ifc.isVirtual()) { // skip fake addresses - byte[] bs = ifc.getHardwareAddress(); - if (bs != null) { - int n = bs.length; - int m = Math.min(n >>> 1, 4); - for (int i = 0; i < m; ++i) - h = (h << 16) ^ (bs[i] << 8) ^ bs[n-1-i]; - if (m < 4) - h = (h << 8) ^ bs[n-1-m]; - h = mix64(h); - break; - } - else if (!retry) - retry = true; - else - break; - } - } - } catch (Exception ignore) { - } - return (h ^ mix64(System.currentTimeMillis()) ^ + return (mix64(System.currentTimeMillis()) ^ mix64(System.nanoTime())); } @@ -375,7 +344,7 @@ public class SplittableRandom { * @return a pseudorandom value */ final double internalNextDouble(double origin, double bound) { - double r = (nextLong() >>> 11) * DOUBLE_ULP; + double r = (nextLong() >>> 11) * DOUBLE_UNIT; if (origin < bound) { r = r * (bound - origin) + origin; if (r >= bound) // correct for rounding @@ -404,7 +373,7 @@ public class SplittableRandom { * may, and typically does, vary across program invocations. */ public SplittableRandom() { // emulate defaultGen.split() - long s = defaultGen.getAndAdd(2*GOLDEN_GAMMA); + long s = defaultGen.getAndAdd(2 * GOLDEN_GAMMA); this.seed = mix64(s); this.gamma = mixGamma(s + GOLDEN_GAMMA); } @@ -539,7 +508,7 @@ public class SplittableRandom { * (inclusive) and one (exclusive) */ public double nextDouble() { - return (mix64(nextSeed()) >>> 11) * DOUBLE_ULP; + return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT; } /** @@ -554,7 +523,7 @@ public class SplittableRandom { public double nextDouble(double bound) { if (!(bound > 0.0)) throw new IllegalArgumentException(BadBound); - double result = (mix64(nextSeed()) >>> 11) * DOUBLE_ULP * bound; + double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound; return (result < bound) ? result : // correct for rounding Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1); }