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 } |