1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.rng;
18
19 import java.util.Objects;
20 import java.util.Spliterator;
21 import java.util.function.Consumer;
22 import java.util.function.DoubleConsumer;
23 import java.util.function.IntConsumer;
24 import java.util.function.LongConsumer;
25 import java.util.function.ToDoubleFunction;
26 import java.util.function.ToIntFunction;
27 import java.util.function.ToLongFunction;
28
29
30
31
32
33
34 final class UniformRandomProviderSupport {
35
36 private static final String INVALID_STREAM_SIZE = "Invalid stream size: ";
37
38 private static final String INVALID_UPPER_BOUND = "Upper bound must be above zero: ";
39
40 private static final String INVALID_RANGE = "Invalid range: [%s, %s)";
41
42 private static final long POW_32 = 1L << 32;
43
44 private static final String NULL_ACTION = "action must not be null";
45
46
47 private UniformRandomProviderSupport() {}
48
49
50
51
52
53
54
55 static void validateStreamSize(long size) {
56 if (size < 0) {
57 throw new IllegalArgumentException(INVALID_STREAM_SIZE + size);
58 }
59 }
60
61
62
63
64
65
66
67 static void validateUpperBound(int bound) {
68 if (bound <= 0) {
69 throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
70 }
71 }
72
73
74
75
76
77
78
79 static void validateUpperBound(long bound) {
80 if (bound <= 0) {
81 throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
82 }
83 }
84
85
86
87
88
89
90
91
92 static void validateUpperBound(float bound) {
93
94 if (!(bound > 0 && bound <= Float.MAX_VALUE)) {
95 throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
96 }
97 }
98
99
100
101
102
103
104
105
106 static void validateUpperBound(double bound) {
107
108 if (!(bound > 0 && bound <= Double.MAX_VALUE)) {
109 throw new IllegalArgumentException(INVALID_UPPER_BOUND + bound);
110 }
111 }
112
113
114
115
116
117
118
119
120
121
122 static void validateRange(int origin, int bound) {
123 if (origin >= bound) {
124 throw new IllegalArgumentException(String.format(INVALID_RANGE, origin, bound));
125 }
126 }
127
128
129
130
131
132
133
134
135
136
137 static void validateRange(long origin, long bound) {
138 if (origin >= bound) {
139 throw new IllegalArgumentException(String.format(INVALID_RANGE, origin, bound));
140 }
141 }
142
143
144
145
146
147
148
149
150
151
152 static void validateRange(double origin, double bound) {
153 if (origin >= bound || !Double.isFinite(origin) || !Double.isFinite(bound)) {
154 throw new IllegalArgumentException(String.format(INVALID_RANGE, origin, bound));
155 }
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190 static void validateFromIndexSize(int fromIndex, int size, int length) {
191
192
193
194 if ((fromIndex | size) < 0 || size > length - fromIndex) {
195 throw new IndexOutOfBoundsException(
196
197 String.format("Range [%d, %<d + %d) out of bounds for length %d",
198 fromIndex, size, length));
199 }
200 }
201
202
203
204
205
206
207
208
209
210
211
212
213
214 static void nextBytes(UniformRandomProvider source,
215 byte[] bytes, int start, int len) {
216
217
218 final int indexLoopLimit = start + (len & 0x7ffffff8);
219
220
221 int index = start;
222 while (index < indexLoopLimit) {
223 final long random = source.nextLong();
224 bytes[index++] = (byte) random;
225 bytes[index++] = (byte) (random >>> 8);
226 bytes[index++] = (byte) (random >>> 16);
227 bytes[index++] = (byte) (random >>> 24);
228 bytes[index++] = (byte) (random >>> 32);
229 bytes[index++] = (byte) (random >>> 40);
230 bytes[index++] = (byte) (random >>> 48);
231 bytes[index++] = (byte) (random >>> 56);
232 }
233
234
235 final int indexLimit = start + len;
236
237
238 if (index < indexLimit) {
239 long random = source.nextLong();
240 for (;;) {
241 bytes[index++] = (byte) random;
242 if (index == indexLimit) {
243 break;
244 }
245 random >>>= 8;
246 }
247 }
248 }
249
250
251
252
253
254
255
256
257
258 static int nextInt(UniformRandomProvider source,
259 int n) {
260
261
262 long m = (source.nextInt() & 0xffffffffL) * n;
263 long l = m & 0xffffffffL;
264 if (l < n) {
265
266 final long t = POW_32 % n;
267 while (l < t) {
268 m = (source.nextInt() & 0xffffffffL) * n;
269 l = m & 0xffffffffL;
270 }
271 }
272 return (int) (m >>> 32);
273 }
274
275
276
277
278
279
280
281
282
283
284
285
286 static int nextInt(UniformRandomProvider source,
287 int origin, int bound) {
288 final int n = bound - origin;
289 if (n > 0) {
290 return nextInt(source, n) + origin;
291 }
292
293
294 int v = source.nextInt();
295 while (v < origin || v >= bound) {
296 v = source.nextInt();
297 }
298 return v;
299 }
300
301
302
303
304
305
306
307
308
309
310 static long nextLong(UniformRandomProvider source,
311 long n) {
312 long bits;
313 long val;
314 do {
315 bits = source.nextLong() >>> 1;
316 val = bits % n;
317 } while (bits - val + (n - 1) < 0);
318
319 return val;
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333 static long nextLong(UniformRandomProvider source,
334 long origin, long bound) {
335 final long n = bound - origin;
336 if (n > 0) {
337 return nextLong(source, n) + origin;
338 }
339
340
341 long v = source.nextLong();
342 while (v < origin || v >= bound) {
343 v = source.nextLong();
344 }
345 return v;
346 }
347
348
349
350
351
352
353
354
355
356
357 static float nextFloat(UniformRandomProvider source,
358 float bound) {
359 float v = source.nextFloat() * bound;
360 if (v >= bound) {
361
362 v = Math.nextDown(bound);
363 }
364 return v;
365 }
366
367
368
369
370
371
372
373
374
375
376
377
378 static float nextFloat(UniformRandomProvider source,
379 float origin, float bound) {
380 float v = source.nextFloat();
381
382
383
384 v = (1f - v) * origin + v * bound;
385 if (v >= bound) {
386
387 v = Math.nextDown(bound);
388 }
389 return v;
390 }
391
392
393
394
395
396
397
398
399
400
401 static double nextDouble(UniformRandomProvider source,
402 double bound) {
403 double v = source.nextDouble() * bound;
404 if (v >= bound) {
405
406 v = Math.nextDown(bound);
407 }
408 return v;
409 }
410
411
412
413
414
415
416
417
418
419
420
421
422 static double nextDouble(UniformRandomProvider source,
423 double origin, double bound) {
424 double v = source.nextDouble();
425
426
427
428 v = (1f - v) * origin + v * bound;
429 if (v >= bound) {
430
431 v = Math.nextDown(bound);
432 }
433 return v;
434 }
435
436
437
438
439
440
441
442
443 private static class ProviderSpliterator {
444
445 protected long position;
446
447 protected final long end;
448
449
450
451
452
453 ProviderSpliterator(long start, long end) {
454 position = start;
455 this.end = end;
456 }
457
458
459
460
461 public long estimateSize() {
462 return end - position;
463 }
464
465
466 public int characteristics() {
467 return Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.NONNULL | Spliterator.IMMUTABLE;
468 }
469 }
470
471
472
473
474 static class ProviderSplitsSpliterator extends ProviderSpliterator
475 implements Spliterator<SplittableUniformRandomProvider> {
476
477 private final SplittableUniformRandomProvider source;
478
479 private final SplittableUniformRandomProvider rng;
480
481
482
483
484
485
486
487 ProviderSplitsSpliterator(long start, long end,
488 SplittableUniformRandomProvider source,
489 SplittableUniformRandomProvider rng) {
490 super(start, end);
491 this.source = source;
492 this.rng = rng;
493 }
494
495 @Override
496 public Spliterator<SplittableUniformRandomProvider> trySplit() {
497 final long start = position;
498 final long middle = (start + end) >>> 1;
499 if (middle <= start) {
500 return null;
501 }
502 position = middle;
503 return new ProviderSplitsSpliterator(start, middle, source.split(), rng);
504 }
505
506 @Override
507 public boolean tryAdvance(Consumer<? super SplittableUniformRandomProvider> action) {
508 Objects.requireNonNull(action, NULL_ACTION);
509 final long pos = position;
510 if (pos < end) {
511
512 position = pos + 1;
513 action.accept(rng.split(source));
514 return true;
515 }
516 return false;
517 }
518
519 @Override
520 public void forEachRemaining(Consumer<? super SplittableUniformRandomProvider> action) {
521 Objects.requireNonNull(action, NULL_ACTION);
522 long pos = position;
523 final long last = end;
524 if (pos < last) {
525
526 position = last;
527 final SplittableUniformRandomProvider s = source;
528 final SplittableUniformRandomProvider r = rng;
529 do {
530 action.accept(r.split(s));
531 } while (++pos < last);
532 }
533 }
534 }
535
536
537
538
539 static class ProviderIntsSpliterator extends ProviderSpliterator
540 implements Spliterator.OfInt {
541
542 private final SplittableUniformRandomProvider source;
543
544 private final ToIntFunction<SplittableUniformRandomProvider> gen;
545
546
547
548
549
550
551
552 ProviderIntsSpliterator(long start, long end,
553 SplittableUniformRandomProvider source,
554 ToIntFunction<SplittableUniformRandomProvider> gen) {
555 super(start, end);
556 this.source = source;
557 this.gen = gen;
558 }
559
560 @Override
561 public Spliterator.OfInt trySplit() {
562 final long start = position;
563 final long middle = (start + end) >>> 1;
564 if (middle <= start) {
565 return null;
566 }
567 position = middle;
568 return new ProviderIntsSpliterator(start, middle, source.split(), gen);
569 }
570
571 @Override
572 public boolean tryAdvance(IntConsumer action) {
573 Objects.requireNonNull(action, NULL_ACTION);
574 final long pos = position;
575 if (pos < end) {
576
577 position = pos + 1;
578 action.accept(gen.applyAsInt(source));
579 return true;
580 }
581 return false;
582 }
583
584 @Override
585 public void forEachRemaining(IntConsumer action) {
586 Objects.requireNonNull(action, NULL_ACTION);
587 long pos = position;
588 final long last = end;
589 if (pos < last) {
590
591 position = last;
592 final SplittableUniformRandomProvider s = source;
593 final ToIntFunction<SplittableUniformRandomProvider> g = gen;
594 do {
595 action.accept(g.applyAsInt(s));
596 } while (++pos < last);
597 }
598 }
599 }
600
601
602
603
604 static class ProviderLongsSpliterator extends ProviderSpliterator
605 implements Spliterator.OfLong {
606
607 private final SplittableUniformRandomProvider source;
608
609 private final ToLongFunction<SplittableUniformRandomProvider> gen;
610
611
612
613
614
615
616
617 ProviderLongsSpliterator(long start, long end,
618 SplittableUniformRandomProvider source,
619 ToLongFunction<SplittableUniformRandomProvider> gen) {
620 super(start, end);
621 this.source = source;
622 this.gen = gen;
623 }
624
625 @Override
626 public Spliterator.OfLong trySplit() {
627 final long start = position;
628 final long middle = (start + end) >>> 1;
629 if (middle <= start) {
630 return null;
631 }
632 position = middle;
633 return new ProviderLongsSpliterator(start, middle, source.split(), gen);
634 }
635
636 @Override
637 public boolean tryAdvance(LongConsumer action) {
638 Objects.requireNonNull(action, NULL_ACTION);
639 final long pos = position;
640 if (pos < end) {
641
642 position = pos + 1;
643 action.accept(gen.applyAsLong(source));
644 return true;
645 }
646 return false;
647 }
648
649 @Override
650 public void forEachRemaining(LongConsumer action) {
651 Objects.requireNonNull(action, NULL_ACTION);
652 long pos = position;
653 final long last = end;
654 if (pos < last) {
655
656 position = last;
657 final SplittableUniformRandomProvider s = source;
658 final ToLongFunction<SplittableUniformRandomProvider> g = gen;
659 do {
660 action.accept(g.applyAsLong(s));
661 } while (++pos < last);
662 }
663 }
664 }
665
666
667
668
669 static class ProviderDoublesSpliterator extends ProviderSpliterator
670 implements Spliterator.OfDouble {
671
672 private final SplittableUniformRandomProvider source;
673
674 private final ToDoubleFunction<SplittableUniformRandomProvider> gen;
675
676
677
678
679
680
681
682 ProviderDoublesSpliterator(long start, long end,
683 SplittableUniformRandomProvider source,
684 ToDoubleFunction<SplittableUniformRandomProvider> gen) {
685 super(start, end);
686 this.source = source;
687 this.gen = gen;
688 }
689
690 @Override
691 public Spliterator.OfDouble trySplit() {
692 final long start = position;
693 final long middle = (start + end) >>> 1;
694 if (middle <= start) {
695 return null;
696 }
697 position = middle;
698 return new ProviderDoublesSpliterator(start, middle, source.split(), gen);
699 }
700
701 @Override
702 public boolean tryAdvance(DoubleConsumer action) {
703 Objects.requireNonNull(action, NULL_ACTION);
704 final long pos = position;
705 if (pos < end) {
706
707 position = pos + 1;
708 action.accept(gen.applyAsDouble(source));
709 return true;
710 }
711 return false;
712 }
713
714 @Override
715 public void forEachRemaining(DoubleConsumer action) {
716 Objects.requireNonNull(action, NULL_ACTION);
717 long pos = position;
718 final long last = end;
719 if (pos < last) {
720
721 position = last;
722 final SplittableUniformRandomProvider s = source;
723 final ToDoubleFunction<SplittableUniformRandomProvider> g = gen;
724 do {
725 action.accept(g.applyAsDouble(s));
726 } while (++pos < last);
727 }
728 }
729 }
730 }