ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/SplittableRandom.java
Revision: 1.6
Committed: Thu Jul 11 23:22:01 2013 UTC (10 years, 9 months ago) by dl
Branch: MAIN
Changes since 1.5: +1 -1 lines
Log Message:
Typo

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