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
//! A tiny deterministic PRNG (SplitMix64).
//!
//! Dependency-free and good enough for bootstrap sampling and shuffling a
//! search space — not for anything cryptographic.
/// A SplitMix64 pseudo-random generator.
#[derive(Clone, Debug)]
pub struct Rng {
state: u64,
}
impl Rng {
/// Seed the generator.
pub fn new(seed: u64) -> Self {
Rng { state: seed }
}
/// Next raw 64-bit value.
pub fn next_u64(&mut self) -> u64 {
self.state = self.state.wrapping_add(0x9E37_79B9_7F4A_7C15);
let mut z = self.state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
z ^ (z >> 31)
}
/// A uniform index in `0..n` (panics if `n == 0`).
pub fn below(&mut self, n: usize) -> usize {
(self.next_u64() % n as u64) as usize
}
/// Fisher–Yates shuffle in place.
pub fn shuffle<T>(&mut self, xs: &mut [T]) {
for i in (1..xs.len()).rev() {
let j = self.below(i + 1);
xs.swap(i, j);
}
}
}