src/java.base/share/classes/java/util/random/L64X1024MixRandom.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 L64X1024MixRandom} implements
    36  * generate subtasks.  Class {@link L64X1024MixRandom} 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 L64X1024MixRandom} objects,
    40  * as well as creating new split-off {@link L64X1024MixRandom} 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 L64X1024MixRandom extends AbstractSplittableRNG {
   139 public final class L64X1024MixRandom extends AbstractSplittableGenerator {
   138 
   140 
   139     /*
   141     /*
   140      * Implementation Overview.
   142      * Implementation Overview.
   141      *
   143      *
   142      * The split() operation uses the current generator to choose 18 new 64-bit
   144      * The split() operation uses the current generator to choose 18 new 64-bit
   172     private static final int N = 16;
   174     private static final int N = 16;
   173 
   175 
   174     /**
   176     /**
   175      * The seed generator for default constructors.
   177      * The seed generator for default constructors.
   176      */
   178      */
   177     private static final AtomicLong defaultGen = new AtomicLong(RNGSupport.initialSeed());
   179     private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
   178 
   180 
   179     /*
   181     /*
   180      * The period of this generator, which is (2**1024 - 1) * 2**64.
   182      * The period of this generator, which is (2**1024 - 1) * 2**64.
   181      */
   183      */
   182     private static final BigInteger PERIOD =
   184     private static final BigInteger PERIOD =
   262         this.x[15] = x15;
   264         this.x[15] = x15;
   263         // If x0, x1, ..., x15 are all zero (very unlikely), we must choose nonzero values.
   265         // If x0, x1, ..., x15 are all zero (very unlikely), we must choose nonzero values.
   264         if ((x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15) == 0) {
   266         if ((x0 | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15) == 0) {
   265             // At least fifteen of the sixteen values generated here will be nonzero.
   267             // At least fifteen of the sixteen values generated here will be nonzero.
   266             for (int j = 0; j < N; j++) {
   268             for (int j = 0; j < N; j++) {
   267                 this.x[j] = RNGSupport.mixStafford13(s += RNGSupport.GOLDEN_RATIO_64);
   269                 this.x[j] = RandomSupport.mixStafford13(s += RandomSupport.GOLDEN_RATIO_64);
   268             }
   270             }
   269         }
   271         }
   270     }
   272     }
   271 
   273 
   272     /**
   274     /**
   285         // The seed is hashed by mixMurmur64 to produce the `a` parameter.
   287         // The seed is hashed by mixMurmur64 to produce the `a` parameter.
   286         // The seed is hashed by mixStafford13 to produce the initial `x[0]`,
   288         // The seed is hashed by mixStafford13 to produce the initial `x[0]`,
   287         // which will then be used to produce the first generated value.
   289         // which will then be used to produce the first generated value.
   288         // The other x values are filled in as if by a SplitMix PRNG with
   290         // The other x values are filled in as if by a SplitMix PRNG with
   289         // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
   291         // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
   290         this(RNGSupport.mixMurmur64(seed ^= RNGSupport.SILVER_RATIO_64),
   292         this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
   291              1,
   293              1,
   292              RNGSupport.mixStafford13(seed),
   294              RandomSupport.mixStafford13(seed),
   293              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   295              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   294              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   296              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   295              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   297              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   296              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   298              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   297              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   299              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   298              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   300              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   299              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   301              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   300              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   302              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   301              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   303              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   302              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   304              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   303              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   305              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   304              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   306              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   305              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   307              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   306              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   308              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   307              RNGSupport.mixStafford13(seed + RNGSupport.GOLDEN_RATIO_64));
   309              RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
   308     }
   310     }
   309 
   311 
   310     /**
   312     /**
   311      * Creates a new instance of {@link L64X1024MixRandom} that is likely to
   313      * Creates a new instance of {@link L64X1024MixRandom} that is likely to
   312      * generate sequences of values that are statistically independent
   314      * generate sequences of values that are statistically independent
   313      * of those of any other instances in the current program execution,
   315      * of those of any other instances in the current program execution,
   314      * but may, and typically does, vary across program invocations.
   316      * but may, and typically does, vary across program invocations.
   315      */
   317      */
   316     public L64X1024MixRandom() {
   318     public L64X1024MixRandom() {
   317         // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
   319         // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
   318         this(defaultGen.getAndAdd(RNGSupport.GOLDEN_RATIO_64));
   320         this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
   319     }
   321     }
   320 
   322 
   321     /**
   323     /**
   322      * Creates a new instance of {@link L64X1024MixRandom} using the specified array of
   324      * Creates a new instance of {@link L64X1024MixRandom} using the specified array of
   323      * initial seed bytes. Instances of {@link L64X1024MixRandom} created with the same
   325      * initial seed bytes. Instances of {@link L64X1024MixRandom} created with the same
   325      *
   327      *
   326      * @param seed the initial seed
   328      * @param seed the initial seed
   327      */
   329      */
   328     public L64X1024MixRandom(byte[] seed) {
   330     public L64X1024MixRandom(byte[] seed) {
   329         // Convert the seed to 18 long values, of which the last 16 are not all zero.
   331         // Convert the seed to 18 long values, of which the last 16 are not all zero.
   330         long[] data = RNGSupport.convertSeedBytesToLongs(seed, 18, 16);
   332         long[] data = RandomSupport.convertSeedBytesToLongs(seed, 18, 16);
   331         long a = data[0], s = data[1];
   333         long a = data[0], s = data[1];
   332         // Force a to be odd.
   334         // Force a to be odd.
   333         this.a = a | 1;
   335         this.a = a | 1;
   334         this.s = s;
   336         this.s = s;
   335         this.x = new long[N];
   337         this.x = new long[N];
   349      * a single {@link L64X1024MixRandom} object.  Either or both of the two
   351      * a single {@link L64X1024MixRandom} object.  Either or both of the two
   350      * objects may be further split using the {@code split} method,
   352      * objects may be further split using the {@code split} method,
   351      * and the same expected statistical properties apply to the
   353      * and the same expected statistical properties apply to the
   352      * entire set of generators constructed by such recursive splitting.
   354      * entire set of generators constructed by such recursive splitting.
   353      *
   355      *
   354      * @param source a {@link SplittableRNG} instance to be used instead
   356      * @param source a {@link SplittableGenerator} instance to be used instead
   355      *               of this one as a source of pseudorandom bits used to
   357      *               of this one as a source of pseudorandom bits used to
   356      *               initialize the state of the new ones.
   358      *               initialize the state of the new ones.
   357      * @return a new instance of {@link L64X1024MixRandom}
   359      * @return a new instance of {@link L64X1024MixRandom}
   358      */
   360      */
   359     public L64X1024MixRandom split(SplittableRNG source) {
   361     public L64X1024MixRandom split(SplittableGenerator source) {
   360         // Literally pick a new instance "at random".
   362         // Literally pick a new instance "at random".
   361         return new L64X1024MixRandom(source.nextLong(), source.nextLong(),
   363         return new L64X1024MixRandom(source.nextLong(), source.nextLong(),
   362                                      source.nextLong(), source.nextLong(),
   364                                      source.nextLong(), source.nextLong(),
   363                                      source.nextLong(), source.nextLong(),
   365                                      source.nextLong(), source.nextLong(),
   364                                      source.nextLong(), source.nextLong(),
   366                                      source.nextLong(), source.nextLong(),
   386         // Second part of xoroshiro1024: update array data
   388         // Second part of xoroshiro1024: update array data
   387         s15 ^= s0;
   389         s15 ^= s0;
   388         x[q] = Long.rotateLeft(s0, 25) ^ s15 ^ (s15 << 27);
   390         x[q] = Long.rotateLeft(s0, 25) ^ s15 ^ (s15 << 27);
   389         x[p] = Long.rotateLeft(s15, 36);
   391         x[p] = Long.rotateLeft(s15, 36);
   390 
   392 
   391         return RNGSupport.mixLea64(z);  // mixing function
   393         return RandomSupport.mixLea64(z);  // mixing function
   392     }
   394     }
   393 
   395 
   394     public BigInteger period() {
   396     public BigInteger period() {
   395         return PERIOD;
   397         return PERIOD;
   396     }
   398     }