ferray_random/bitgen/
pcg64.rs1use super::BitGenerator;
7
8pub struct Pcg64 {
22 state: u128,
23 inc: u128,
24}
25
26const PCG_DEFAULT_MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645;
28
29impl Pcg64 {
30 #[inline]
32 fn step(&mut self) {
33 self.state = self
34 .state
35 .wrapping_mul(PCG_DEFAULT_MULTIPLIER)
36 .wrapping_add(self.inc);
37 }
38
39 #[inline]
41 fn output(state: u128) -> u64 {
42 let xsl = ((state >> 64) ^ state) as u64;
43 let rot = (state >> 122) as u32;
44 xsl.rotate_right(rot)
45 }
46}
47
48impl BitGenerator for Pcg64 {
49 fn next_u64(&mut self) -> u64 {
50 let old_state = self.state;
51 self.step();
52 Self::output(old_state)
53 }
54
55 fn seed_from_u64(seed: u64) -> Self {
56 let seed128 = {
58 let mut s = seed;
59 let a = splitmix64_step(&mut s);
60 let b = splitmix64_step(&mut s);
61 ((a as u128) << 64) | (b as u128)
62 };
63 let inc = {
65 let mut s = seed.wrapping_add(0xda3e39cb94b95bdb);
66 let a = splitmix64_step(&mut s);
67 let b = splitmix64_step(&mut s);
68 (((a as u128) << 64) | (b as u128)) | 1
69 };
70
71 let mut rng = Pcg64 { state: 0, inc };
72 rng.step();
73 rng.state = rng.state.wrapping_add(seed128);
74 rng.step();
75 rng
76 }
77
78 fn jump(&mut self) -> Option<()> {
79 None
81 }
82
83 fn stream(_seed: u64, _stream_id: u64) -> Option<Self> {
84 None
86 }
87}
88
89fn splitmix64_step(state: &mut u64) -> u64 {
91 *state = state.wrapping_add(0x9e3779b97f4a7c15);
92 let mut z = *state;
93 z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
94 z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
95 z ^ (z >> 31)
96}
97
98impl Clone for Pcg64 {
99 fn clone(&self) -> Self {
100 Self {
101 state: self.state,
102 inc: self.inc,
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn deterministic_output() {
113 let mut rng1 = Pcg64::seed_from_u64(42);
114 let mut rng2 = Pcg64::seed_from_u64(42);
115 for _ in 0..1000 {
116 assert_eq!(rng1.next_u64(), rng2.next_u64());
117 }
118 }
119
120 #[test]
121 fn different_seeds_differ() {
122 let mut rng1 = Pcg64::seed_from_u64(42);
123 let mut rng2 = Pcg64::seed_from_u64(43);
124 let mut same = true;
125 for _ in 0..100 {
126 if rng1.next_u64() != rng2.next_u64() {
127 same = false;
128 break;
129 }
130 }
131 assert!(!same);
132 }
133
134 #[test]
135 fn jump_not_supported() {
136 let mut rng = Pcg64::seed_from_u64(42);
137 assert!(rng.jump().is_none());
138 }
139
140 #[test]
141 fn stream_not_supported() {
142 assert!(Pcg64::stream(42, 0).is_none());
143 }
144
145 #[test]
146 fn output_covers_full_range() {
147 let mut rng = Pcg64::seed_from_u64(12345);
148 let mut seen_high = false;
149 let mut seen_low = false;
150 for _ in 0..10_000 {
151 let v = rng.next_u64();
152 if v > (u64::MAX / 2) {
153 seen_high = true;
154 } else {
155 seen_low = true;
156 }
157 if seen_high && seen_low {
158 break;
159 }
160 }
161 assert!(seen_high && seen_low);
162 }
163}