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.LeapableGenerator; |
30 |
31 |
31 /** |
32 /** |
32 * A generator of uniform pseudorandom values applicable for use in |
33 * A generator of uniform pseudorandom values applicable for use in |
33 * (among other contexts) isolated parallel computations that may |
34 * (among other contexts) isolated parallel computations that may |
34 * generate subtasks. Class {@link Xoshiro256StarStar} implements |
35 * generate subtasks. Class {@link Xoshiro256StarStar} implements |
35 * interfaces {@link RandomNumberGenerator} and {@link LeapableRNG}, |
36 * interfaces {@link RandomGenerator} and {@link LeapableGenerator}, |
36 * and therefore supports methods for producing pseudorandomly chosen |
37 * and therefore supports methods for producing pseudorandomly chosen |
37 * numbers of type {@code int}, {@code long}, {@code float}, and {@code double} |
38 * numbers of type {@code int}, {@code long}, {@code float}, and {@code double} |
38 * as well as creating new {@link Xoshiro256StarStar} objects |
39 * as well as creating new {@link Xoshiro256StarStar} objects |
39 * by "jumping" or "leaping". |
40 * by "jumping" or "leaping". |
40 * <p> |
41 * <p> |
87 * seed unless the {@linkplain System#getProperty system property} |
88 * seed unless the {@linkplain System#getProperty system property} |
88 * {@code java.util.secureRandomSeed} is set to {@code true}. |
89 * {@code java.util.secureRandomSeed} is set to {@code true}. |
89 * |
90 * |
90 * @since 14 |
91 * @since 14 |
91 */ |
92 */ |
92 public final class Xoshiro256StarStar implements LeapableRNG { |
93 public final class Xoshiro256StarStar implements LeapableGenerator { |
93 |
94 |
94 /* |
95 /* |
95 * Implementation Overview. |
96 * Implementation Overview. |
96 * |
97 * |
97 * This is an implementation of the xoroshiro128** algorithm written |
98 * This is an implementation of the xoroshiro128** algorithm written |
126 /* ---------------- static fields ---------------- */ |
127 /* ---------------- static fields ---------------- */ |
127 |
128 |
128 /** |
129 /** |
129 * The seed generator for default constructors. |
130 * The seed generator for default constructors. |
130 */ |
131 */ |
131 private static final AtomicLong DEFAULT_GEN = new AtomicLong(RNGSupport.initialSeed()); |
132 private static final AtomicLong DEFAULT_GEN = new AtomicLong(RandomSupport.initialSeed()); |
132 |
133 |
133 /* |
134 /* |
134 * The period of this generator, which is 2**256 - 1. |
135 * The period of this generator, which is 2**256 - 1. |
135 */ |
136 */ |
136 private static final BigInteger PERIOD = |
137 private static final BigInteger PERIOD = |
162 this.x2 = x2; |
163 this.x2 = x2; |
163 this.x3 = x3; |
164 this.x3 = x3; |
164 // If x0, x1, x2, and x3 are all zero, we must choose nonzero values. |
165 // If x0, x1, x2, and x3 are all zero, we must choose nonzero values. |
165 if ((x0 | x1 | x2 | x3) == 0) { |
166 if ((x0 | x1 | x2 | x3) == 0) { |
166 // At least three of the four values generated here will be nonzero. |
167 // At least three of the four values generated here will be nonzero. |
167 this.x0 = RNGSupport.mixStafford13(x0 += RNGSupport.GOLDEN_RATIO_64); |
168 this.x0 = RandomSupport.mixStafford13(x0 += RandomSupport.GOLDEN_RATIO_64); |
168 this.x1 = (x0 += RNGSupport.GOLDEN_RATIO_64); |
169 this.x1 = (x0 += RandomSupport.GOLDEN_RATIO_64); |
169 this.x2 = (x0 += RNGSupport.GOLDEN_RATIO_64); |
170 this.x2 = (x0 += RandomSupport.GOLDEN_RATIO_64); |
170 this.x3 = (x0 += RNGSupport.GOLDEN_RATIO_64); |
171 this.x3 = (x0 += RandomSupport.GOLDEN_RATIO_64); |
171 } |
172 } |
172 } |
173 } |
173 |
174 |
174 /** |
175 /** |
175 * Creates a new instance of {@link Xoshiro256StarStar} using the |
176 * Creates a new instance of {@link Xoshiro256StarStar} using the |
184 // argument tends to improve "pedestrian" seeds such as 0 or |
185 // argument tends to improve "pedestrian" seeds such as 0 or |
185 // other small integers. We may as well use SILVER_RATIO_64. |
186 // other small integers. We may as well use SILVER_RATIO_64. |
186 // |
187 // |
187 // The x values are then filled in as if by a SplitMix PRNG with |
188 // The x values are then filled in as if by a SplitMix PRNG with |
188 // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer. |
189 // GOLDEN_RATIO_64 as the gamma value and Stafford13 as the mixer. |
189 this(RNGSupport.mixStafford13(seed ^= RNGSupport.SILVER_RATIO_64), |
190 this(RandomSupport.mixStafford13(seed ^= RandomSupport.SILVER_RATIO_64), |
190 RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64), |
191 RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64), |
191 RNGSupport.mixStafford13(seed += RNGSupport.GOLDEN_RATIO_64), |
192 RandomSupport.mixStafford13(seed += RandomSupport.GOLDEN_RATIO_64), |
192 RNGSupport.mixStafford13(seed + RNGSupport.GOLDEN_RATIO_64)); |
193 RandomSupport.mixStafford13(seed + RandomSupport.GOLDEN_RATIO_64)); |
193 } |
194 } |
194 |
195 |
195 /** |
196 /** |
196 * Creates a new instance of {@link Xoshiro256StarStar} that is likely to |
197 * Creates a new instance of {@link Xoshiro256StarStar} that is likely to |
197 * generate sequences of values that are statistically independent |
198 * generate sequences of values that are statistically independent |
198 * of those of any other instances in the current program execution, |
199 * of those of any other instances in the current program execution, |
199 * but may, and typically does, vary across program invocations. |
200 * but may, and typically does, vary across program invocations. |
200 */ |
201 */ |
201 public Xoshiro256StarStar() { |
202 public Xoshiro256StarStar() { |
202 // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values. |
203 // Using GOLDEN_RATIO_64 here gives us a good Weyl sequence of values. |
203 this(DEFAULT_GEN.getAndAdd(RNGSupport.GOLDEN_RATIO_64)); |
204 this(DEFAULT_GEN.getAndAdd(RandomSupport.GOLDEN_RATIO_64)); |
204 } |
205 } |
205 |
206 |
206 /** |
207 /** |
207 * Creates a new instance of {@link Xoshiro256StarStar} using the specified array of |
208 * Creates a new instance of {@link Xoshiro256StarStar} using the specified array of |
208 * initial seed bytes. Instances of {@link Xoshiro256StarStar} created with the same |
209 * initial seed bytes. Instances of {@link Xoshiro256StarStar} created with the same |
210 * |
211 * |
211 * @param seed the initial seed |
212 * @param seed the initial seed |
212 */ |
213 */ |
213 public Xoshiro256StarStar(byte[] seed) { |
214 public Xoshiro256StarStar(byte[] seed) { |
214 // Convert the seed to 4 long values, which are not all zero. |
215 // Convert the seed to 4 long values, which are not all zero. |
215 long[] data = RNGSupport.convertSeedBytesToLongs(seed, 4, 4); |
216 long[] data = RandomSupport.convertSeedBytesToLongs(seed, 4, 4); |
216 long x0 = data[0], x1 = data[1], x2 = data[2], x3 = data[3]; |
217 long x0 = data[0], x1 = data[1], x2 = data[2], x3 = data[3]; |
217 this.x0 = x0; |
218 this.x0 = x0; |
218 this.x1 = x1; |
219 this.x1 = x1; |
219 this.x2 = x2; |
220 this.x2 = x2; |
220 this.x3 = x3; |
221 this.x3 = x3; |