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