1use rand::RngCore;
7use rand::SeedableRng;
8use rand_pcg::Pcg64Mcg;
9
10#[derive(Clone, Debug)]
15pub struct Rng {
16 inner: Pcg64Mcg,
17}
18
19impl Rng {
20 pub fn new(seed: u64) -> Self {
22 Self {
23 inner: Pcg64Mcg::seed_from_u64(seed),
24 }
25 }
26
27 pub fn next_u64(&mut self) -> u64 {
29 self.inner.next_u64()
30 }
31
32 pub fn next_usize(&mut self, bound: usize) -> usize {
37 if bound <= 1 {
38 return 0;
39 }
40 ((self.next_u64() as u128 * bound as u128) >> 64) as usize
41 }
42
43 pub fn next_f64(&mut self) -> f64 {
45 (self.next_u64() >> 11) as f64 * (1.0 / 9007199254740992.0)
47 }
48
49 pub fn fork(&mut self) -> Self {
52 Self::new(self.next_u64())
53 }
54}
55
56#[cfg(test)]
57mod tests {
58 use super::*;
59
60 #[test]
61 fn test_deterministic() {
62 let mut a = Rng::new(42);
63 let mut b = Rng::new(42);
64 for _ in 0..100 {
65 assert_eq!(a.next_u64(), b.next_u64());
66 }
67 }
68
69 #[test]
70 fn test_fork_differs() {
71 let mut parent = Rng::new(42);
72 let mut child = parent.fork();
73 assert_ne!(parent.next_u64(), child.next_u64());
75 }
76
77 #[test]
78 fn test_next_usize_bounded() {
79 let mut rng = Rng::new(0);
80 for _ in 0..1000 {
81 let v = rng.next_usize(10);
82 assert!(v < 10, "value {v} out of range");
83 }
84 }
85
86 #[test]
87 fn test_next_f64_range() {
88 let mut rng = Rng::new(1);
89 for _ in 0..1000 {
90 let v = rng.next_f64();
91 assert!((0.0..1.0).contains(&v), "value {v} out of [0,1)");
92 }
93 }
94}