ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/SplittableRandom.java
Revision: 1.1
Committed: Wed Jul 10 15:40:19 2013 UTC (10 years, 9 months ago) by dl
Branch: MAIN
Log Message:
Initial version

File Contents

# Content
1 /*
2 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.util;
27
28 import java.util.concurrent.atomic.AtomicLong;
29 import java.util.Spliterator;
30 import java.util.function.IntConsumer;
31 import java.util.function.LongConsumer;
32 import java.util.function.DoubleConsumer;
33 import java.util.stream.StreamSupport;
34 import java.util.stream.IntStream;
35 import java.util.stream.LongStream;
36 import java.util.stream.DoubleStream;
37
38
39 /**
40 * A generator of uniform pseudorandom values applicable for use in
41 * (among other contexts) isolated parallel computations that may
42 * generate subtasks. Class SplittableRandom supports methods for
43 * producing pseudorandom nunmbers of type {@code int}, {@code long},
44 * and {@code double} with similar usages as for class
45 * {@link java.util.Random} but differs in the following ways: <ul>
46 *
47 * <li>Series of generated values pass the DieHarder suite testing
48 * independence and uniformity properties of random number generators.
49 * (Most recently validated with <a
50 * href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> version
51 * 3.31.1</a>.) These tests validate only the methods for certain
52 * types and ranges, but similar properties are expected to hold, at
53 * least approximately, for others as well. </li>
54 *
55 * <li> Method {@link #split} constructs and returns a new
56 * SplittableRandom instance that shares no mutable state with the
57 * current instance. However, with very high probability, the set of
58 * values collectively generated by the two objects has the same
59 * statistical properties as if the same quantity of values were
60 * generated by a single thread using a single {@code
61 * SplittableRandom} object. </li>
62 *
63 * <li>Instances of SplittableRandom are <em>not</em> thread-safe.
64 * They are designed to be split, not shared, across threads. For
65 * example, a {@link java.util.concurrent.ForkJoinTask
66 * fork/join-style} computation using random numbers might include a
67 * construction of the form {@code new
68 * Subtask(aSplittableRandom.split()).fork()}.
69 *
70 * <li>This class provides additional methods for generating random
71 * streams, that employ the above techniques when used in {@code
72 * stream.parallel()} mode.</li>
73 *
74 * </ul>
75 *
76 * @author Guy Steele
77 * @since 1.8
78 */
79 public class SplittableRandom {
80
81 /*
82 * File organization: First the non-public methods that constitute
83 * the main algorithm, then the main public methods, followed by
84 * some custom spliterator classes needed for stream methods.
85 *
86 * Credits: Primary algorithm and code by Guy Steele. Stream
87 * support methods by Doug Lea. Documentation jointly produced
88 * with additional help from Brian Goetz.
89 */
90
91 /*
92 * Implementation Overview.
93 *
94 * This algorithm was inspired by the "DotMix" algorithm by
95 * Leiserson, Schardl, and Sukha "Deterministic Parallel
96 * Random-Number Generation for Dynamic-Multithreading Platforms",
97 * PPoPP 2012, but improves and extends it in several ways.
98 *
99 * The primary update step is simply to add a constant ("gamma")
100 * to the current seed, modulo a prime ("George"). However, the
101 * nextLong and nextInt methods do not return this value, but
102 * instead the results of bit-mixing transformations that produce
103 * more uniformly distributed sequences.
104 *
105 * "George" is the otherwise nameless (because it cannot be
106 * represented) prime number 2^64+13. Using a prime number larger
107 * than can fit in a long ensures that all possible long values
108 * can occur, plus 13 others that just get skipped over when they
109 * are encountered; see method addGammaModGeorge. For this to
110 * work, initial gamma values must be at least 13.
111 *
112 * The value of gamma differs for each instance across a series of
113 * splits, and is generated using a slightly stripped-down variant
114 * of the same algorithm, but operating across calls to split(),
115 * not calls to nextLong(): Each instance carries the state of
116 * this generator as nextSplit, and uses mix64(nextSplit) as its
117 * own gamma value. Computations of gammas themselves use a fixed
118 * constant as the second argument to the addGammaModGeorge
119 * function, GAMMA_GAMMA, a "genuinely random" number from a
120 * radioactive decay reading (obtained from
121 * http://www.fourmilab.ch/hotbits/) meeting the above range
122 * constraint. Using a fixed constant maintains the invariant that
123 * the value of gamma is the same for every instance that is at
124 * the same split-distance from their common root. (Note: there is
125 * nothing especially magic about obtaining this constant from a
126 * "truly random" physical source rather than just choosing one
127 * arbitrarily; using "hotbits" was merely an aesthetically pleasing
128 * choice. In either case, good statistical behavior of the
129 * algorithm should be, and was, verified by using the DieHarder
130 * test suite.)
131 *
132 * The mix64 bit-mixing function called by nextLong and other
133 * methods computes the same value as the "64-bit finalizer"
134 * function in Austin Appleby's MurmurHash3 algorithm. See
135 * http://code.google.com/p/smhasher/wiki/MurmurHash3 , which
136 * comments: "The constants for the finalizers were generated by a
137 * simple simulated-annealing algorithm, and both avalanche all
138 * bits of 'h' to within 0.25% bias." It also appears to work to
139 * use instead any of the variants proposed by David Stafford at
140 * http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
141 * but these variants have not yet been tested as thoroughly
142 * in the context of the implementation of SplittableRandom.
143 *
144 * The mix32 function used for nextInt just consists of two of the
145 * five lines of mix64; avalanche testing shows that the 64-bit result
146 * has its top 32 bits avalanched well, though not the bottom 32 bits.
147 * DieHarder tests show that it is adequate for generating one
148 * random int from the 64-bit result of nextSeed.
149 *
150 * Support for the default (no-argument) constructor relies on an
151 * AtomicLong (defaultSeedGenerator) to help perform the
152 * equivalent of a split of a statically constructed
153 * SplittableRandom. Unlike other cases, this split must be
154 * performed in a thread-safe manner. We use
155 * AtomicLong.compareAndSet as the (typically) most efficient
156 * mechanism. To bootstrap, we start off using System.nanotime(),
157 * and update using another "genuinely random" constant
158 * DEFAULT_SEED_GAMMA. The default constructor uses GAMMA_GAMMA,
159 * not 0, for its splitSeed argument (addGammaModGeorge(0,
160 * GAMMA_GAMMA) == GAMMA_GAMMA) to reflect that each is split from
161 * this root generator, even though the root is not explicitly
162 * represented as a SplittableRandom.
163 */
164
165 /**
166 * The "genuinely random" value for producing new gamma values.
167 * The value is arbitrary, subject to the requirement that it be
168 * greater or equal to 13.
169 */
170 private static final long GAMMA_GAMMA = 0xF2281E2DBA6606F3L;
171
172 /**
173 * The "genuinely random" seed update value for default constructors.
174 * The value is arbitrary, subject to the requirement that it be
175 * greater or equal to 13.
176 */
177 private static final long DEFAULT_SEED_GAMMA = 0xBD24B73A95FB84D9L;
178
179 /**
180 * The next seed for default constructors.
181 */
182 private static final AtomicLong defaultSeedGenerator =
183 new AtomicLong(System.nanoTime());
184
185 /**
186 * The seed, updated only via method nextSeed.
187 */
188 private long seed;
189
190 /**
191 * The constant value added to seed (mod George) on each update.
192 */
193 private final long gamma;
194
195 /**
196 * The next seed to use for splits. Propagated using
197 * addGammaModGeorge across instances.
198 */
199 private final long nextSplit;
200
201 /**
202 * Internal constructor used by all other constructors and by
203 * method split. Establishes the initial seed for this instance,
204 * and uses the given splitSeed to establish gamma, as well as the
205 * nextSplit to use by this instance.
206 */
207 private SplittableRandom(long seed, long splitSeed) {
208 this.seed = seed;
209 long s = splitSeed, g;
210 do { // ensure gamma >= 13, considered as an unsigned integer
211 s = addGammaModGeorge(s, GAMMA_GAMMA);
212 g = mix64(s);
213 } while (Long.compareUnsigned(g, 13L) < 0);
214 this.gamma = g;
215 this.nextSplit = s;
216 }
217
218 /**
219 * Adds the given gamma value, g, to the given seed value s, mod
220 * George (2^64+13). We regard s and g as unsigned values
221 * (ranging from 0 to 2^64-1). We add g to s either once or twice
222 * (mod George) as necessary to produce an (unsigned) result less
223 * than 2^64. We require that g must be at least 13. This
224 * guarantees that if (s+g) mod George >= 2^64 then (s+g+g) mod
225 * George < 2^64; thus we need only a conditional, not a loop,
226 * to be sure of getting a representable value.
227 *
228 * @param s a seed value
229 * @param g a gamma value, 13 <= g (as unsigned)
230 */
231 private static long addGammaModGeorge(long s, long g) {
232 long p = s + g;
233 if (Long.compareUnsigned(p, g) >= 0)
234 return p;
235 long q = p - 13L;
236 return (Long.compareUnsigned(p, 13L) >= 0) ? q : (q + g);
237 }
238
239 /**
240 * Updates in-place and returns seed.
241 * See above for explanation.
242 */
243 private long nextSeed() {
244 return seed = addGammaModGeorge(seed, gamma);
245 }
246
247 /**
248 * Returns a bit-mixed transformation of its argument.
249 * See above for explanation.
250 */
251 private static long mix64(long z) {
252 z ^= (z >>> 33);
253 z *= 0xff51afd7ed558ccdL;
254 z ^= (z >>> 33);
255 z *= 0xc4ceb9fe1a85ec53L;
256 z ^= (z >>> 33);
257 return z;
258 }
259
260 /**
261 * Returns a bit-mixed int transformation of its argument.
262 * See above for explanation.
263 */
264 private static int mix32(long z) {
265 z ^= (z >>> 33);
266 z *= 0xc4ceb9fe1a85ec53L;
267 return (int)(z >>> 32);
268 }
269
270 /**
271 * Atomically updates and returns next seed for default constructor
272 */
273 private static long nextDefaultSeed() {
274 long oldSeed, newSeed;
275 do {
276 oldSeed = defaultSeedGenerator.get();
277 newSeed = addGammaModGeorge(oldSeed, DEFAULT_SEED_GAMMA);
278 } while (!defaultSeedGenerator.compareAndSet(oldSeed, newSeed));
279 return mix64(newSeed);
280 }
281
282 /*
283 * Internal versions of nextX methods used by streams, as well as
284 * the public nextX(origin, bound) methods. These exist mainly to
285 * avoid the need for multiple versions of stream spliterators
286 * across the different exported forms of streams.
287 */
288
289 /**
290 * The form of nextLong used by LongStream Spliterators. If
291 * origin is greater than bound, acts as unbounded form of
292 * nextLong, else as bounded form.
293 *
294 * @param origin the least value, unless greater than bound
295 * @param bound the upper bound (exclusive), must not equal origin
296 * @return a pseudorandom value
297 */
298 final long internalNextLong(long origin, long bound) {
299 /*
300 * Four Cases:
301 *
302 * 1. If the arguments indicate unbounded form, act as
303 * nextLong().
304 *
305 * 2. If the range is an exact power of two, apply the
306 * associated bit mask.
307 *
308 * 3. If the range is positive, loop to avoid potential bias
309 * when the implicit nextLong() bound (2<sup>64</sup>) is not
310 * evenly divisible by the range. The loop rejects candidates
311 * computed from otherwise over-represented values. The
312 * expected number of iterations under an ideal generator
313 * varies from 1 to 2, depending on the bound.
314 *
315 * 4. Otherwise, the range cannot be represented as a positive
316 * long. Repeatedly generate unbounded longs until obtaining
317 * a candidate meeting constraints (with an expected number of
318 * iterations of less than two).
319 */
320
321 long r = mix64(nextSeed());
322 if (origin < bound) {
323 long n = bound - origin, m = n - 1;
324 if ((n & m) == 0L) // power of two
325 r = (r & m) + origin;
326 else if (n > 0) { // reject over-represented candidates
327 for (long u = r >>> 1; // ensure nonnegative
328 u + m - (r = u % n) < 0L; // reject
329 u = mix64(nextSeed()) >>> 1) // retry
330 ;
331 r += origin;
332 }
333 else { // range not representable as long
334 while (r < origin || r >= bound)
335 r = mix64(nextSeed());
336 }
337 }
338 return r;
339 }
340
341 /**
342 * The form of nextInt used by IntStream Spliterators.
343 * Exactly the same as long version, except for types.
344 *
345 * @param origin the least value, unless greater than bound
346 * @param bound the upper bound (exclusive), must not equal origin
347 * @return a pseudorandom value
348 */
349 final int internalNextInt(int origin, int bound) {
350 int r = mix32(nextSeed());
351 if (origin < bound) {
352 int n = bound - origin, m = n - 1;
353 if ((n & m) == 0L)
354 r = (r & m) + origin;
355 else if (n > 0) {
356 for (int u = r >>> 1;
357 u + m - (r = u % n) < 0L;
358 u = mix32(nextSeed()) >>> 1)
359 ;
360 r += origin;
361 }
362 else {
363 while (r < origin || r >= bound)
364 r = mix32(nextSeed());
365 }
366 }
367 return r;
368 }
369
370 /**
371 * The form of nextDouble used by DoubleStream Spliterators.
372 *
373 * @param origin the least value, unless greater than bound
374 * @param bound the upper bound (exclusive), must not equal origin
375 * @return a pseudorandom value
376 */
377 final double internalNextDouble(double origin, double bound) {
378 long bits = (1023L << 52) | (nextLong() >>> 12);
379 double r = Double.longBitsToDouble(bits) - 1.0;
380 if (origin < bound) {
381 r = r * (bound - origin) + origin;
382 if (r == bound) // correct for rounding
383 r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
384 }
385 return r;
386 }
387
388 /* ---------------- public methods ---------------- */
389
390 /**
391 * Creates a new SplittableRandom instance using the given initial
392 * seed. Two SplittableRandom instances created with the same seed
393 * generate identical sequences of values.
394 *
395 * @param seed the initial seed
396 */
397 public SplittableRandom(long seed) {
398 this(seed, 0);
399 }
400
401 /**
402 * Creates a new SplittableRandom instance that is likely to
403 * generate sequences of values that are statistically independent
404 * of those of any other instances in the current program; and
405 * may, and typically does, vary across program invocations.
406 */
407 public SplittableRandom() {
408 this(nextDefaultSeed(), GAMMA_GAMMA);
409 }
410
411 /**
412 * Constructs and returns a new SplittableRandom instance that
413 * shares no mutable state with this instance. However, with very
414 * high probability, the set of values collectively generated by
415 * the two objects has the same statistical properties as if the
416 * same quantity of values were generated by a single thread using
417 * a single SplittableRandom object. Either or both of the two
418 * objects may be further split using the {@code split()} method,
419 * and the same expected statistical properties apply to the
420 * entire set of generators constructed by such recursive
421 * splitting.
422 *
423 * @return the new SplittableRandom instance
424 */
425 public SplittableRandom split() {
426 return new SplittableRandom(nextSeed(), nextSplit);
427 }
428
429 /**
430 * Returns a pseudorandom {@code int} value.
431 *
432 * @return a pseudorandom value
433 */
434 public int nextInt() {
435 return mix32(nextSeed());
436 }
437
438 /**
439 * Returns a pseudorandom {@code int} value between 0 (inclusive)
440 * and the specified bound (exclusive).
441 *
442 * @param bound the bound on the random number to be returned. Must be
443 * positive.
444 * @return a pseudorandom {@code int} value between {@code 0}
445 * (inclusive) and the bound (exclusive).
446 * @exception IllegalArgumentException if the bound is not positive
447 */
448 public int nextInt(int bound) {
449 if (bound <= 0)
450 throw new IllegalArgumentException("bound must be positive");
451 // Specialize internalNextInt for origin 0
452 int r = mix32(nextSeed());
453 int m = bound - 1;
454 if ((bound & m) == 0L) // power of two
455 r &= m;
456 else { // reject over-represented candidates
457 for (int u = r >>> 1;
458 u + m - (r = u % bound) < 0L;
459 u = mix32(nextSeed()) >>> 1)
460 ;
461 }
462 return r;
463 }
464
465 /**
466 * Returns a pseudorandom {@code int} value between the specified
467 * origin (inclusive) and the specified bound (exclusive).
468 *
469 * @param origin the least value returned
470 * @param bound the upper bound (exclusive)
471 * @return a pseudorandom {@code int} value between the origin
472 * (inclusive) and the bound (exclusive).
473 * @exception IllegalArgumentException if {@code origin} is greater than
474 * or equal to {@code bound}
475 */
476 public int nextInt(int origin, int bound) {
477 if (origin >= bound)
478 throw new IllegalArgumentException("bound must be greater than origin");
479 return internalNextInt(origin, bound);
480 }
481
482 /**
483 * Returns a pseudorandom {@code long} value.
484 *
485 * @return a pseudorandom value
486 */
487 public long nextLong() {
488 return mix64(nextSeed());
489 }
490
491 /**
492 * Returns a pseudorandom {@code long} value between 0 (inclusive)
493 * and the specified bound (exclusive).
494 *
495 * @param bound the bound on the random number to be returned. Must be
496 * positive.
497 * @return a pseudorandom {@code long} value between {@code 0}
498 * (inclusive) and the bound (exclusive).
499 * @exception IllegalArgumentException if the bound is not positive
500 */
501 public long nextLong(long bound) {
502 if (bound <= 0)
503 throw new IllegalArgumentException("bound must be positive");
504 // Specialize internalNextLong for origin 0
505 long r = mix64(nextSeed());
506 long m = bound - 1;
507 if ((bound & m) == 0L) // power of two
508 r &= m;
509 else { // reject over-represented candidates
510 for (long u = r >>> 1;
511 u + m - (r = u % bound) < 0L;
512 u = mix64(nextSeed()) >>> 1)
513 ;
514 }
515 return r;
516 }
517
518 /**
519 * Returns a pseudorandom {@code long} value between the specified
520 * origin (inclusive) and the specified bound (exclusive).
521 *
522 * @param origin the least value returned
523 * @param bound the upper bound (exclusive)
524 * @return a pseudorandom {@code long} value between the origin
525 * (inclusive) and the bound (exclusive).
526 * @exception IllegalArgumentException if {@code origin} is greater than
527 * or equal to {@code bound}
528 */
529 public long nextLong(long origin, long bound) {
530 if (origin >= bound)
531 throw new IllegalArgumentException("bound must be greater than origin");
532 return internalNextLong(origin, bound);
533 }
534
535 /**
536 * Returns a pseudorandom {@code double} value between {@code 0.0}
537 * (inclusive) and {@code 1.0} (exclusive).
538 *
539 * @return a pseudorandom value between {@code 0.0}
540 * (inclusive) and {@code 1.0} (exclusive)
541 */
542 public double nextDouble() {
543 long bits = (1023L << 52) | (nextLong() >>> 12);
544 return Double.longBitsToDouble(bits) - 1.0;
545 }
546
547 /**
548 * Returns a pseudorandom {@code double} value between 0.0
549 * (inclusive) and the specified bound (exclusive).
550 *
551 * @param bound the bound on the random number to be returned. Must be
552 * positive.
553 * @return a pseudorandom {@code double} value between {@code 0.0}
554 * (inclusive) and the bound (exclusive).
555 * @throws IllegalArgumentException if {@code bound} is not positive
556 */
557 public double nextDouble(double bound) {
558 if (bound <= 0.0)
559 throw new IllegalArgumentException("bound must be positive");
560 double result = nextDouble() * bound;
561 return (result < bound) ? result : // correct for rounding
562 Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
563 }
564
565 /**
566 * Returns a pseudorandom {@code double} value between the given
567 * origin (inclusive) and bound (exclusive).
568 *
569 * @param origin the least value returned
570 * @param bound the upper bound
571 * @return a pseudorandom {@code double} value between the origin
572 * (inclusive) and the bound (exclusive).
573 * @throws IllegalArgumentException if {@code origin} is greater than
574 * or equal to {@code bound}
575 */
576 public double nextDouble(double origin, double bound) {
577 if (origin >= bound)
578 throw new IllegalArgumentException("bound must be greater than origin");
579 return internalNextDouble(origin, bound);
580 }
581
582 // stream methods, coded in a way intended to better isolate for
583 // maintenance purposes the small differences across forms.
584
585 /**
586 * Returns a stream with the given {@code streamSize} number of
587 * pseudorandom {@code int} values.
588 *
589 * @param streamSize the number of values to generate
590 * @return a stream of pseudorandom {@code int} values
591 * @throws IllegalArgumentException if {@code streamSize} is
592 * less than zero
593 */
594 public IntStream ints(long streamSize) {
595 if (streamSize < 0L)
596 throw new IllegalArgumentException("negative Stream size");
597 return StreamSupport.intStream
598 (new RandomIntsSpliterator
599 (this, 0L, streamSize, Integer.MAX_VALUE, 0),
600 false);
601 }
602
603 /**
604 * Returns an effectively unlimited stream of pseudorandom {@code int}
605 * values
606 *
607 * @implNote This method is implemented to be equivalent to {@code
608 * ints(Long.MAX_VALUE)}.
609 *
610 * @return a stream of pseudorandom {@code int} values
611 */
612 public IntStream ints() {
613 return StreamSupport.intStream
614 (new RandomIntsSpliterator
615 (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
616 false);
617 }
618
619 /**
620 * Returns a stream with the given {@code streamSize} number of
621 * pseudorandom {@code int} values, each conforming to the given
622 * origin and bound.
623 *
624 * @param streamSize the number of values to generate
625 * @param randomNumberOrigin the origin of each random value
626 * @param randomNumberBound the bound of each random value
627 * @return a stream of pseudorandom {@code int} values,
628 * each with the given origin and bound.
629 * @throws IllegalArgumentException if {@code streamSize} is
630 * less than zero.
631 * @throws IllegalArgumentException if {@code randomNumberOrigin}
632 * is greater than or equal to {@code randomNumberBound}
633 */
634 public IntStream ints(long streamSize, int randomNumberOrigin,
635 int randomNumberBound) {
636 if (streamSize < 0L)
637 throw new IllegalArgumentException("negative Stream size");
638 if (randomNumberOrigin >= randomNumberBound)
639 throw new IllegalArgumentException("bound must be greater than origin");
640 return StreamSupport.intStream
641 (new RandomIntsSpliterator
642 (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
643 false);
644 }
645
646 /**
647 * Returns an effectively unlimited stream of pseudorandom {@code
648 * int} values, each conforming to the given origin and bound.
649 *
650 * @implNote This method is implemented to be equivalent to {@code
651 * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
652 *
653 * @param randomNumberOrigin the origin of each random value
654 * @param randomNumberBound the bound of each random value
655 * @return a stream of pseudorandom {@code int} values,
656 * each with the given origin and bound.
657 * @throws IllegalArgumentException if {@code randomNumberOrigin}
658 * is greater than or equal to {@code randomNumberBound}
659 */
660 public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
661 if (randomNumberOrigin >= randomNumberBound)
662 throw new IllegalArgumentException("bound must be greater than origin");
663 return StreamSupport.intStream
664 (new RandomIntsSpliterator
665 (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
666 false);
667 }
668
669 /**
670 * Returns a stream with the given {@code streamSize} number of
671 * pseudorandom {@code long} values.
672 *
673 * @param streamSize the number of values to generate
674 * @return a stream of {@code long} values
675 * @throws IllegalArgumentException if {@code streamSize} is
676 * less than zero
677 */
678 public LongStream longs(long streamSize) {
679 if (streamSize < 0L)
680 throw new IllegalArgumentException("negative Stream size");
681 return StreamSupport.longStream
682 (new RandomLongsSpliterator
683 (this, 0L, streamSize, Long.MAX_VALUE, 0L),
684 false);
685 }
686
687 /**
688 * Returns an effectively unlimited stream of pseudorandom {@code long}
689 * values.
690 *
691 * @implNote This method is implemented to be equivalent to {@code
692 * longs(Long.MAX_VALUE)}.
693 *
694 * @return a stream of pseudorandom {@code long} values
695 */
696 public LongStream longs() {
697 return StreamSupport.longStream
698 (new RandomLongsSpliterator
699 (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
700 false);
701 }
702
703 /**
704 * Returns a stream with the given {@code streamSize} number of
705 * pseudorandom {@code long} values, each conforming to the
706 * given origin and bound.
707 *
708 * @param streamSize the number of values to generate
709 * @param randomNumberOrigin the origin of each random value
710 * @param randomNumberBound the bound of each random value
711 * @return a stream of pseudorandom {@code long} values,
712 * each with the given origin and bound.
713 * @throws IllegalArgumentException if {@code streamSize} is
714 * less than zero.
715 * @throws IllegalArgumentException if {@code randomNumberOrigin}
716 * is greater than or equal to {@code randomNumberBound}
717 */
718 public LongStream longs(long streamSize, long randomNumberOrigin,
719 long randomNumberBound) {
720 if (streamSize < 0L)
721 throw new IllegalArgumentException("negative Stream size");
722 if (randomNumberOrigin >= randomNumberBound)
723 throw new IllegalArgumentException("bound must be greater than origin");
724 return StreamSupport.longStream
725 (new RandomLongsSpliterator
726 (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
727 false);
728 }
729
730 /**
731 * Returns an effectively unlimited stream of pseudorandom {@code
732 * long} values, each conforming to the given origin and bound.
733 *
734 * @implNote This method is implemented to be equivalent to {@code
735 * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
736 *
737 * @param randomNumberOrigin the origin of each random value
738 * @param randomNumberBound the bound of each random value
739 * @return a stream of pseudorandom {@code long} values,
740 * each with the given origin and bound.
741 * @throws IllegalArgumentException if {@code randomNumberOrigin}
742 * is greater than or equal to {@code randomNumberBound}
743 */
744 public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
745 if (randomNumberOrigin >= randomNumberBound)
746 throw new IllegalArgumentException("bound must be greater than origin");
747 return StreamSupport.longStream
748 (new RandomLongsSpliterator
749 (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
750 false);
751 }
752
753 /**
754 * Returns a stream with the given {@code streamSize} number of
755 * pseudorandom {@code double} values.
756 *
757 * @param streamSize the number of values to generate
758 * @return a stream of {@code double} values
759 * @throws IllegalArgumentException if {@code streamSize} is
760 * less than zero
761 */
762 public DoubleStream doubles(long streamSize) {
763 if (streamSize < 0L)
764 throw new IllegalArgumentException("negative Stream size");
765 return StreamSupport.doubleStream
766 (new RandomDoublesSpliterator
767 (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
768 false);
769 }
770
771 /**
772 * Returns an effectively unlimited stream of pseudorandom {@code
773 * double} values.
774 *
775 * @implNote This method is implemented to be equivalent to {@code
776 * doubles(Long.MAX_VALUE)}.
777 *
778 * @return a stream of pseudorandom {@code double} values
779 */
780 public DoubleStream doubles() {
781 return StreamSupport.doubleStream
782 (new RandomDoublesSpliterator
783 (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
784 false);
785 }
786
787 /**
788 * Returns a stream with the given {@code streamSize} number of
789 * pseudorandom {@code double} values, each conforming to the
790 * given origin and bound.
791 *
792 * @param streamSize the number of values to generate
793 * @param randomNumberOrigin the origin of each random value
794 * @param randomNumberBound the bound of each random value
795 * @return a stream of pseudorandom {@code double} values,
796 * each with the given origin and bound.
797 * @throws IllegalArgumentException if {@code streamSize} is
798 * less than zero.
799 * @throws IllegalArgumentException if {@code randomNumberOrigin}
800 * is greater than or equal to {@code randomNumberBound}
801 */
802 public DoubleStream doubles(long streamSize, double randomNumberOrigin,
803 double randomNumberBound) {
804 if (streamSize < 0L)
805 throw new IllegalArgumentException("negative Stream size");
806 if (randomNumberOrigin >= randomNumberBound)
807 throw new IllegalArgumentException("bound must be greater than origin");
808 return StreamSupport.doubleStream
809 (new RandomDoublesSpliterator
810 (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
811 false);
812 }
813
814 /**
815 * Returns an effectively unlimited stream of pseudorandom {@code
816 * double} values, each conforming to the given origin and bound.
817 *
818 * @implNote This method is implemented to be equivalent to {@code
819 * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
820 *
821 * @param randomNumberOrigin the origin of each random value
822 * @param randomNumberBound the bound of each random value
823 * @return a stream of pseudorandom {@code double} values,
824 * each with the given origin and bound.
825 * @throws IllegalArgumentException if {@code randomNumberOrigin}
826 * is greater than or equal to {@code randomNumberBound}
827 */
828 public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
829 if (randomNumberOrigin >= randomNumberBound)
830 throw new IllegalArgumentException("bound must be greater than origin");
831 return StreamSupport.doubleStream
832 (new RandomDoublesSpliterator
833 (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
834 false);
835 }
836
837 /**
838 * Spliterator for int streams. We multiplex the four int
839 * versions into one class by treating and bound < origin as
840 * unbounded, and also by treating "infinite" as equivalent to
841 * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
842 * approach. The long and double versions of this class are
843 * identical except for types.
844 */
845 static class RandomIntsSpliterator implements Spliterator.OfInt {
846 final SplittableRandom rng;
847 long index;
848 final long fence;
849 final int origin;
850 final int bound;
851 RandomIntsSpliterator(SplittableRandom rng, long index, long fence,
852 int origin, int bound) {
853 this.rng = rng; this.index = index; this.fence = fence;
854 this.origin = origin; this.bound = bound;
855 }
856
857 public RandomIntsSpliterator trySplit() {
858 long i = index, m = (i + fence) >>> 1;
859 return (m <= i) ? null :
860 new RandomIntsSpliterator(rng.split(), i, index = m, origin, bound);
861 }
862
863 public long estimateSize() {
864 return fence - index;
865 }
866
867 public int characteristics() {
868 return (Spliterator.SIZED | Spliterator.SUBSIZED |
869 Spliterator.ORDERED | Spliterator.NONNULL |
870 Spliterator.IMMUTABLE);
871 }
872
873 public boolean tryAdvance(IntConsumer consumer) {
874 if (consumer == null) throw new NullPointerException();
875 long i = index, f = fence;
876 if (i < f) {
877 consumer.accept(rng.internalNextInt(origin, bound));
878 index = i + 1;
879 return true;
880 }
881 return false;
882 }
883
884 public void forEachRemaining(IntConsumer consumer) {
885 if (consumer == null) throw new NullPointerException();
886 long i = index, f = fence;
887 if (i < f) {
888 index = f;
889 int o = origin, b = bound;
890 do {
891 consumer.accept(rng.internalNextInt(o, b));
892 } while (++i < f);
893 }
894 }
895 }
896
897 /**
898 * Spliterator for long streams.
899 */
900 static class RandomLongsSpliterator implements Spliterator.OfLong {
901 final SplittableRandom rng;
902 long index;
903 final long fence;
904 final long origin;
905 final long bound;
906 RandomLongsSpliterator(SplittableRandom rng, long index, long fence,
907 long origin, long bound) {
908 this.rng = rng; this.index = index; this.fence = fence;
909 this.origin = origin; this.bound = bound;
910 }
911
912 public RandomLongsSpliterator trySplit() {
913 long i = index, m = (i + fence) >>> 1;
914 return (m <= i) ? null :
915 new RandomLongsSpliterator(rng.split(), i, index = m, origin, bound);
916 }
917
918 public long estimateSize() {
919 return fence - index;
920 }
921
922 public int characteristics() {
923 return (Spliterator.SIZED | Spliterator.SUBSIZED |
924 Spliterator.ORDERED | Spliterator.NONNULL |
925 Spliterator.IMMUTABLE);
926 }
927
928 public boolean tryAdvance(LongConsumer consumer) {
929 if (consumer == null) throw new NullPointerException();
930 long i = index, f = fence;
931 if (i < f) {
932 consumer.accept(rng.internalNextLong(origin, bound));
933 index = i + 1;
934 return true;
935 }
936 return false;
937 }
938
939 public void forEachRemaining(LongConsumer consumer) {
940 if (consumer == null) throw new NullPointerException();
941 long i = index, f = fence;
942 if (i < f) {
943 index = f;
944 long o = origin, b = bound;
945 do {
946 consumer.accept(rng.internalNextLong(o, b));
947 } while (++i < f);
948 }
949 }
950
951 }
952
953 /**
954 * Spliterator for double streams.
955 */
956 static class RandomDoublesSpliterator implements Spliterator.OfDouble {
957 final SplittableRandom rng;
958 long index;
959 final long fence;
960 final double origin;
961 final double bound;
962 RandomDoublesSpliterator(SplittableRandom rng, long index, long fence,
963 double origin, double bound) {
964 this.rng = rng; this.index = index; this.fence = fence;
965 this.origin = origin; this.bound = bound;
966 }
967
968 public RandomDoublesSpliterator trySplit() {
969 long i = index, m = (i + fence) >>> 1;
970 return (m <= i) ? null :
971 new RandomDoublesSpliterator(rng.split(), i, index = m, origin, bound);
972 }
973
974 public long estimateSize() {
975 return fence - index;
976 }
977
978 public int characteristics() {
979 return (Spliterator.SIZED | Spliterator.SUBSIZED |
980 Spliterator.ORDERED | Spliterator.NONNULL |
981 Spliterator.IMMUTABLE);
982 }
983
984 public boolean tryAdvance(DoubleConsumer consumer) {
985 if (consumer == null) throw new NullPointerException();
986 long i = index, f = fence;
987 if (i < f) {
988 consumer.accept(rng.internalNextDouble(origin, bound));
989 index = i + 1;
990 return true;
991 }
992 return false;
993 }
994
995 public void forEachRemaining(DoubleConsumer consumer) {
996 if (consumer == null) throw new NullPointerException();
997 long i = index, f = fence;
998 if (i < f) {
999 index = f;
1000 double o = origin, b = bound;
1001 do {
1002 consumer.accept(rng.internalNextDouble(o, b));
1003 } while (++i < f);
1004 }
1005 }
1006 }
1007
1008 }
1009