src/java.base/share/classes/java/util/random/L64X256MixRandom.java
branchJDK-8193209-branch
changeset 57547 56cbdc3ea079
parent 57437 f02ffcb61dce
child 57684 7cb325557832
equal deleted inserted replaced
57546:1ca1cfdcb451 57547:56cbdc3ea079
    25 
    25 
    26 package java.util.random;
    26 package java.util.random;
    27 
    27 
    28 import java.math.BigInteger;
    28 import java.math.BigInteger;
    29 import java.util.concurrent.atomic.AtomicLong;
    29 import java.util.concurrent.atomic.AtomicLong;
       
    30 import java.util.random.RandomGenerator.SplittableGenerator;
       
    31 import java.util.random.RandomSupport.AbstractSplittableGenerator;
    30 
    32 
    31 /**
    33 /**
    32  * A generator of uniform pseudorandom values applicable for use in
    34  * A generator of uniform pseudorandom values applicable for use in
    33  * (among other contexts) isolated parallel computations that may
    35  * (among other contexts) isolated parallel computations that may
    34  * generate subtasks.  Class {@link L64X256MixRandom} implements
    36  * generate subtasks.  Class {@link L64X256MixRandom} implements
    35  * interfaces {@link RandomNumberGenerator} and {@link SplittableRNG},
    37  * interfaces {@link RandomGenerator} and {@link SplittableGenerator},
    36  * and therefore supports methods for producing pseudorandomly chosen
    38  * and therefore supports methods for producing pseudorandomly chosen
    37  * numbers of type {@code int}, {@code long}, {@code float}, and {@code double}
    39  * numbers of type {@code int}, {@code long}, {@code float}, and {@code double}
    38  * as well as creating new split-off {@link L64X256MixRandom} objects,
    40  * as well as creating new split-off {@link L64X256MixRandom} objects,
    39  * with similar usages as for class {@link java.util.SplittableRandom}.
    41  * with similar usages as for class {@link java.util.SplittableRandom}.
    40  * <p>
    42  * <p>
   132  * seed unless the {@linkplain System#getProperty system property}
   134  * seed unless the {@linkplain System#getProperty system property}
   133  * {@code java.util.secureRandomSeed} is set to {@code true}.
   135  * {@code java.util.secureRandomSeed} is set to {@code true}.
   134  *
   136  *
   135  * @since 14
   137  * @since 14
   136  */
   138  */
   137 public final class L64X256MixRandom extends AbstractSplittableRNG {
   139 public final class L64X256MixRandom extends AbstractSplittableGenerator {
   138 
   140 
   139     /*
   141     /*
   140      * Implementation Overview.
   142      * Implementation Overview.
   141      *
   143      *
   142      * The split operation uses the current generator to choose six new 64-bit
   144      * The split operation uses the current generator to choose six new 64-bit
   167     /* ---------------- static fields ---------------- */
   169     /* ---------------- static fields ---------------- */
   168 
   170 
   169     /**
   171     /**
   170      * The seed generator for default constructors.
   172      * The seed generator for default constructors.
   171      */
   173      */
   172     private static final AtomicLong defaultGen = new AtomicLong(RNGSupport.initialSeed());
   174     private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
   173 
   175 
   174     /*
   176     /*
   175      * The period of this generator, which is (2**256 - 1) * 2**64.
   177      * The period of this generator, which is (2**256 - 1) * 2**64.
   176      */
   178      */
   177     private static final BigInteger PERIOD =
   179     private static final BigInteger PERIOD =
   224         this.x2 = x2;
   226         this.x2 = x2;
   225         this.x3 = x3;
   227         this.x3 = x3;
   226         // If x0, x1, x2, and x3 are all zero, we must choose nonzero values.
   228         // If x0, x1, x2, and x3 are all zero, we must choose nonzero values.
   227         if ((x0 | x1 | x2 | x3) == 0) {
   229         if ((x0 | x1 | x2 | x3) == 0) {
   228             // At least three of the four values generated here will be nonzero.
   230             // At least three of the four values generated here will be nonzero.
   229             this.x0 = RNGSupport.mixStafford13(s += RNGSupport.GOLDEN_RATIO_64);
   231             this.x0 = RandomSupport.mixStafford13(s += RandomSupport.GOLDEN_RATIO_64);
   230             this.x1 = RNGSupport.mixStafford13(s += RNGSupport.GOLDEN_RATIO_64);
   232             this.x1 = RandomSupport.mixStafford13(s += RandomSupport.GOLDEN_RATIO_64);
   231             this.x2 = RNGSupport.mixStafford13(s += RNGSupport.GOLDEN_RATIO_64);
   233             this.x2 = RandomSupport.mixStafford13(s += RandomSupport.GOLDEN_RATIO_64);
   232             this.x3 = RNGSupport.mixStafford13(s + RNGSupport.GOLDEN_RATIO_64);
   234             this.x3 = RandomSupport.mixStafford13(s + RandomSupport.GOLDEN_RATIO_64);
   233         }
   235         }
   234     }
   236     }
   235 
   237 
   236     /**
   238     /**
   237      * Creates a new instance of {@link L64X256MixRandom} using the
   239      * Creates a new instance of {@link L64X256MixRandom} using the
   249         // The seed is hashed by mixMurmur64 to produce the `a` parameter.
   251         // The seed is hashed by mixMurmur64 to produce the `a` parameter.
   250         // The seed is hashed by mixStafford13 to produce the initial `x0`,
   252         // The seed is hashed by mixStafford13 to produce the initial `x0`,
   251         // which will then be used to produce the first generated value.
   253         // which will then be used to produce the first generated value.
   252         // The other x values are filled in as if by a SplitMix PRNG with
   254         // The other x values are filled in as if by a SplitMix PRNG with
   253         // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
   255         // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
   254         this(RNGSupport.mixMurmur64(seed ^= RNGSupport.SILVER_RATIO_64),
   256         this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
   255              1,
   257              1,
   256              RNGSupport.mixStafford13(seed),
   258              RandomSupport.mixStafford13(seed),
   257              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   259              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   258              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   260              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   259              RNGSupport.mixStafford13(seed + RNGSupport.GOLDEN_RATIO_64));
   261              RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
   260     }
   262     }
   261 
   263 
   262     /**
   264     /**
   263      * Creates a new instance of {@link L64X256MixRandom} that is likely to
   265      * Creates a new instance of {@link L64X256MixRandom} that is likely to
   264      * generate sequences of values that are statistically independent
   266      * generate sequences of values that are statistically independent
   265      * of those of any other instances in the current program execution,
   267      * of those of any other instances in the current program execution,
   266      * but may, and typically does, vary across program invocations.
   268      * but may, and typically does, vary across program invocations.
   267      */
   269      */
   268     public L64X256MixRandom() {
   270     public L64X256MixRandom() {
   269         // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
   271         // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
   270         this(defaultGen.getAndAdd(RNGSupport.GOLDEN_RATIO_64));
   272         this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
   271     }
   273     }
   272 
   274 
   273     /**
   275     /**
   274      * Creates a new instance of {@link L64X256MixRandom} using the specified array of
   276      * Creates a new instance of {@link L64X256MixRandom} using the specified array of
   275      * initial seed bytes. Instances of {@link L64X256MixRandom} created with the same
   277      * initial seed bytes. Instances of {@link L64X256MixRandom} created with the same
   277      *
   279      *
   278      * @param seed the initial seed
   280      * @param seed the initial seed
   279      */
   281      */
   280     public L64X256MixRandom(byte[] seed) {
   282     public L64X256MixRandom(byte[] seed) {
   281         // Convert the seed to 6 long values, of which the last 4 are not all zero.
   283         // Convert the seed to 6 long values, of which the last 4 are not all zero.
   282         long[] data = RNGSupport.convertSeedBytesToLongs(seed, 6, 4);
   284         long[] data = RandomSupport.convertSeedBytesToLongs(seed, 6, 4);
   283         long a = data[0], s = data[1], x0 = data[2], x1 = data[3], x2 = data[4], x3 = data[5];
   285         long a = data[0], s = data[1], x0 = data[2], x1 = data[3], x2 = data[4], x3 = data[5];
   284         // Force a to be odd.
   286         // Force a to be odd.
   285         this.a = a | 1;
   287         this.a = a | 1;
   286         this.s = s;
   288         this.s = s;
   287         this.x0 = x0;
   289         this.x0 = x0;
   301      * a single {@link L64X256MixRandom} object.  Either or both of the two
   303      * a single {@link L64X256MixRandom} object.  Either or both of the two
   302      * objects may be further split using the {@code split} method,
   304      * objects may be further split using the {@code split} method,
   303      * and the same expected statistical properties apply to the
   305      * and the same expected statistical properties apply to the
   304      * entire set of generators constructed by such recursive splitting.
   306      * entire set of generators constructed by such recursive splitting.
   305      *
   307      *
   306      * @param source a {@link SplittableRNG} instance to be used instead
   308      * @param source a {@link SplittableGenerator} instance to be used instead
   307      *               of this one as a source of pseudorandom bits used to
   309      *               of this one as a source of pseudorandom bits used to
   308      *               initialize the state of the new ones.
   310      *               initialize the state of the new ones.
   309      *
   311      *
   310      * @return a new instance of {@link L64X256MixRandom}
   312      * @return a new instance of {@link L64X256MixRandom}
   311      */
   313      */
   312     public L64X256MixRandom split(SplittableRNG source) {
   314     public L64X256MixRandom split(SplittableGenerator source) {
   313         // Literally pick a new instance "at random".
   315         // Literally pick a new instance "at random".
   314         return new L64X256MixRandom(source.nextLong(), source.nextLong(),
   316         return new L64X256MixRandom(source.nextLong(), source.nextLong(),
   315                                     source.nextLong(), source.nextLong(),
   317                                     source.nextLong(), source.nextLong(),
   316                                     source.nextLong(), source.nextLong());
   318                                     source.nextLong(), source.nextLong());
   317     }
   319     }
   325         final long z = s + x0;
   327         final long z = s + x0;
   326         s = M * s + a;  // LCG
   328         s = M * s + a;  // LCG
   327         long q0 = x0, q1 = x1, q2 = x2, q3 = x3;
   329         long q0 = x0, q1 = x1, q2 = x2, q3 = x3;
   328         { long t = q1 << 17; q2 ^= q0; q3 ^= q1; q1 ^= q2; q0 ^= q3; q2 ^= t; q3 = Long.rotateLeft(q3, 45); }  // xoshiro256 1.0
   330         { long t = q1 << 17; q2 ^= q0; q3 ^= q1; q1 ^= q2; q0 ^= q3; q2 ^= t; q3 = Long.rotateLeft(q3, 45); }  // xoshiro256 1.0
   329         x0 = q0; x1 = q1; x2 = q2; x3 = q3;
   331         x0 = q0; x1 = q1; x2 = q2; x3 = q3;
   330         return RNGSupport.mixLea64(z);  // mixing function
   332         return RandomSupport.mixLea64(z);  // mixing function
   331     }
   333     }
   332 
   334 
   333     public BigInteger period() {
   335     public BigInteger period() {
   334         return PERIOD;
   336         return PERIOD;
   335     }
   337     }