src/java.base/share/classes/java/util/random/L128X256MixRandom.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;
       
    32 
    30 
    33 
    31 /**
    34 /**
    32  * A generator of uniform pseudorandom values applicable for use in
    35  * A generator of uniform pseudorandom values applicable for use in
    33  * (among other contexts) isolated parallel computations that may
    36  * (among other contexts) isolated parallel computations that may
    34  * generate subtasks.  Class {@link L128X256MixRandom} implements
    37  * generate subtasks.  Class {@link L128X256MixRandom} implements
    35  * interfaces {@link RandomNumberGenerator} and {@link SplittableRNG},
    38  * interfaces {@link RandomGenerator} and {@link SplittableGenerator},
    36  * and therefore supports methods for producing pseudorandomly chosen
    39  * and therefore supports methods for producing pseudorandomly chosen
    37  * numbers of type {@code int}, {@code long}, {@code float}, and {@code double}
    40  * numbers of type {@code int}, {@code long}, {@code float}, and {@code double}
    38  * as well as creating new split-off {@link L128X256MixRandom} objects,
    41  * as well as creating new split-off {@link L128X256MixRandom} objects,
    39  * with similar usages as for class {@link java.util.SplittableRandom}.
    42  * with similar usages as for class {@link java.util.SplittableRandom}.
    40  * <p>
    43  * <p>
   141  * seed unless the {@linkplain System#getProperty system property}
   144  * seed unless the {@linkplain System#getProperty system property}
   142  * {@code java.util.secureRandomSeed} is set to {@code true}.
   145  * {@code java.util.secureRandomSeed} is set to {@code true}.
   143  *
   146  *
   144  * @since 14
   147  * @since 14
   145  */
   148  */
   146 public final class L128X256MixRandom extends AbstractSplittableRNG {
   149 public final class L128X256MixRandom extends AbstractSplittableGenerator {
   147 
   150 
   148     /*
   151     /*
   149      * Implementation Overview.
   152      * Implementation Overview.
   150      *
   153      *
   151      * The 128-bit parameter `a` is represented as two long fields `ah` and `al`.
   154      * The 128-bit parameter `a` is represented as two long fields `ah` and `al`.
   179     /* ---------------- static fields ---------------- */
   182     /* ---------------- static fields ---------------- */
   180 
   183 
   181     /**
   184     /**
   182      * The seed generator for default constructors.
   185      * The seed generator for default constructors.
   183      */
   186      */
   184     private static final AtomicLong defaultGen = new AtomicLong(RNGSupport.initialSeed());
   187     private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed());
   185 
   188 
   186     /*
   189     /*
   187      * The period of this generator, which is (2**256 - 1) * 2**128.
   190      * The period of this generator, which is (2**256 - 1) * 2**128.
   188      */
   191      */
   189     private static final BigInteger PERIOD =
   192     private static final BigInteger PERIOD =
   248         this.x2 = x2;
   251         this.x2 = x2;
   249         this.x3 = x3;
   252         this.x3 = x3;
   250         // If x0, x1, x2, and x3 are all zero, we must choose nonzero values.
   253         // If x0, x1, x2, and x3 are all zero, we must choose nonzero values.
   251         if ((x0 | x1 | x2 | x3) == 0) {
   254         if ((x0 | x1 | x2 | x3) == 0) {
   252             // At least three of the four values generated here will be nonzero.
   255             // At least three of the four values generated here will be nonzero.
   253             this.x0 = RNGSupport.mixStafford13(sh += RNGSupport.GOLDEN_RATIO_64);
   256             this.x0 = RandomSupport.mixStafford13(sh += RandomSupport.GOLDEN_RATIO_64);
   254             this.x1 = RNGSupport.mixStafford13(sh += RNGSupport.GOLDEN_RATIO_64);
   257             this.x1 = RandomSupport.mixStafford13(sh += RandomSupport.GOLDEN_RATIO_64);
   255             this.x2 = RNGSupport.mixStafford13(sh += RNGSupport.GOLDEN_RATIO_64);
   258             this.x2 = RandomSupport.mixStafford13(sh += RandomSupport.GOLDEN_RATIO_64);
   256             this.x3 = RNGSupport.mixStafford13(sh + RNGSupport.GOLDEN_RATIO_64);
   259             this.x3 = RandomSupport.mixStafford13(sh + RandomSupport.GOLDEN_RATIO_64);
   257         }
   260         }
   258     }
   261     }
   259 
   262 
   260     /**
   263     /**
   261      * Creates a new instance of {@link L128X256MixRandom} using the
   264      * Creates a new instance of {@link L128X256MixRandom} using the
   273         // The seed is hashed by mixMurmur64 to produce the `a` parameter.
   276         // The seed is hashed by mixMurmur64 to produce the `a` parameter.
   274         // The seed is hashed by mixStafford13 to produce the initial `x0`,
   277         // The seed is hashed by mixStafford13 to produce the initial `x0`,
   275         // which will then be used to produce the first generated value.
   278         // which will then be used to produce the first generated value.
   276         // The other x values are filled in as if by a SplitMix PRNG with
   279         // The other x values are filled in as if by a SplitMix PRNG with
   277         // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
   280         // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer.
   278         this(RNGSupport.mixMurmur64(seed ^= RNGSupport.SILVER_RATIO_64),
   281         this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64),
   279              RNGSupport.mixMurmur64(seed += RNGSupport.GOLDEN_RATIO_64),
   282              RandomSupport.mixMurmur64(seed += RandomSupport.GOLDEN_RATIO_64),
   280              0,
   283              0,
   281              1,
   284              1,
   282              RNGSupport.mixStafford13(seed),
   285              RandomSupport.mixStafford13(seed),
   283              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   286              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   284              RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64),
   287              RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64),
   285              RNGSupport.mixStafford13(seed + RNGSupport.GOLDEN_RATIO_64));
   288              RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64));
   286     }
   289     }
   287 
   290 
   288     /**
   291     /**
   289      * Creates a new instance of {@link L128X256MixRandom} that is likely to
   292      * Creates a new instance of {@link L128X256MixRandom} that is likely to
   290      * generate sequences of values that are statistically independent
   293      * generate sequences of values that are statistically independent
   291      * of those of any other instances in the current program execution,
   294      * of those of any other instances in the current program execution,
   292      * but may, and typically does, vary across program invocations.
   295      * but may, and typically does, vary across program invocations.
   293      */
   296      */
   294     public L128X256MixRandom() {
   297     public L128X256MixRandom() {
   295         // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
   298         // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values.
   296         this(defaultGen.getAndAdd(RNGSupport.GOLDEN_RATIO_64));
   299         this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64));
   297     }
   300     }
   298 
   301 
   299     /**
   302     /**
   300      * Creates a new instance of {@link L128X256MixRandom} using the specified array of
   303      * Creates a new instance of {@link L128X256MixRandom} using the specified array of
   301      * initial seed bytes. Instances of {@link L128X256MixRandom} created with the same
   304      * initial seed bytes. Instances of {@link L128X256MixRandom} created with the same
   303      *
   306      *
   304      * @param seed the initial seed
   307      * @param seed the initial seed
   305      */
   308      */
   306     public L128X256MixRandom(byte[] seed) {
   309     public L128X256MixRandom(byte[] seed) {
   307         // Convert the seed to 6 long values, of which the last 4 are not all zero.
   310         // Convert the seed to 6 long values, of which the last 4 are not all zero.
   308         long[] data = RNGSupport.convertSeedBytesToLongs(seed, 6, 4);
   311         long[] data = RandomSupport.convertSeedBytesToLongs(seed, 6, 4);
   309         long ah = data[0], al = data[1], sh = data[2], sl = data[3], x0 = data[4], x1 = data[5], x2 = data[6], x3 = data[7];
   312         long ah = data[0], al = data[1], sh = data[2], sl = data[3], x0 = data[4], x1 = data[5], x2 = data[6], x3 = data[7];
   310         // Force a to be odd.
   313         // Force a to be odd.
   311         this.ah = ah;
   314         this.ah = ah;
   312         this.al = al | 1;
   315         this.al = al | 1;
   313         this.sh = sh;
   316         this.sh = sh;
   329      * a single {@link L128X256MixRandom} object.  Either or both of the two
   332      * a single {@link L128X256MixRandom} object.  Either or both of the two
   330      * objects may be further split using the {@code split} method,
   333      * objects may be further split using the {@code split} method,
   331      * and the same expected statistical properties apply to the
   334      * and the same expected statistical properties apply to the
   332      * entire set of generators constructed by such recursive splitting.
   335      * entire set of generators constructed by such recursive splitting.
   333      *
   336      *
   334      * @param source a {@link SplittableRNG} instance to be used instead
   337      * @param source a {@link SplittableGenerator} instance to be used instead
   335      *               of this one as a source of pseudorandom bits used to
   338      *               of this one as a source of pseudorandom bits used to
   336      *               initialize the state of the new ones.
   339      *               initialize the state of the new ones.
   337      * @return a new instance of {@link L128X256MixRandom}
   340      * @return a new instance of {@link L128X256MixRandom}
   338      */
   341      */
   339     public L128X256MixRandom split(SplittableRNG source) {
   342     public L128X256MixRandom split(SplittableGenerator source) {
   340         // Literally pick a new instance "at random".
   343         // Literally pick a new instance "at random".
   341         return new L128X256MixRandom(source.nextLong(), source.nextLong(),
   344         return new L128X256MixRandom(source.nextLong(), source.nextLong(),
   342                                      source.nextLong(), source.nextLong(),
   345                                      source.nextLong(), source.nextLong(),
   343                                      source.nextLong(), source.nextLong(),
   346                                      source.nextLong(), source.nextLong(),
   344                                      source.nextLong(), source.nextLong());
   347                                      source.nextLong(), source.nextLong());
   357         sl = u + al;
   360         sl = u + al;
   358         if (Long.compareUnsigned(sl, u) < 0) ++sh;  // Handle the carry propagation from low half to high half.
   361         if (Long.compareUnsigned(sl, u) < 0) ++sh;  // Handle the carry propagation from low half to high half.
   359         long q0 = x0, q1 = x1, q2 = x2, q3 = x3;
   362         long q0 = x0, q1 = x1, q2 = x2, q3 = x3;
   360         { long t = q1 << 17; q2 ^= q0; q3 ^= q1; q1 ^= q2; q0 ^= q3; q2 ^= t; q3 = Long.rotateLeft(q3, 45); }  // xoshiro256 1.0
   363         { long t = q1 << 17; q2 ^= q0; q3 ^= q1; q1 ^= q2; q0 ^= q3; q2 ^= t; q3 = Long.rotateLeft(q3, 45); }  // xoshiro256 1.0
   361         x0 = q0; x1 = q1; x2 = q2; x3 = q3;
   364         x0 = q0; x1 = q1; x2 = q2; x3 = q3;
   362         return RNGSupport.mixLea64(z);  // mixing function
   365         return RandomSupport.mixLea64(z);  // mixing function
   363     }
   366     }
   364 
   367 
   365     public BigInteger period() {
   368     public BigInteger period() {
   366         return PERIOD;
   369         return PERIOD;
   367     }
   370     }