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