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 L64X256Random} implements |
36 * generate subtasks. Class {@link L64X256Random} 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 L64X256Random} objects, |
40 * as well as creating new split-off {@link L64X256Random} 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> |
130 * seed unless the {@linkplain System#getProperty system property} |
132 * seed unless the {@linkplain System#getProperty system property} |
131 * {@code java.util.secureRandomSeed} is set to {@code true}. |
133 * {@code java.util.secureRandomSeed} is set to {@code true}. |
132 * |
134 * |
133 * @since 14 |
135 * @since 14 |
134 */ |
136 */ |
135 public final class L64X256Random extends AbstractSplittableRNG { |
137 public final class L64X256Random extends AbstractSplittableGenerator { |
136 |
138 |
137 /* |
139 /* |
138 * Implementation Overview. |
140 * Implementation Overview. |
139 * |
141 * |
140 * The split() operation uses the current generator to choose six new 64-bit |
142 * The split() operation uses the current generator to choose six new 64-bit |
165 /* ---------------- static fields ---------------- */ |
167 /* ---------------- static fields ---------------- */ |
166 |
168 |
167 /** |
169 /** |
168 * The seed generator for default constructors. |
170 * The seed generator for default constructors. |
169 */ |
171 */ |
170 private static final AtomicLong defaultGen = new AtomicLong(RNGSupport.initialSeed()); |
172 private static final AtomicLong defaultGen = new AtomicLong(RandomSupport.initialSeed()); |
171 |
173 |
172 /* |
174 /* |
173 * The period of this generator, which is (2**256 - 1) * 2**64. |
175 * The period of this generator, which is (2**256 - 1) * 2**64. |
174 */ |
176 */ |
175 private static final BigInteger PERIOD = |
177 private static final BigInteger PERIOD = |
222 this.x2 = x2; |
224 this.x2 = x2; |
223 this.x3 = x3; |
225 this.x3 = x3; |
224 // If x0, x1, x2, and x3 are all zero, we must choose nonzero values. |
226 // If x0, x1, x2, and x3 are all zero, we must choose nonzero values. |
225 if ((x0 | x1 | x2 | x3) == 0) { |
227 if ((x0 | x1 | x2 | x3) == 0) { |
226 // At least three of the four values generated here will be nonzero. |
228 // At least three of the four values generated here will be nonzero. |
227 this.x0 = RNGSupport.mixStafford13(s += RNGSupport.GOLDEN_RATIO_64); |
229 this.x0 = RandomSupport.mixStafford13(s += RandomSupport.GOLDEN_RATIO_64); |
228 this.x1 = RNGSupport.mixStafford13(s += RNGSupport.GOLDEN_RATIO_64); |
230 this.x1 = RandomSupport.mixStafford13(s += RandomSupport.GOLDEN_RATIO_64); |
229 this.x2 = RNGSupport.mixStafford13(s += RNGSupport.GOLDEN_RATIO_64); |
231 this.x2 = RandomSupport.mixStafford13(s += RandomSupport.GOLDEN_RATIO_64); |
230 this.x3 = RNGSupport.mixStafford13(s + RNGSupport.GOLDEN_RATIO_64); |
232 this.x3 = RandomSupport.mixStafford13(s + RandomSupport.GOLDEN_RATIO_64); |
231 } |
233 } |
232 } |
234 } |
233 |
235 |
234 /** |
236 /** |
235 * Creates a new instance of {@link L64X256Random} using the |
237 * Creates a new instance of {@link L64X256Random} using the |
247 // The seed is hashed by mixMurmur64 to produce the `a` parameter. |
249 // The seed is hashed by mixMurmur64 to produce the `a` parameter. |
248 // The seed is hashed by mixStafford13 to produce the initial `x0`, |
250 // The seed is hashed by mixStafford13 to produce the initial `x0`, |
249 // which will then be used to produce the first generated value. |
251 // which will then be used to produce the first generated value. |
250 // The other x values are filled in as if by a SplitMix PRNG with |
252 // The other x values are filled in as if by a SplitMix PRNG with |
251 // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer. |
253 // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer. |
252 this(RNGSupport.mixMurmur64(seed ^= RNGSupport.SILVER_RATIO_64), |
254 this(RandomSupport.mixMurmur64(seed ^= RandomSupport.SILVER_RATIO_64), |
253 1, |
255 1, |
254 RNGSupport.mixStafford13(seed), |
256 RandomSupport.mixStafford13(seed), |
255 RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64), |
257 RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64), |
256 RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64), |
258 RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64), |
257 RNGSupport.mixStafford13(seed + RNGSupport.GOLDEN_RATIO_64)); |
259 RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64)); |
258 } |
260 } |
259 |
261 |
260 /** |
262 /** |
261 * Creates a new instance of {@link L64X256Random} that is likely to |
263 * Creates a new instance of {@link L64X256Random} that is likely to |
262 * generate sequences of values that are statistically independent |
264 * generate sequences of values that are statistically independent |
263 * of those of any other instances in the current program execution, |
265 * of those of any other instances in the current program execution, |
264 * but may, and typically does, vary across program invocations. |
266 * but may, and typically does, vary across program invocations. |
265 */ |
267 */ |
266 public L64X256Random() { |
268 public L64X256Random() { |
267 // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values. |
269 // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values. |
268 this(defaultGen.getAndAdd(RNGSupport.GOLDEN_RATIO_64)); |
270 this(defaultGen.getAndAdd(RandomSupport.GOLDEN_RATIO_64)); |
269 } |
271 } |
270 |
272 |
271 /** |
273 /** |
272 * Creates a new instance of {@link L64X256Random} using the specified array of |
274 * Creates a new instance of {@link L64X256Random} using the specified array of |
273 * initial seed bytes. Instances of {@link L64X256Random} created with the same |
275 * initial seed bytes. Instances of {@link L64X256Random} created with the same |
275 * |
277 * |
276 * @param seed the initial seed |
278 * @param seed the initial seed |
277 */ |
279 */ |
278 public L64X256Random(byte[] seed) { |
280 public L64X256Random(byte[] seed) { |
279 // Convert the seed to 6 long values, of which the last 4 are not all zero. |
281 // Convert the seed to 6 long values, of which the last 4 are not all zero. |
280 long[] data = RNGSupport.convertSeedBytesToLongs(seed, 6, 4); |
282 long[] data = RandomSupport.convertSeedBytesToLongs(seed, 6, 4); |
281 long a = data[0], s = data[1], x0 = data[2], x1 = data[3], x2 = data[4], x3 = data[5]; |
283 long a = data[0], s = data[1], x0 = data[2], x1 = data[3], x2 = data[4], x3 = data[5]; |
282 // Force a to be odd. |
284 // Force a to be odd. |
283 this.a = a | 1; |
285 this.a = a | 1; |
284 this.s = s; |
286 this.s = s; |
285 this.x0 = x0; |
287 this.x0 = x0; |
299 * a single {@link L64X256Random} object. Either or both of the two |
301 * a single {@link L64X256Random} object. Either or both of the two |
300 * objects may be further split using the {@code split} method, |
302 * objects may be further split using the {@code split} method, |
301 * and the same expected statistical properties apply to the |
303 * and the same expected statistical properties apply to the |
302 * entire set of generators constructed by such recursive splitting. |
304 * entire set of generators constructed by such recursive splitting. |
303 * |
305 * |
304 * @param source a {@link SplittableRNG} instance to be used instead |
306 * @param source a {@link SplittableGenerator} instance to be used instead |
305 * of this one as a source of pseudorandom bits used to |
307 * of this one as a source of pseudorandom bits used to |
306 * initialize the state of the new ones. |
308 * initialize the state of the new ones. |
307 * |
309 * |
308 * @return a new instance of {@link L64X256Random} |
310 * @return a new instance of {@link L64X256Random} |
309 */ |
311 */ |
310 public L64X256Random split(SplittableRNG source) { |
312 public L64X256Random split(SplittableGenerator source) { |
311 // Literally pick a new instance "at random". |
313 // Literally pick a new instance "at random". |
312 return new L64X256Random(source.nextLong(), source.nextLong(), |
314 return new L64X256Random(source.nextLong(), source.nextLong(), |
313 source.nextLong(), source.nextLong(), |
315 source.nextLong(), source.nextLong(), |
314 source.nextLong(), source.nextLong()); |
316 source.nextLong(), source.nextLong()); |
315 } |
317 } |