ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/SplittableRandom.java
Revision: 1.15
Committed: Fri Aug 9 12:12:10 2013 UTC (10 years, 8 months ago) by dl
Branch: MAIN
Changes since 1.14: +129 -204 lines
Log Message:
Improved algorithm

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.net.InetAddress;
29 import java.util.concurrent.atomic.AtomicLong;
30 import java.util.Spliterator;
31 import java.util.function.IntConsumer;
32 import java.util.function.LongConsumer;
33 import java.util.function.DoubleConsumer;
34 import java.util.stream.StreamSupport;
35 import java.util.stream.IntStream;
36 import java.util.stream.LongStream;
37 import java.util.stream.DoubleStream;
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:
46 *
47 * <ul>
48 *
49 * <li>Series of generated values pass the DieHarder suite testing
50 * independence and uniformity properties of random number generators.
51 * (Most recently validated with <a
52 * href="http://www.phy.duke.edu/~rgb/General/dieharder.php"> version
53 * 3.31.1</a>.) These tests validate only the methods for certain
54 * types and ranges, but similar properties are expected to hold, at
55 * least approximately, for others as well. The <em>period</em>
56 * (length of any series of generated values before it repeats) is at
57 * least 2<sup>64</sup>. </li>
58 *
59 * <li> Method {@link #split} constructs and returns a new
60 * SplittableRandom instance that shares no mutable state with the
61 * current instance. However, with very high probability, the
62 * values collectively generated by the two objects have the same
63 * statistical properties as if the same quantity of values were
64 * generated by a single thread using a single {@code
65 * SplittableRandom} object. </li>
66 *
67 * <li>Instances of SplittableRandom are <em>not</em> thread-safe.
68 * They are designed to be split, not shared, across threads. For
69 * example, a {@link java.util.concurrent.ForkJoinTask
70 * fork/join-style} computation using random numbers might include a
71 * construction of the form {@code new
72 * Subtask(aSplittableRandom.split()).fork()}.
73 *
74 * <li>This class provides additional methods for generating random
75 * streams, that employ the above techniques when used in {@code
76 * stream.parallel()} mode.</li>
77 *
78 * </ul>
79 *
80 * @author Guy Steele
81 * @author Doug Lea
82 * @since 1.8
83 */
84 public class SplittableRandom {
85
86 /*
87 * Implementation Overview.
88 *
89 * This algorithm was inspired by the "DotMix" algorithm by
90 * Leiserson, Schardl, and Sukha "Deterministic Parallel
91 * Random-Number Generation for Dynamic-Multithreading Platforms",
92 * PPoPP 2012, as well as those in "Parallel random numbers: as
93 * easy as 1, 2, 3" by Salmon, Morae, Dror, and Shaw, SC 2011. It
94 * differs mainly in simplifying and cheapening operations.
95 *
96 * The primary update step (method nextSeed()) is to add a
97 * constant ("gamma") to the current (64 bit) seed, forming a
98 * simple sequence. The seed and the gamma values for any two
99 * SplittableRandom instances are highly likely to be different.
100 *
101 * Methods nextLong, nextInt, and derivatives do not return the
102 * sequence (seed) values, but instead a hash-like bit-mix of
103 * their bits, producing more independently distributed sequences.
104 * For nextLong, the mix64 bit-mixing function computes the same
105 * value as the "64-bit finalizer" function in Austin Appleby's
106 * MurmurHash3 algorithm. See
107 * http://code.google.com/p/smhasher/wiki/MurmurHash3 , which
108 * comments: "The constants for the finalizers were generated by a
109 * simple simulated-annealing algorithm, and both avalanche all
110 * bits of 'h' to within 0.25% bias." The mix32 function is
111 * equivalent to (int)(mix64(seed) >>> 32), but faster because it
112 * omits a step that doesn't contribute to result.
113 *
114 * The split operation uses the current generator to form the seed
115 * and gamma for another SplittableRandom. To conservatively
116 * avoid potential correlations between seed and value generation,
117 * gamma selection (method nextGamma) uses the "Mix13" constants
118 * for MurmurHash3 described by David Stafford
119 * (http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html)
120 * To avoid potential weaknesses in bit-mixing transformations, we
121 * restrict gammas to odd values with at least 12 and no more than
122 * 52 bits set. Rather than rejecting candidates with too few or
123 * too many bits set, method nextGamma flips some bits (which has
124 * the effect of mapping at most 4 to any given gamma value).
125 * This reduces the effective set of 64bit odd gamma values by
126 * about 2<sup>14</sup>, a very tiny percentage, and serves as an
127 * automated screening for sequence constant selection that is
128 * left as an empirical decision in some other hashing and crypto
129 * algorithms.
130 *
131 * The resulting generator thus transforms a sequence in which
132 * (typically) many bits change on each step, with an inexpensive
133 * mixer with good (but less than cryptographically secure)
134 * avalanching.
135 *
136 * The default (no-argument) constructor, in essence, invokes
137 * split() for a common "seeder" SplittableRandom. Unlike other
138 * cases, this split must be performed in a thread-safe manner, so
139 * we use an AtomicLong to represent the seed rather than use an
140 * explicit SplittableRandom. To bootstrap the seeder, we start
141 * off using a seed based on current time and host. This serves as
142 * a slimmed-down (and insecure) variant of SecureRandom that also
143 * avoids stalls that may occur when using /dev/random.
144 *
145 * It is a relatively simple matter to apply the basic design here
146 * to use 128 bit seeds. However, emulating 128bit arithmetic and
147 * carrying around twice the state add more overhead than appears
148 * warranted for current usages.
149 *
150 * File organization: First the non-public methods that constitute
151 * the main algorithm, then the main public methods, followed by
152 * some custom spliterator classes needed for stream methods.
153 */
154
155 /**
156 * The initial gamma value for (unsplit) SplittableRandoms. Must
157 * be odd with at least 12 and no more than 52 bits set. Currently
158 * set to the golden ratio scaled to 64bits.
159 */
160 private static final long INITIAL_GAMMA = 0x9e3779b97f4a7c15L;
161
162 /**
163 * The least non-zero value returned by nextDouble(). This value
164 * is scaled by a random value of 53 bits to produce a result.
165 */
166 private static final double DOUBLE_UNIT = 1.0 / (1L << 53);
167
168 /**
169 * The seed. Updated only via method nextSeed.
170 */
171 private long seed;
172
173 /**
174 * The step value.
175 */
176 private final long gamma;
177
178 /**
179 * Internal constructor used by all others except default constructor.
180 */
181 private SplittableRandom(long seed, long gamma) {
182 this.seed = seed;
183 this.gamma = gamma;
184 }
185
186 /**
187 * Computes MurmurHash3 64bit mix function.
188 */
189 private static long mix64(long z) {
190 z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
191 z = (z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L;
192 return z ^ (z >>> 33);
193 }
194
195 /**
196 * Returns the 32 high bits of mix64(z) as int.
197 */
198 private static int mix32(long z) {
199 z = (z ^ (z >>> 33)) * 0xff51afd7ed558ccdL;
200 return (int)(((z ^ (z >>> 33)) * 0xc4ceb9fe1a85ec53L) >>> 32);
201 }
202
203 /**
204 * Returns the gamma value to use for a new split instance.
205 */
206 private static long nextGamma(long z) {
207 z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L; // Stafford "Mix13"
208 z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
209 z = (z ^ (z >>> 31)) | 1L; // force to be odd
210 int n = Long.bitCount(z); // ensure enough 0 and 1 bits
211 return (n < 12 || n > 52) ? z ^ 0xaaaaaaaaaaaaaaaaL : z;
212 }
213
214 /**
215 * Adds gamma to seed.
216 */
217 private long nextSeed() {
218 return seed += gamma;
219 }
220
221 /**
222 * The seed generator for default constructors.
223 */
224 private static final AtomicLong seeder =
225 new AtomicLong(mix64((((long)hashedHostAddress()) << 32) ^
226 System.currentTimeMillis()) ^
227 mix64(System.nanoTime()));
228
229 /**
230 * Returns hash of local host IP address, if available; else 0.
231 */
232 private static int hashedHostAddress() {
233 try {
234 return InetAddress.getLocalHost().hashCode();
235 } catch (Exception ex) {
236 return 0;
237 }
238 }
239
240 // IllegalArgumentException messages
241 static final String BadBound = "bound must be positive";
242 static final String BadRange = "bound must be greater than origin";
243 static final String BadSize = "size must be non-negative";
244
245 /*
246 * Internal versions of nextX methods used by streams, as well as
247 * the public nextX(origin, bound) methods. These exist mainly to
248 * avoid the need for multiple versions of stream spliterators
249 * across the different exported forms of streams.
250 */
251
252 /**
253 * The form of nextLong used by LongStream Spliterators. If
254 * origin is greater than bound, acts as unbounded form of
255 * nextLong, else as bounded form.
256 *
257 * @param origin the least value, unless greater than bound
258 * @param bound the upper bound (exclusive), must not equal origin
259 * @return a pseudorandom value
260 */
261 final long internalNextLong(long origin, long bound) {
262 /*
263 * Four Cases:
264 *
265 * 1. If the arguments indicate unbounded form, act as
266 * nextLong().
267 *
268 * 2. If the range is an exact power of two, apply the
269 * associated bit mask.
270 *
271 * 3. If the range is positive, loop to avoid potential bias
272 * when the implicit nextLong() bound (2<sup>64</sup>) is not
273 * evenly divisible by the range. The loop rejects candidates
274 * computed from otherwise over-represented values. The
275 * expected number of iterations under an ideal generator
276 * varies from 1 to 2, depending on the bound. The loop itself
277 * takes an unlovable form. Because the first candidate is
278 * already available, we need a break-in-the-middle
279 * construction, which is concisely but cryptically performed
280 * within the while-condition of a body-less for loop.
281 *
282 * 4. Otherwise, the range cannot be represented as a positive
283 * long. The loop repeatedly generates unbounded longs until
284 * obtaining a candidate meeting constraints (with an expected
285 * number of iterations of less than two).
286 */
287
288 long r = mix64(nextSeed());
289 if (origin < bound) {
290 long n = bound - origin, m = n - 1;
291 if ((n & m) == 0L) // power of two
292 r = (r & m) + origin;
293 else if (n > 0L) { // reject over-represented candidates
294 for (long u = r >>> 1; // ensure nonnegative
295 u + m - (r = u % n) < 0L; // rejection check
296 u = mix64(nextSeed()) >>> 1) // retry
297 ;
298 r += origin;
299 }
300 else { // range not representable as long
301 while (r < origin || r >= bound)
302 r = mix64(nextSeed());
303 }
304 }
305 return r;
306 }
307
308 /**
309 * The form of nextInt used by IntStream Spliterators.
310 * Exactly the same as long version, except for types.
311 *
312 * @param origin the least value, unless greater than bound
313 * @param bound the upper bound (exclusive), must not equal origin
314 * @return a pseudorandom value
315 */
316 final int internalNextInt(int origin, int bound) {
317 int r = mix32(nextSeed());
318 if (origin < bound) {
319 int n = bound - origin, m = n - 1;
320 if ((n & m) == 0)
321 r = (r & m) + origin;
322 else if (n > 0) {
323 for (int u = r >>> 1;
324 u + m - (r = u % n) < 0;
325 u = mix32(nextSeed()) >>> 1)
326 ;
327 r += origin;
328 }
329 else {
330 while (r < origin || r >= bound)
331 r = mix32(nextSeed());
332 }
333 }
334 return r;
335 }
336
337 /**
338 * The form of nextDouble used by DoubleStream Spliterators.
339 *
340 * @param origin the least value, unless greater than bound
341 * @param bound the upper bound (exclusive), must not equal origin
342 * @return a pseudorandom value
343 */
344 final double internalNextDouble(double origin, double bound) {
345 double r = (nextLong() >>> 11) * DOUBLE_UNIT;
346 if (origin < bound) {
347 r = r * (bound - origin) + origin;
348 if (r >= bound) // correct for rounding
349 r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
350 }
351 return r;
352 }
353
354 /* ---------------- public methods ---------------- */
355
356 /**
357 * Creates a new SplittableRandom instance using the specified
358 * initial seed. SplittableRandom instances created with the same
359 * seed in the same program generate identical sequences of values.
360 *
361 * @param seed the initial seed
362 */
363 public SplittableRandom(long seed) {
364 this(seed, INITIAL_GAMMA);
365 }
366
367 /**
368 * Creates a new SplittableRandom instance that is likely to
369 * generate sequences of values that are statistically independent
370 * of those of any other instances in the current program; and
371 * may, and typically does, vary across program invocations.
372 */
373 public SplittableRandom() { // emulate seeder.split()
374 this.gamma = nextGamma(this.seed = seeder.addAndGet(INITIAL_GAMMA));
375 }
376
377 /**
378 * Constructs and returns a new SplittableRandom instance that
379 * shares no mutable state with this instance. However, with very
380 * high probability, the set of values collectively generated by
381 * the two objects has the same statistical properties as if the
382 * same quantity of values were generated by a single thread using
383 * a single SplittableRandom object. Either or both of the two
384 * objects may be further split using the {@code split()} method,
385 * and the same expected statistical properties apply to the
386 * entire set of generators constructed by such recursive
387 * splitting.
388 *
389 * @return the new SplittableRandom instance
390 */
391 public SplittableRandom split() {
392 long s = nextSeed();
393 return new SplittableRandom(s, nextGamma(s));
394 }
395
396 /**
397 * Returns a pseudorandom {@code int} value.
398 *
399 * @return a pseudorandom {@code int} value
400 */
401 public int nextInt() {
402 return mix32(nextSeed());
403 }
404
405 /**
406 * Returns a pseudorandom {@code int} value between zero (inclusive)
407 * and the specified bound (exclusive).
408 *
409 * @param bound the bound on the random number to be returned. Must be
410 * positive.
411 * @return a pseudorandom {@code int} value between zero
412 * (inclusive) and the bound (exclusive)
413 * @throws IllegalArgumentException if the bound is less than zero
414 */
415 public int nextInt(int bound) {
416 if (bound <= 0)
417 throw new IllegalArgumentException(BadBound);
418 // Specialize internalNextInt for origin 0
419 int r = mix32(nextSeed());
420 int m = bound - 1;
421 if ((bound & m) == 0) // power of two
422 r &= m;
423 else { // reject over-represented candidates
424 for (int u = r >>> 1;
425 u + m - (r = u % bound) < 0;
426 u = mix32(nextSeed()) >>> 1)
427 ;
428 }
429 return r;
430 }
431
432 /**
433 * Returns a pseudorandom {@code int} value between the specified
434 * origin (inclusive) and the specified bound (exclusive).
435 *
436 * @param origin the least value returned
437 * @param bound the upper bound (exclusive)
438 * @return a pseudorandom {@code int} value between the origin
439 * (inclusive) and the bound (exclusive)
440 * @throws IllegalArgumentException if {@code origin} is greater than
441 * or equal to {@code bound}
442 */
443 public int nextInt(int origin, int bound) {
444 if (origin >= bound)
445 throw new IllegalArgumentException(BadRange);
446 return internalNextInt(origin, bound);
447 }
448
449 /**
450 * Returns a pseudorandom {@code long} value.
451 *
452 * @return a pseudorandom {@code long} value
453 */
454 public long nextLong() {
455 return mix64(nextSeed());
456 }
457
458 /**
459 * Returns a pseudorandom {@code long} value between zero (inclusive)
460 * and the specified bound (exclusive).
461 *
462 * @param bound the bound on the random number to be returned. Must be
463 * positive.
464 * @return a pseudorandom {@code long} value between zero
465 * (inclusive) and the bound (exclusive)
466 * @throws IllegalArgumentException if {@code bound} is less than zero
467 */
468 public long nextLong(long bound) {
469 if (bound <= 0)
470 throw new IllegalArgumentException(BadBound);
471 // Specialize internalNextLong for origin 0
472 long r = mix64(nextSeed());
473 long m = bound - 1;
474 if ((bound & m) == 0L) // power of two
475 r &= m;
476 else { // reject over-represented candidates
477 for (long u = r >>> 1;
478 u + m - (r = u % bound) < 0L;
479 u = mix64(nextSeed()) >>> 1)
480 ;
481 }
482 return r;
483 }
484
485 /**
486 * Returns a pseudorandom {@code long} value between the specified
487 * origin (inclusive) and the specified bound (exclusive).
488 *
489 * @param origin the least value returned
490 * @param bound the upper bound (exclusive)
491 * @return a pseudorandom {@code long} value between the origin
492 * (inclusive) and the bound (exclusive)
493 * @throws IllegalArgumentException if {@code origin} is greater than
494 * or equal to {@code bound}
495 */
496 public long nextLong(long origin, long bound) {
497 if (origin >= bound)
498 throw new IllegalArgumentException(BadRange);
499 return internalNextLong(origin, bound);
500 }
501
502 /**
503 * Returns a pseudorandom {@code double} value between zero
504 * (inclusive) and one (exclusive).
505 *
506 * @return a pseudorandom {@code double} value between zero
507 * (inclusive) and one (exclusive)
508 */
509 public double nextDouble() {
510 return (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT;
511 }
512
513 /**
514 * Returns a pseudorandom {@code double} value between 0.0
515 * (inclusive) and the specified bound (exclusive).
516 *
517 * @param bound the bound on the random number to be returned. Must be
518 * positive.
519 * @return a pseudorandom {@code double} value between zero
520 * (inclusive) and the bound (exclusive)
521 * @throws IllegalArgumentException if {@code bound} is less than zero
522 */
523 public double nextDouble(double bound) {
524 if (!(bound > 0.0))
525 throw new IllegalArgumentException(BadBound);
526 double result = (mix64(nextSeed()) >>> 11) * DOUBLE_UNIT * bound;
527 return (result < bound) ? result : // correct for rounding
528 Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
529 }
530
531 /**
532 * Returns a pseudorandom {@code double} value between the specified
533 * origin (inclusive) and bound (exclusive).
534 *
535 * @param origin the least value returned
536 * @param bound the upper bound
537 * @return a pseudorandom {@code double} value between the origin
538 * (inclusive) and the bound (exclusive)
539 * @throws IllegalArgumentException if {@code origin} is greater than
540 * or equal to {@code bound}
541 */
542 public double nextDouble(double origin, double bound) {
543 if (!(origin < bound))
544 throw new IllegalArgumentException(BadRange);
545 return internalNextDouble(origin, bound);
546 }
547
548 /**
549 * Returns a pseudorandom {@code boolean} value.
550 *
551 * @return a pseudorandom {@code boolean} value
552 */
553 public boolean nextBoolean() {
554 return mix32(nextSeed()) < 0;
555 }
556
557 // stream methods, coded in a way intended to better isolate for
558 // maintenance purposes the small differences across forms.
559
560 /**
561 * Returns a stream producing the given {@code streamSize} number of
562 * pseudorandom {@code int} values.
563 *
564 * @param streamSize the number of values to generate
565 * @return a stream of pseudorandom {@code int} values
566 * @throws IllegalArgumentException if {@code streamSize} is
567 * less than zero
568 */
569 public IntStream ints(long streamSize) {
570 if (streamSize < 0L)
571 throw new IllegalArgumentException(BadSize);
572 return StreamSupport.intStream
573 (new RandomIntsSpliterator
574 (this, 0L, streamSize, Integer.MAX_VALUE, 0),
575 false);
576 }
577
578 /**
579 * Returns an effectively unlimited stream of pseudorandom {@code int}
580 * values.
581 *
582 * @implNote This method is implemented to be equivalent to {@code
583 * ints(Long.MAX_VALUE)}.
584 *
585 * @return a stream of pseudorandom {@code int} values
586 */
587 public IntStream ints() {
588 return StreamSupport.intStream
589 (new RandomIntsSpliterator
590 (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
591 false);
592 }
593
594 /**
595 * Returns a stream producing the given {@code streamSize} number of
596 * pseudorandom {@code int} values, each conforming to the given
597 * origin and bound.
598 *
599 * @param streamSize the number of values to generate
600 * @param randomNumberOrigin the origin of each random value
601 * @param randomNumberBound the bound of each random value
602 * @return a stream of pseudorandom {@code int} values,
603 * each with the given origin and bound
604 * @throws IllegalArgumentException if {@code streamSize} is
605 * less than zero, or {@code randomNumberOrigin}
606 * is greater than or equal to {@code randomNumberBound}
607 */
608 public IntStream ints(long streamSize, int randomNumberOrigin,
609 int randomNumberBound) {
610 if (streamSize < 0L)
611 throw new IllegalArgumentException(BadSize);
612 if (randomNumberOrigin >= randomNumberBound)
613 throw new IllegalArgumentException(BadRange);
614 return StreamSupport.intStream
615 (new RandomIntsSpliterator
616 (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
617 false);
618 }
619
620 /**
621 * Returns an effectively unlimited stream of pseudorandom {@code
622 * int} values, each conforming to the given origin and bound.
623 *
624 * @implNote This method is implemented to be equivalent to {@code
625 * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
626 *
627 * @param randomNumberOrigin the origin of each random value
628 * @param randomNumberBound the bound of each random value
629 * @return a stream of pseudorandom {@code int} values,
630 * each with the given origin and bound
631 * @throws IllegalArgumentException if {@code randomNumberOrigin}
632 * is greater than or equal to {@code randomNumberBound}
633 */
634 public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
635 if (randomNumberOrigin >= randomNumberBound)
636 throw new IllegalArgumentException(BadRange);
637 return StreamSupport.intStream
638 (new RandomIntsSpliterator
639 (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
640 false);
641 }
642
643 /**
644 * Returns a stream producing the given {@code streamSize} number of
645 * pseudorandom {@code long} values.
646 *
647 * @param streamSize the number of values to generate
648 * @return a stream of pseudorandom {@code long} values
649 * @throws IllegalArgumentException if {@code streamSize} is
650 * less than zero
651 */
652 public LongStream longs(long streamSize) {
653 if (streamSize < 0L)
654 throw new IllegalArgumentException(BadSize);
655 return StreamSupport.longStream
656 (new RandomLongsSpliterator
657 (this, 0L, streamSize, Long.MAX_VALUE, 0L),
658 false);
659 }
660
661 /**
662 * Returns an effectively unlimited stream of pseudorandom {@code long}
663 * values.
664 *
665 * @implNote This method is implemented to be equivalent to {@code
666 * longs(Long.MAX_VALUE)}.
667 *
668 * @return a stream of pseudorandom {@code long} values
669 */
670 public LongStream longs() {
671 return StreamSupport.longStream
672 (new RandomLongsSpliterator
673 (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
674 false);
675 }
676
677 /**
678 * Returns a stream producing the given {@code streamSize} number of
679 * pseudorandom {@code long} values, each conforming to the
680 * given origin and bound.
681 *
682 * @param streamSize the number of values to generate
683 * @param randomNumberOrigin the origin of each random value
684 * @param randomNumberBound the bound of each random value
685 * @return a stream of pseudorandom {@code long} values,
686 * each with the given origin and bound
687 * @throws IllegalArgumentException if {@code streamSize} is
688 * less than zero, or {@code randomNumberOrigin}
689 * is greater than or equal to {@code randomNumberBound}
690 */
691 public LongStream longs(long streamSize, long randomNumberOrigin,
692 long randomNumberBound) {
693 if (streamSize < 0L)
694 throw new IllegalArgumentException(BadSize);
695 if (randomNumberOrigin >= randomNumberBound)
696 throw new IllegalArgumentException(BadRange);
697 return StreamSupport.longStream
698 (new RandomLongsSpliterator
699 (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
700 false);
701 }
702
703 /**
704 * Returns an effectively unlimited stream of pseudorandom {@code
705 * long} values, each conforming to the given origin and bound.
706 *
707 * @implNote This method is implemented to be equivalent to {@code
708 * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
709 *
710 * @param randomNumberOrigin the origin of each random value
711 * @param randomNumberBound the bound of each random value
712 * @return a stream of pseudorandom {@code long} values,
713 * each with the given origin and bound
714 * @throws IllegalArgumentException if {@code randomNumberOrigin}
715 * is greater than or equal to {@code randomNumberBound}
716 */
717 public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
718 if (randomNumberOrigin >= randomNumberBound)
719 throw new IllegalArgumentException(BadRange);
720 return StreamSupport.longStream
721 (new RandomLongsSpliterator
722 (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
723 false);
724 }
725
726 /**
727 * Returns a stream producing the given {@code streamSize} number of
728 * pseudorandom {@code double} values, each between zero
729 * (inclusive) and one (exclusive).
730 *
731 * @param streamSize the number of values to generate
732 * @return a stream of {@code double} values
733 * @throws IllegalArgumentException if {@code streamSize} is
734 * less than zero
735 */
736 public DoubleStream doubles(long streamSize) {
737 if (streamSize < 0L)
738 throw new IllegalArgumentException(BadSize);
739 return StreamSupport.doubleStream
740 (new RandomDoublesSpliterator
741 (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
742 false);
743 }
744
745 /**
746 * Returns an effectively unlimited stream of pseudorandom {@code
747 * double} values, each between zero (inclusive) and one
748 * (exclusive).
749 *
750 * @implNote This method is implemented to be equivalent to {@code
751 * doubles(Long.MAX_VALUE)}.
752 *
753 * @return a stream of pseudorandom {@code double} values
754 */
755 public DoubleStream doubles() {
756 return StreamSupport.doubleStream
757 (new RandomDoublesSpliterator
758 (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
759 false);
760 }
761
762 /**
763 * Returns a stream producing the given {@code streamSize} number of
764 * pseudorandom {@code double} values, each conforming to the
765 * given origin and bound.
766 *
767 * @param streamSize the number of values to generate
768 * @param randomNumberOrigin the origin of each random value
769 * @param randomNumberBound the bound of each random value
770 * @return a stream of pseudorandom {@code double} values,
771 * each with the given origin and bound
772 * @throws IllegalArgumentException if {@code streamSize} is
773 * less than zero
774 * @throws IllegalArgumentException if {@code randomNumberOrigin}
775 * is greater than or equal to {@code randomNumberBound}
776 */
777 public DoubleStream doubles(long streamSize, double randomNumberOrigin,
778 double randomNumberBound) {
779 if (streamSize < 0L)
780 throw new IllegalArgumentException(BadSize);
781 if (!(randomNumberOrigin < randomNumberBound))
782 throw new IllegalArgumentException(BadRange);
783 return StreamSupport.doubleStream
784 (new RandomDoublesSpliterator
785 (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
786 false);
787 }
788
789 /**
790 * Returns an effectively unlimited stream of pseudorandom {@code
791 * double} values, each conforming to the given origin and bound.
792 *
793 * @implNote This method is implemented to be equivalent to {@code
794 * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
795 *
796 * @param randomNumberOrigin the origin of each random value
797 * @param randomNumberBound the bound of each random value
798 * @return a stream of pseudorandom {@code double} values,
799 * each with the given origin and bound
800 * @throws IllegalArgumentException if {@code randomNumberOrigin}
801 * is greater than or equal to {@code randomNumberBound}
802 */
803 public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
804 if (!(randomNumberOrigin < randomNumberBound))
805 throw new IllegalArgumentException(BadRange);
806 return StreamSupport.doubleStream
807 (new RandomDoublesSpliterator
808 (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
809 false);
810 }
811
812 /**
813 * Spliterator for int streams. We multiplex the four int
814 * versions into one class by treating a bound less than origin as
815 * unbounded, and also by treating "infinite" as equivalent to
816 * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
817 * approach. The long and double versions of this class are
818 * identical except for types.
819 */
820 static final class RandomIntsSpliterator implements Spliterator.OfInt {
821 final SplittableRandom rng;
822 long index;
823 final long fence;
824 final int origin;
825 final int bound;
826 RandomIntsSpliterator(SplittableRandom rng, long index, long fence,
827 int origin, int bound) {
828 this.rng = rng; this.index = index; this.fence = fence;
829 this.origin = origin; this.bound = bound;
830 }
831
832 public RandomIntsSpliterator trySplit() {
833 long i = index, m = (i + fence) >>> 1;
834 return (m <= i) ? null :
835 new RandomIntsSpliterator(rng.split(), i, index = m, origin, bound);
836 }
837
838 public long estimateSize() {
839 return fence - index;
840 }
841
842 public int characteristics() {
843 return (Spliterator.SIZED | Spliterator.SUBSIZED |
844 Spliterator.NONNULL | Spliterator.IMMUTABLE);
845 }
846
847 public boolean tryAdvance(IntConsumer consumer) {
848 if (consumer == null) throw new NullPointerException();
849 long i = index, f = fence;
850 if (i < f) {
851 consumer.accept(rng.internalNextInt(origin, bound));
852 index = i + 1;
853 return true;
854 }
855 return false;
856 }
857
858 public void forEachRemaining(IntConsumer consumer) {
859 if (consumer == null) throw new NullPointerException();
860 long i = index, f = fence;
861 if (i < f) {
862 index = f;
863 SplittableRandom r = rng;
864 int o = origin, b = bound;
865 do {
866 consumer.accept(r.internalNextInt(o, b));
867 } while (++i < f);
868 }
869 }
870 }
871
872 /**
873 * Spliterator for long streams.
874 */
875 static final class RandomLongsSpliterator implements Spliterator.OfLong {
876 final SplittableRandom rng;
877 long index;
878 final long fence;
879 final long origin;
880 final long bound;
881 RandomLongsSpliterator(SplittableRandom rng, long index, long fence,
882 long origin, long bound) {
883 this.rng = rng; this.index = index; this.fence = fence;
884 this.origin = origin; this.bound = bound;
885 }
886
887 public RandomLongsSpliterator trySplit() {
888 long i = index, m = (i + fence) >>> 1;
889 return (m <= i) ? null :
890 new RandomLongsSpliterator(rng.split(), i, index = m, origin, bound);
891 }
892
893 public long estimateSize() {
894 return fence - index;
895 }
896
897 public int characteristics() {
898 return (Spliterator.SIZED | Spliterator.SUBSIZED |
899 Spliterator.NONNULL | Spliterator.IMMUTABLE);
900 }
901
902 public boolean tryAdvance(LongConsumer consumer) {
903 if (consumer == null) throw new NullPointerException();
904 long i = index, f = fence;
905 if (i < f) {
906 consumer.accept(rng.internalNextLong(origin, bound));
907 index = i + 1;
908 return true;
909 }
910 return false;
911 }
912
913 public void forEachRemaining(LongConsumer consumer) {
914 if (consumer == null) throw new NullPointerException();
915 long i = index, f = fence;
916 if (i < f) {
917 index = f;
918 SplittableRandom r = rng;
919 long o = origin, b = bound;
920 do {
921 consumer.accept(r.internalNextLong(o, b));
922 } while (++i < f);
923 }
924 }
925
926 }
927
928 /**
929 * Spliterator for double streams.
930 */
931 static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
932 final SplittableRandom rng;
933 long index;
934 final long fence;
935 final double origin;
936 final double bound;
937 RandomDoublesSpliterator(SplittableRandom rng, long index, long fence,
938 double origin, double bound) {
939 this.rng = rng; this.index = index; this.fence = fence;
940 this.origin = origin; this.bound = bound;
941 }
942
943 public RandomDoublesSpliterator trySplit() {
944 long i = index, m = (i + fence) >>> 1;
945 return (m <= i) ? null :
946 new RandomDoublesSpliterator(rng.split(), i, index = m, origin, bound);
947 }
948
949 public long estimateSize() {
950 return fence - index;
951 }
952
953 public int characteristics() {
954 return (Spliterator.SIZED | Spliterator.SUBSIZED |
955 Spliterator.NONNULL | Spliterator.IMMUTABLE);
956 }
957
958 public boolean tryAdvance(DoubleConsumer consumer) {
959 if (consumer == null) throw new NullPointerException();
960 long i = index, f = fence;
961 if (i < f) {
962 consumer.accept(rng.internalNextDouble(origin, bound));
963 index = i + 1;
964 return true;
965 }
966 return false;
967 }
968
969 public void forEachRemaining(DoubleConsumer consumer) {
970 if (consumer == null) throw new NullPointerException();
971 long i = index, f = fence;
972 if (i < f) {
973 index = f;
974 SplittableRandom r = rng;
975 double o = origin, b = bound;
976 do {
977 consumer.accept(r.internalNextDouble(o, b));
978 } while (++i < f);
979 }
980 }
981 }
982
983 }