1use core::ops::{BitXor, BitXorAssign};
10use irox_bits::MutBits;
11
12const DEFAULT_STATE: u64 = 0x4d595df4d0f33173u64;
14
15const MULTIPLIER: u64 = 6364136223846793005u64;
17
18const INCREMENT: u64 = 1442695040888963407u64;
20
21const MULTIPLIER_128: u128 = 0x2360ED051FC65DA44385DF649FCCF645u128;
22const INCREMENT_128: u128 = 0x5851F42D4C957F2D14057B7EF767814Fu128;
23
24pub type Random = PcgXshRR;
25pub struct PcgXshRR {
28 state: u64,
29}
30
31impl PcgXshRR {
32 pub fn new_seed(seed: u64) -> Self {
35 Self {
36 state: seed.wrapping_mul(2).wrapping_add(1),
37 }
38 }
39}
40
41impl PRNG for PcgXshRR {
42 fn next_u32(&mut self) -> u32 {
45 let count = (self.state >> 59) as u32;
47 let mut x = self.state;
48 self.state = x.wrapping_mul(MULTIPLIER).wrapping_add(INCREMENT);
49 x.bitxor_assign(x >> 18);
50 let x = (x >> 27) as u32;
51 x.rotate_right(count)
52 }
53}
54
55pub struct PcgXshRs {
59 state: u64,
60}
61
62impl PcgXshRs {
63 pub fn new_seed(seed: u64) -> Self {
66 Self {
67 state: seed.wrapping_mul(2).wrapping_add(1),
68 }
69 }
70}
71
72impl PRNG for PcgXshRs {
73 fn next_u32(&mut self) -> u32 {
74 let state = self.state;
75 self.state = state.wrapping_mul(MULTIPLIER).wrapping_add(INCREMENT);
76 let shift = 22 + (state >> 61);
77
78 (state.bitxor(state >> 22) >> shift) as u32
79 }
80}
81
82pub struct PcgRxsMXs64 {
85 state: u64,
86}
87
88impl PcgRxsMXs64 {
89 pub fn new_seed(seed: u64) -> Self {
92 Self {
93 state: seed.wrapping_mul(2).wrapping_add(1),
94 }
95 }
96}
97
98impl PRNG for PcgRxsMXs64 {
99 fn next_u32(&mut self) -> u32 {
100 self.next_u64() as u32
101 }
102
103 fn next_u64(&mut self) -> u64 {
104 let state = self.state;
105 self.state = state.wrapping_mul(MULTIPLIER).wrapping_add(INCREMENT);
106 let word = ((state >> ((state >> 59).wrapping_add(5))) ^ state)
107 .wrapping_mul(12605985483714917081u64);
108 (word >> 43) ^ word
109 }
110}
111
112pub struct PcgXslRrRr {
115 state: u128,
116}
117impl PcgXslRrRr {
118 pub fn new_seed(seed: u128) -> Self {
121 Self {
122 state: seed.wrapping_mul(2).wrapping_add(1),
123 }
124 }
125}
126
127impl PRNG for PcgXslRrRr {
128 fn next_u32(&mut self) -> u32 {
129 self.next_u128() as u32
130 }
131
132 fn next_u128(&mut self) -> u128 {
133 let state = self.state;
134 self.state = state
135 .wrapping_mul(MULTIPLIER_128)
136 .wrapping_add(INCREMENT_128);
137 let rot1 = (state >> 122) as u32;
138 let high = (state >> 64) as u64;
139 let newlow = (high ^ state as u64).rotate_right(rot1);
140 let newhigh = high.rotate_right((newlow & 0x3F) as u32);
141 ((newhigh as u128) << 64) | newlow as u128
142 }
143}
144
145pub struct PcgMcgXslRr {
146 state: u128,
147}
148impl PcgMcgXslRr {
149 pub fn new_seed(seed: u128) -> Self {
150 Self {
151 state: seed.wrapping_mul(2).wrapping_add(1),
152 }
153 }
154}
155impl PRNG for PcgMcgXslRr {
156 fn next_u32(&mut self) -> u32 {
157 self.next_u64() as u32
158 }
159
160 fn next_u64(&mut self) -> u64 {
161 let state = self.state.wrapping_mul(MULTIPLIER_128);
162 self.state = state;
163 let rot = (state >> 122) as u32;
164 ((state >> 64) as u64)
165 .bitxor(state as u64)
166 .rotate_right(rot)
167 }
168}
169
170pub trait PRNG {
171 fn next_u32(&mut self) -> u32;
174 fn next_u8(&mut self) -> u8 {
177 self.next_u32() as u8
178 }
179 fn next_u16(&mut self) -> u16 {
182 self.next_u32() as u16
183 }
184 fn next_u64(&mut self) -> u64 {
187 let a: u64 = self.next_u32() as u64;
188 let b: u64 = self.next_u32() as u64;
189 (a << 32) | b
190 }
191 fn next_u128(&mut self) -> u128 {
194 let a: u128 = self.next_u64() as u128;
195 let b: u128 = self.next_u64() as u128;
196 (a << 64) | b
197 }
198 fn next_f32(&mut self) -> f32 {
201 f32::from_bits(self.next_u32())
202 }
203 fn next_f64(&mut self) -> f64 {
206 f64::from_bits(self.next_u64())
207 }
208
209 fn fill(&mut self, mut data: &mut [u8]) {
210 while !data.is_empty() {
211 let val = self.next_u64().to_ne_bytes();
212 for v in val {
213 if data.write_u8(v).is_err() {
214 return;
215 }
216 }
217 }
218 }
219
220 fn next_unit_f64(&mut self) -> f64 {
223 self.next_u64() as f64 / u64::MAX as f64
224 }
225 fn next_in_range(&mut self, min: f64, max: f64) -> f64 {
228 let off = (max - min) * self.next_unit_f64();
229 min + off
230 }
231 fn next_in_distribution(&mut self, center: f64, range: f64) -> f64 {
234 let off = (self.next_unit_f64() - 0.5) * range;
235 center + off
236 }
237
238 fn unbiased_next_u32(&mut self, max: u32) -> u32 {
241 if max.is_power_of_two() {
242 return self.next_u32() & (max - 1);
243 }
244 let lim = (1 << 31) - 1 - (1 << 31) % max;
245 let mut v = self.next_u32();
246 while v > lim {
247 v = self.next_u32();
248 }
249 v % max
250 }
251 fn unbiased_next_u64(&mut self, max: u64) -> u64 {
254 if max.is_power_of_two() {
255 return self.next_u64() & (max - 1);
256 }
257 let lim = (1 << 63) - 1 - (1 << 63) % max;
258 let mut v = self.next_u64();
259 while v > lim {
260 v = self.next_u64();
261 }
262 v % max
263 }
264}
265
266#[cfg(feature = "std")]
267impl Default for Random {
268 fn default() -> Self {
269 let seed = match std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH) {
270 Ok(e) => e.as_nanos() as u64,
271 Err(_) => DEFAULT_STATE,
272 };
273 Random::new_seed(seed)
274 }
275}
276#[cfg(not(feature = "std"))]
277impl Default for Random {
278 fn default() -> Self {
279 Random::new_seed(DEFAULT_STATE)
280 }
281}
282
283#[cfg(all(test, feature = "std"))]
284mod tests {
285 #![allow(clippy::all)]
286 use crate::random::{PcgRxsMXs64, PcgXslRrRr, PRNG};
287
288 pub fn speedtest_128() -> f64 {
291 let mut rand = PcgXslRrRr::new_seed(0);
292 let start = std::time::Instant::now();
293 let todo = 100_000_000;
294 core::hint::black_box({
295 let mut _v = 0;
296 for _i in 0..todo {
297 _v = rand.next_u128();
298 _v = rand.next_u128();
299 _v = rand.next_u128();
300 _v = rand.next_u128();
301 _v = rand.next_u128();
302 _v = rand.next_u128();
303 _v = rand.next_u128();
304 _v = rand.next_u128();
305 }
306 });
307 let elapsed = start.elapsed().as_secs_f64();
308 let did = todo as f64 * 128. / 1e6;
309 println!("Did {} MB/s", did / elapsed);
310 did
311 }
312 #[allow(unused)]
313 pub fn speedtest_64() -> f64 {
314 let mut rand = PcgRxsMXs64::new_seed(0);
315 let start = std::time::Instant::now();
316 let todo = 1_000_000;
317 core::hint::black_box({
318 let mut _v = 0;
319 for _i in 0..todo {
320 _v = rand.next_u64();
321 _v = rand.next_u64();
322 _v = rand.next_u64();
323 _v = rand.next_u64();
324 _v = rand.next_u64();
325 _v = rand.next_u64();
326 _v = rand.next_u64();
327 _v = rand.next_u64();
328 }
329 });
330 let elapsed = start.elapsed().as_secs_f64();
331 let did = todo as f64 * 64. / 1e6;
332 println!("Did {} MB/s", did / elapsed);
333 did
334 }
335
336 #[test]
337 #[ignore]
338 pub fn multi_speedtest() {
339 let core_ids = core_affinity::get_core_ids().unwrap_or_default();
340 let start = std::time::Instant::now();
341 let mut handles = core_ids
342 .into_iter()
343 .map(|id| {
344 std::thread::spawn(move || {
345 let _val = core_affinity::set_for_current(id);
346 speedtest_128()
347 })
348 })
349 .collect::<Vec<_>>();
350
351 let did: f64 = handles
352 .drain(..)
353 .map(|v| v.join().unwrap_or_default())
354 .sum();
355 let elapsed = start.elapsed().as_secs_f64();
356 println!("Did {} MB/s", did / elapsed);
357 }
358}