1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
#![allow(clippy::module_name_repetitions)]
use crate::ranges::GenerateRange;
use core::mem;
/// This is the trait that all PRNGs must implement.
/// It declares two functions that PRNGs must implement (to generate u32 and u64 random values),
/// and based on these provides implementations of all the other
/// functions supported by the crate.
pub trait Rng {
/// Generates a random u32.
/// Used by other functions as input.
fn random_u32(&mut self) -> u32;
/// Generates a random u64.
/// Used by other functions as input.
fn random_u64(&mut self) -> u64;
/// Generates a single random integer or bool.
///
/// # Arguments
///
/// returns: A random unsigned integer
///
#[inline]
fn random<T>(&mut self) -> T
where
T: ValueFromRng,
Self: Sized,
{
T::value_from_rng(self)
}
/// Generates a single random integer or float in a specified range.
/// The distribution is strictly uniform.
/// The following types are supported:
/// u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
///
/// Any kind of range is supported for integers, but only `Range` for floats.
///
/// # Arguments
///
/// * `range`: The range of the uniform distribution.
///
/// returns: A random value in the range
///
fn range<T>(&mut self, range: impl Into<GenerateRange<T>>) -> T
where
T: RangeFromRng,
Self: Sized,
{
T::range_from_rng(self, range)
}
/// Provides an iterator that emits random values.
///
/// returns: An iterator that outputs random values. Never None.
///
#[inline]
fn iter<T>(&mut self) -> impl Iterator<Item = T>
where
T: ValueFromRng,
Self: Sized,
{
core::iter::from_fn(|| Some(self.random()))
}
/// Fills a mutable slice with random values.
///
/// # Arguments
///
/// * `destination`: The slice to fill
///
#[inline]
fn fill<T>(&mut self, destination: &mut [T])
where
T: ValueFromRng,
Self: Sized,
{
for element in destination {
*element = self.random();
}
}
/// Fills a mutable slice of u8 with random values.
/// Faster than [fill](Self::fill()) for u8 values.
///
/// # Arguments
///
/// * `destination`: The slice to fill
///
#[inline]
fn fill_u8(&mut self, destination: &mut [u8])
where
Self: Sized,
{
let mut blocks = destination.chunks_exact_mut(mem::size_of::<u64>());
for block in blocks.by_ref() {
block.copy_from_slice(&self.random_u64().to_le_bytes());
}
let bytes_remaining = blocks.into_remainder();
if !bytes_remaining.is_empty() {
bytes_remaining
.copy_from_slice(&self.random_u64().to_le_bytes()[..bytes_remaining.len()]);
}
}
/// Shuffles the elements of a slice
///
/// # Arguments
///
/// * `target`: The slice to shuffle
///
#[inline]
fn shuffle<T>(&mut self, target: &mut [T])
where
Self: Sized,
{
// This is the forward version of the Fisher-Yates/Knuth shuffle:
// https://en.wikipedia.org/wiki/Fisher–Yates_shuffle
if !target.is_empty() {
for inx in 0_usize..target.len() - 1 {
// Note: "inx" is part of the range, to allow the current element to be swapped
// with itself. Otherwise, it will always be moved, which would be incorrect.
target.swap(inx, self.range(inx..target.len()));
}
}
}
}
pub trait ValueFromRng {
fn value_from_rng<T: Rng>(entropy_source: &mut T) -> Self;
}
impl ValueFromRng for bool {
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u32() & 1 == 1
}
}
impl ValueFromRng for u8 {
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u32() as Self
}
}
impl ValueFromRng for u16 {
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u32() as Self
}
}
impl ValueFromRng for u32 {
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u32()
}
}
impl ValueFromRng for u64 {
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u64()
}
}
impl ValueFromRng for u128 {
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
(u128::from(rng.random_u64()) << 64) | u128::from(rng.random_u64())
}
}
impl ValueFromRng for usize {
#[cfg(target_pointer_width = "16")]
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u32() as usize
}
#[cfg(target_pointer_width = "32")]
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u32() as usize
}
#[cfg(target_pointer_width = "64")]
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
rng.random_u64() as usize
}
}
// Macro to implement ValueFromRng for signed types based on the unsigned implementations:
macro_rules! value_from_rng_signed {
($output_type: ty, $source_type: ty) => {
impl ValueFromRng for $output_type {
#[inline]
#[allow(clippy::cast_possible_wrap)]
fn value_from_rng<T: Rng>(rng: &mut T) -> Self {
<$source_type>::value_from_rng(rng) as $output_type
}
}
};
}
value_from_rng_signed!(i8, u8);
value_from_rng_signed!(i16, u16);
value_from_rng_signed!(i32, u32);
value_from_rng_signed!(i64, u64);
value_from_rng_signed!(i128, u128);
value_from_rng_signed!(isize, usize);
pub trait RangeFromRng {
fn range_from_rng<T: Rng>(
entropy_source: &mut T,
range: impl Into<GenerateRange<Self>>,
) -> Self
where
Self: Sized;
}
trait ZeroBasedRange {
fn zero_based_range_from_rng(rng: &mut impl Rng, span: Self) -> Self;
}
macro_rules! zero_based_range_from_rng_lemire {
($output_type: ty, $bigger_type: ty) => {
impl ZeroBasedRange for $output_type {
#[inline]
#[allow(clippy::cast_possible_truncation)]
fn zero_based_range_from_rng(rng: &mut impl Rng, span: Self) -> Self {
// Lemire's algorithm (https://lemire.me/blog/2016/06/30/fast-random-shuffling/)
const SIZE_IN_BITS: usize = mem::size_of::<$output_type>() * 8;
let m =
<$bigger_type>::from(rng.random::<$output_type>()) * <$bigger_type>::from(span);
let mut high = (m >> SIZE_IN_BITS) as $output_type;
let mut low = m as $output_type;
if low < span {
let threshold = span.wrapping_neg() % span;
let mut iterations = 0_u32;
while low < threshold {
iterations = iterations.wrapping_add(1);
debug_assert!(
iterations < 128,
"Lemire rejection loop did not terminate: RNG may be broken"
);
let m = <$bigger_type>::from(rng.random::<$output_type>())
* <$bigger_type>::from(span);
high = (m >> SIZE_IN_BITS) as $output_type;
low = m as $output_type;
}
}
high
}
}
};
}
zero_based_range_from_rng_lemire!(u16, u32);
zero_based_range_from_rng_lemire!(u32, u64);
zero_based_range_from_rng_lemire!(u64, u128);
macro_rules! zero_based_range_from_rng {
($output_type: ty) => {
impl ZeroBasedRange for $output_type {
#[inline]
fn zero_based_range_from_rng(rng: &mut impl Rng, span: Self) -> Self {
let mut random_value: Self = rng.random();
let reduced_max = Self::MAX - span + 1;
let max_valid_value = Self::MAX - (reduced_max % span);
while random_value > max_valid_value {
random_value = rng.random();
}
random_value % span
}
}
};
}
// We're using the simpler rejection sampling for u128.
// Lemire gets very complicated for u128 when there is no "u256"
// and the implementation would be virtually untestable.
// Also, the total speed difference on the "bigger" CPUs that are likely to
// need random u128s in a range is not that big (measured to 7% on an M1 for u64)
zero_based_range_from_rng!(u128);
macro_rules! range_from_rng {
($output_type: ty, $unsigned_type: ty, $generate_type: ty) => {
impl RangeFromRng for $output_type {
#[allow(
clippy::cast_possible_truncation,
clippy::cast_sign_loss,
clippy::cast_possible_wrap,
clippy::cast_lossless
)]
fn range_from_rng<T: Rng>(
rng: &mut T,
range: impl Into<GenerateRange<$output_type>>,
) -> Self {
const _: () = {
assert!(mem::size_of::<$generate_type>() >= mem::size_of::<$output_type>());
};
let GenerateRange {
start,
end_inclusive,
} = range.into();
if start == <$output_type>::MIN && end_inclusive == <$output_type>::MAX {
return rng.random::<$generate_type>() as $output_type;
}
assert!(start <= end_inclusive, "Inverted range");
let span = (end_inclusive.wrapping_sub(start).wrapping_add(1)) as $unsigned_type;
if span == 0 {
return start;
}
start.wrapping_add(
(<$generate_type>::zero_based_range_from_rng(rng, span as $generate_type)
as $output_type),
)
}
}
};
}
// We could have used u32 as the generated type here,
// which would probably perform marginally better.
// However, using u16 makes it much easier to test that
// the Lemire algorithm is correct and the distribution uniform.
range_from_rng! {u8, u8, u16}
range_from_rng! {i8, u8, u16}
range_from_rng! {u16, u16, u32}
range_from_rng! {i16, u16, u32}
range_from_rng! {u32, u32, u32}
range_from_rng! {i32, u32, u32}
range_from_rng! {u64, u64, u64}
range_from_rng! {i64, u64, u64}
range_from_rng! {u128, u128, u128}
range_from_rng! {i128, u128, u128}
#[cfg(target_pointer_width = "16")]
range_from_rng! {usize, usize, u32}
#[cfg(target_pointer_width = "32")]
range_from_rng! {usize, usize, u32}
#[cfg(target_pointer_width = "64")]
range_from_rng! {usize, usize, u64}
#[cfg(target_pointer_width = "16")]
range_from_rng! {isize, usize, u32}
#[cfg(target_pointer_width = "32")]
range_from_rng! {isize, usize, u32}
#[cfg(target_pointer_width = "64")]
range_from_rng! {isize, usize, u64}
impl RangeFromRng for f32 {
#[allow(clippy::cast_precision_loss, clippy::cast_possible_truncation)]
fn range_from_rng<T: Rng>(rng: &mut T, range: impl Into<GenerateRange<f32>>) -> Self {
let GenerateRange {
start,
end_inclusive,
} = range.into();
let span = end_inclusive - start;
// The simple algorithm is just to generate an integer of the same size and convert it
// to a float while scaling it. However, this does not utilize the full dynamic range
// of the mantissa when the integer is small. The rand crate seems to do this.
// An ideal algorithm should draw a real number, then round that to the nearest float
// representation, in order to allow all possible float values to be possible outcomes.
// This would be equivalent to drawing an int with virtually infinite size before
// converting to float.
// In practice, we just need enough bits to ensure that the mantissa is fully used.
// A u64 will suffice, unless it has enough leading zero bits that there are less
// than 24 remaining bits (because the mantissa has 23 bits plus an initial implicit 1).
// We thus check the number of leading 0 bits, and draw one more random u64
// to make the integer value u128 if necessary.
// It is theoretically possible that a u128 this still not enough, but the probability
// of that many leading zero bits is more than small enough to ignore.
// Always using u128 would be simpler, but not as fast.
let r = rng.random_u64();
let normalized = if (r >> 23) != 0 {
(r as f32) / 2_f32.powi(64)
} else {
// Make a random u128 by using 64 more random bits.
// Conversion via f64 may seem unnecessary, but going directly to f32
// is not possible without over/underflow problems.
// There are other ways around that, but this branch is not on the hot path
// so simplicity wins here.
let r = (u128::from(r) << 64) | u128::from(rng.random::<u64>());
((r as f64) / 2_f64.powi(128)) as f32
};
normalized * span + start
}
}
impl RangeFromRng for f64 {
#[allow(clippy::cast_precision_loss)]
fn range_from_rng<T: Rng>(rng: &mut T, range: impl Into<GenerateRange<f64>>) -> Self {
let GenerateRange {
start,
end_inclusive: end,
} = range.into();
let span = end - start;
// The simple algorithm is just to generate an integer of the same size and convert it
// to a float while scaling it. However, this does not utilize the full dynamic range
// of the mantissa when the integer is small. The rand crate seems to do this.
// An ideal algorithm should draw a real number, then round that to the nearest float
// representation, in order to allow all possible float values to be possible outcomes.
// This would be equivalent to drawing an int with virtually infinite size before
// converting to float.
// In practice, we just need enough bits to ensure that the mantissa is fully used.
// A u64 will suffice, unless it has enough leading zero bits that there are less
// than 53 remaining bits (because the mantissa has 52 bits plus an initial implicit 1).
// We thus check the number of leading 0 bits, and draw one more random u64
// to make the integer value u128 if necessary.
// It is theoretically possible that a u128 this still not enough, but the probability
// of that many leading zero bits is more than small enough to ignore.
// Always using u128 would be simpler, but not as fast.
let r = rng.random_u64();
let normalized = if (r >> 52) != 0 {
(r as f64) / 2_f64.powi(64)
} else {
// Make a random u128 by using 64 more random bits.
let r = (u128::from(r) << 64) | u128::from(rng.random::<u64>());
(r as f64) / 2_f64.powi(128)
};
normalized * span + start
}
}
#[cfg(test)]
mod tests {
use crate::rng::Rng;
use crate::{SplitMix, Xoshiro256pp};
struct CountingRng(pub u64);
impl CountingRng {
fn new() -> Self {
// Start near the max to ensure that the uniformity tests
// hit the area where numbers must be discarded:
Self(18446744073709550681)
}
}
impl Rng for CountingRng {
fn random_u32(&mut self) -> u32 {
self.random_u64() as u32
}
fn random_u64(&mut self) -> u64 {
let result = self.0;
self.0 = self.0.wrapping_add(1);
result
}
}
#[test]
fn test_range_u8_is_uniform() {
const START: u8 = 13;
const END: u8 = 42;
const LEN: usize = (END - START) as usize;
// u8 ranges are generated from u16 random values.
// If we start the CountingRng at 0 and draw twice as many range values
// as the Lemire algorithm can output for all possible u16 values,
// then we will have tested all possible outcomes, and the distribution
// should be uniform:
let mut rng = CountingRng(0);
let iterations: usize = 2 * ((1 << 16) / LEN) * LEN;
let mut count: [usize; LEN] = [0; LEN];
for _i in 0..iterations {
let value = rng.range(START..END);
assert!(value >= START);
assert!(value < END);
let inx = (value - START) as usize;
count[inx] += 1;
}
for i in 0..LEN {
assert_eq!(count[0], count[i]);
}
}
#[test]
fn test_range_i8_is_uniform() {
const START: i8 = -127;
const END: i8 = 126;
const LEN: usize = ((END as isize) - (START as isize)) as usize;
// i8 ranges are generated from u16 random values.
// If we start the CountingRng at 0 and draw twice as many range values
// as the Lemire algorithm can output for all possible u16 values,
// then we will have tested all possible outcomes, and the distribution
// should be uniform:
let mut rng = CountingRng(0);
let iterations: usize = 2 * ((1 << 16) / LEN) * LEN;
let mut count: [usize; LEN] = [0; LEN];
for _ in 0..iterations {
let value = rng.range(START..END);
assert!(value >= START);
assert!(value < END);
let inx = (value as isize).wrapping_sub(START as isize) as usize;
count[inx] += 1;
}
for i in 0..LEN {
assert_eq!(count[0], count[i]);
}
}
#[test]
fn test_unbounded_range_u8() {
let mut rng = CountingRng::new();
let mut count: [u8; 256] = [0; 256];
for _ in 0..100 * 256 {
let value: u8 = rng.range(..);
count[value as usize] += 1;
}
for i in 0..256 {
assert_eq!(count[0], count[i], "failed for {i}");
}
}
#[test]
fn test_range_boundaries() {
let mut rng = CountingRng::new();
let _: u8 = rng.range(0..=255);
let _: u8 = rng.range(..=255);
assert_eq!(255u8, rng.range(255u8..=255));
assert_eq!(0u8, rng.range(0u8..=0));
}
struct CountingRng128 {
next: u128,
high: bool,
}
impl CountingRng128 {
fn new() -> Self {
// Start near the max to ensure that the uniformity tests
// hit the area where numbers must be discarded:
Self {
next: u128::MAX - 100,
high: true,
}
}
}
impl Rng for CountingRng128 {
fn random_u32(&mut self) -> u32 {
unimplemented!()
}
fn random_u64(&mut self) -> u64 {
let random = if self.high {
(self.next >> 64) as u64
} else {
let low = self.next as u64;
self.next = self.next.wrapping_add(1);
low
};
self.high = !self.high;
random
}
}
#[test]
fn test_range_u128_is_uniform() {
let mut rng = CountingRng128::new();
const START: u128 = 13;
const END: u128 = 42;
const LEN: usize = (END - START) as usize;
let mut count: [u8; LEN] = [0; LEN];
for _ in 0..100 * LEN {
let value = rng.range(START..END);
assert!(value >= START);
assert!(value < END);
let inx = (value - START) as usize;
count[inx] += 1;
}
for i in 0..LEN {
assert_eq!(count[0], count[i]);
}
}
struct FloatRangeGenerator(u128);
impl FloatRangeGenerator {
fn new(leading_zeros: usize) -> Self {
Self(
((1_u128 << 127) >> leading_zeros)
| (0xDEADBEEFDEADBEEF0000000000000000_u128 >> (leading_zeros + 1)),
)
}
}
impl Rng for FloatRangeGenerator {
fn random_u32(&mut self) -> u32 {
0
}
fn random_u64(&mut self) -> u64 {
let random = self.0 >> 64;
self.0 = self.0 << 64;
random as u64
}
}
#[test]
fn test_float_ranges_f64() {
for leading_zeros in 0..64 {
let mut rng = FloatRangeGenerator::new(leading_zeros);
let value: f64 = rng.range(0.0..1.0);
// The algorithm should always fill the mantissa, so the (slightly modified)
// "DEADBEEF" pattern should always be in the same place:
let bytes = value.to_ne_bytes();
assert_eq!(bytes[5], 0xea);
assert_eq!(bytes[4], 0xdb);
assert_eq!(bytes[3], 0xee);
assert_eq!(bytes[2], 0xfd);
assert_eq!(bytes[1], 0xea);
// The exponent is a function of the number of leading zero bits:
let exponent = u64::from_be_bytes(value.to_be_bytes()) >> 52;
assert_eq!(exponent as usize, 1022 - leading_zeros);
}
}
#[test]
fn test_float_ranges_f32() {
for leading_zeros in 0..64 {
let mut rng = FloatRangeGenerator::new(leading_zeros);
let value: f32 = rng.range(0.0..1.0);
// The algorithm should always fill the mantissa,
// so the mantissa should always be the same with this generator:
let bytes = value.to_ne_bytes();
assert_eq!(bytes[0], 223);
assert_eq!(bytes[1], 86);
// The exponent is a function of the number of leading zero bits:
let exponent = u32::from_be_bytes(value.to_be_bytes()) >> 23;
assert_eq!(exponent as usize, 126 - leading_zeros);
}
}
#[test]
fn test_shuffle() {
let mut rng = Xoshiro256pp::from_entropy(&mut SplitMix::new(42));
let mut numbers = vec![
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
];
rng.shuffle(&mut numbers);
assert_eq!(
numbers,
vec![17, 8, 20, 15, 1, 14, 2, 4, 11, 3, 16, 19, 18, 6, 5, 13, 7, 9, 10, 12]
);
}
#[test]
fn test_shuffle_empty_slice() {
let mut rng = CountingRng::new();
let mut numbers: Vec<u8> = vec![];
rng.shuffle(&mut numbers);
assert_eq!(numbers, vec![]);
}
}