1use super::Rng;
36
37#[derive(Debug, Clone, Default)]
41pub(super) struct PackedBits {
42 pub(super) acc: u64,
43 pub(super) bits: u32,
44}
45
46impl PackedBits {
47 pub(super) fn push(&mut self, value: u32, width: u32) {
48 debug_assert!((1..=32).contains(&width));
49 let masked = if width == 32 {
50 u64::from(value)
51 } else {
52 u64::from(value) & ((1u64 << width) - 1)
53 };
54 self.acc |= masked << self.bits;
55 self.bits += width;
56 }
57
58 pub(super) fn pop_word(&mut self) -> u32 {
59 debug_assert!(self.bits >= 32);
60 let out = self.acc as u32;
61 self.acc >>= 32;
62 self.bits -= 32;
63 out
64 }
65}
66
67fn park_miller31(seed: u32) -> u32 {
68 let mut x = if seed == 0 { 1i64 } else { i64::from(seed) };
69 let hi = x / 127_773;
70 let lo = x % 127_773;
71 x = 16_807 * lo - 2_836 * hi;
72 if x < 0 {
73 x += 2_147_483_647;
74 }
75 x as u32
76}
77
78#[derive(Debug, Clone)]
87pub struct SystemVRand {
88 state: u32,
89 bits: PackedBits,
90}
91
92impl SystemVRand {
93 pub fn new(seed: u32) -> Self {
94 Self {
95 state: seed,
96 bits: PackedBits::default(),
97 }
98 }
99
100 pub fn next_raw(&mut self) -> u32 {
101 self.state = self.state.wrapping_mul(1_103_515_245).wrapping_add(12_345);
102 (self.state >> 16) & 0x7fff
103 }
104}
105
106impl Rng for SystemVRand {
107 fn next_u32(&mut self) -> u32 {
108 while self.bits.bits < 32 {
109 let raw = self.next_raw();
110 self.bits.push(raw, 15);
111 }
112 self.bits.pop_word()
113 }
114}
115
116pub type CRand = SystemVRand;
118
119#[derive(Debug, Clone)]
128pub struct WindowsMsvcRand {
129 state: u32,
130 bits: PackedBits,
131}
132
133impl WindowsMsvcRand {
134 pub fn new(seed: u32) -> Self {
135 Self {
136 state: seed,
137 bits: PackedBits::default(),
138 }
139 }
140
141 pub fn next_raw(&mut self) -> u32 {
142 self.state = self.state.wrapping_mul(214_013).wrapping_add(2_531_011);
143 (self.state >> 16) & 0x7fff
144 }
145}
146
147impl Rng for WindowsMsvcRand {
148 fn next_u32(&mut self) -> u32 {
149 while self.bits.bits < 32 {
150 let raw = self.next_raw();
151 self.bits.push(raw, 15);
152 }
153 self.bits.pop_word()
154 }
155}
156
157#[derive(Debug, Clone)]
168pub struct WindowsVb6Rnd {
169 state: u32,
170 bits: PackedBits,
171}
172
173impl WindowsVb6Rnd {
174 pub fn new(seed: u32) -> Self {
175 Self {
176 state: seed & 0x00ff_ffff,
177 bits: PackedBits::default(),
178 }
179 }
180
181 pub fn next_raw(&mut self) -> u32 {
182 self.state = self
183 .state
184 .wrapping_mul(0x43fd_43fd)
185 .wrapping_add(0x00c3_9ec3)
186 & 0x00ff_ffff;
187 self.state
188 }
189
190 pub fn next_sample(&mut self) -> f64 {
191 self.next_raw() as f64 * (1.0 / 16_777_216.0)
192 }
193}
194
195impl Rng for WindowsVb6Rnd {
196 fn next_u32(&mut self) -> u32 {
197 while self.bits.bits < 32 {
198 let raw = self.next_raw();
199 self.bits.push(raw, 24);
200 }
201 self.bits.pop_word()
202 }
203
204 fn next_f64(&mut self) -> f64 {
205 self.next_sample()
206 }
207}
208
209#[derive(Debug, Clone)]
216pub struct WindowsDotNetRandom {
217 seed_array: [i32; 56],
218 inext: usize,
219 inextp: usize,
220 bits: PackedBits,
221}
222
223impl WindowsDotNetRandom {
224 pub fn new(seed: i32) -> Self {
225 let mut seed_array = [0i32; 56];
226 let subtraction = if seed == i32::MIN {
227 i32::MAX
228 } else {
229 seed.abs()
230 };
231 let mut mj = 161_803_398 - subtraction;
232 seed_array[55] = mj;
233 let mut mk = 1i32;
234 let mut ii = 0usize;
235 for _i in 1..55 {
236 ii += 21;
237 if ii >= 55 {
238 ii -= 55;
239 }
240 seed_array[ii] = mk;
241 mk = mj - mk;
242 if mk < 0 {
243 mk += i32::MAX;
244 }
245 mj = seed_array[ii];
246 }
247
248 for _ in 1..5 {
249 for i in 1..56 {
250 let mut n = i + 30;
251 if n >= 55 {
252 n -= 55;
253 }
254 seed_array[i] -= seed_array[1 + n];
255 if seed_array[i] < 0 {
256 seed_array[i] += i32::MAX;
257 }
258 }
259 }
260
261 Self {
262 seed_array,
263 inext: 0,
264 inextp: 21,
265 bits: PackedBits::default(),
266 }
267 }
268
269 pub fn next_raw(&mut self) -> u32 {
270 self.inext += 1;
271 if self.inext >= 56 {
272 self.inext = 1;
273 }
274
275 self.inextp += 1;
276 if self.inextp >= 56 {
277 self.inextp = 1;
278 }
279
280 let mut ret = self.seed_array[self.inext] - self.seed_array[self.inextp];
281 if ret == i32::MAX {
282 ret -= 1;
283 }
284 if ret < 0 {
285 ret += i32::MAX;
286 }
287
288 self.seed_array[self.inext] = ret;
289 ret as u32
290 }
291
292 pub fn next_sample(&mut self) -> f64 {
293 self.next_raw() as f64 * (1.0 / i32::MAX as f64)
294 }
295}
296
297impl Rng for WindowsDotNetRandom {
298 fn next_u32(&mut self) -> u32 {
299 while self.bits.bits < 32 {
300 let raw = self.next_raw();
301 self.bits.push(raw, 31);
302 }
303 self.bits.pop_word()
304 }
305
306 fn next_f64(&mut self) -> f64 {
307 self.next_sample()
308 }
309}
310
311#[derive(Debug, Clone)]
319pub struct BsdRandom {
320 state: [u32; 31],
321 fptr: usize,
322 rptr: usize,
323 bits: PackedBits,
324}
325
326impl BsdRandom {
327 pub fn new(seed: u32) -> Self {
328 let seed = if seed == 0 { 1 } else { seed };
329 let mut state = [0u32; 31];
330 state[0] = seed;
331 for i in 1..31 {
332 state[i] = park_miller31(state[i - 1]);
333 }
334
335 let mut rng = Self {
336 state,
337 fptr: 3,
338 rptr: 0,
339 bits: PackedBits::default(),
340 };
341
342 for _ in 0..310 {
343 let _ = rng.next_raw();
344 }
345
346 rng
347 }
348
349 pub fn next_raw(&mut self) -> u32 {
350 let val = self.state[self.fptr].wrapping_add(self.state[self.rptr]);
351 self.state[self.fptr] = val;
352 let out = val >> 1;
353
354 self.fptr += 1;
355 if self.fptr == self.state.len() {
356 self.fptr = 0;
357 }
358
359 self.rptr += 1;
360 if self.rptr == self.state.len() {
361 self.rptr = 0;
362 }
363
364 out
365 }
366}
367
368impl Rng for BsdRandom {
369 fn next_u32(&mut self) -> u32 {
370 while self.bits.bits < 32 {
371 let raw = self.next_raw();
372 self.bits.push(raw, 31);
373 }
374 self.bits.pop_word()
375 }
376}
377
378pub type LinuxLibcRandom = BsdRandom;
384
385#[derive(Debug, Clone)]
392pub struct BsdRandCompat {
393 state: u32,
394 bits: PackedBits,
395}
396
397impl BsdRandCompat {
398 pub fn new(seed: u32) -> Self {
399 Self {
400 state: seed,
401 bits: PackedBits::default(),
402 }
403 }
404
405 pub fn next_raw(&mut self) -> u32 {
406 let x = (u64::from(self.state) % 0x7fff_fffe) + 1;
407 let hi = x / 127_773;
408 let lo = x % 127_773;
409 let mut next = 16_807i64 * lo as i64 - 2_836i64 * hi as i64;
410 if next < 0 {
411 next += 2_147_483_647;
412 }
413 let out = (next as u32).wrapping_sub(1);
414 self.state = out;
415 out
416 }
417}
418
419impl Rng for BsdRandCompat {
420 fn next_u32(&mut self) -> u32 {
421 while self.bits.bits < 32 {
422 let raw = self.next_raw();
423 self.bits.push(raw, 31);
424 }
425 self.bits.pop_word()
426 }
427}
428
429#[derive(Debug, Clone)]
437pub struct Rand48 {
438 state: u64,
439}
440
441const RAND48_A: u64 = 0x5DEECE66D;
442const RAND48_C: u64 = 0xB;
443const RAND48_M: u64 = 1 << 48;
444
445impl Rand48 {
446 pub fn new(seed: u64) -> Self {
447 Self {
448 state: (seed << 16) | 0x330E,
449 }
450 }
451}
452
453impl Rng for Rand48 {
454 fn next_u32(&mut self) -> u32 {
455 self.state = (RAND48_A.wrapping_mul(self.state).wrapping_add(RAND48_C)) % RAND48_M;
456 (self.state >> 16) as u32
457 }
458}
459
460#[cfg(test)]
461mod tests {
462 use super::{
463 BsdRandCompat, BsdRandom, LinuxLibcRandom, Rand48, SystemVRand, WindowsDotNetRandom,
464 WindowsMsvcRand, WindowsVb6Rnd,
465 };
466 use crate::rng::Rng;
467
468 #[test]
469 fn system_v_rand_raw_matches_posix_sample() {
470 let mut rng = SystemVRand::new(1);
471 let expected = [16838, 5758, 10113, 17515, 31051];
472 for want in expected {
473 assert_eq!(rng.next_raw(), want);
474 }
475 }
476
477 #[test]
478 fn bsd_random_matches_well_known_seed_1_prefix() {
479 let mut rng = BsdRandom::new(1);
480 let expected = [
481 1_804_289_383,
482 846_930_886,
483 1_681_692_777,
484 1_714_636_915,
485 1_957_747_793,
486 ];
487 for want in expected {
488 assert_eq!(rng.next_raw(), want);
489 }
490 }
491
492 #[test]
493 fn linux_glibc_rand_alias_matches_random() {
494 let mut linux = LinuxLibcRandom::new(1);
495 let mut bsd = BsdRandom::new(1);
496 for _ in 0..8 {
497 assert_eq!(linux.next_u32(), bsd.next_u32());
498 }
499 }
500
501 #[test]
502 fn freebsd_compat_rand_r_prefix_matches_reference_math() {
503 let mut rng = BsdRandCompat::new(1);
504 let expected = [33_613, 564_950_497, 1_097_816_498, 1_969_887_315];
505 for want in expected {
506 assert_eq!(rng.next_raw(), want);
507 }
508 }
509
510 #[test]
511 fn rand48_produces_non_constant_output() {
512 let mut rng = Rand48::new(1);
513 let a = rng.next_u32();
514 let b = rng.next_u32();
515 assert_ne!(a, b);
516 }
517
518 #[test]
519 fn windows_msvc_rand_matches_known_seed_1_prefix() {
520 let mut rng = WindowsMsvcRand::new(1);
521 let expected = [41, 18_467, 6_334, 26_500, 19_169];
522 for want in expected {
523 assert_eq!(rng.next_raw(), want);
524 }
525 }
526
527 #[test]
528 fn windows_vb6_rnd_matches_known_seed_1_prefix() {
529 let mut rng = WindowsVb6Rnd::new(1);
530 let expected = [12_640_960, 8_124_035, 4_294_458, 3_961_109, 14_212_996];
531 for want in expected {
532 assert_eq!(rng.next_raw(), want);
533 }
534 }
535
536 #[test]
537 fn windows_dotnet_random_matches_seed_1_prefix() {
538 let mut rng = WindowsDotNetRandom::new(1);
539 let expected = [
540 534_011_718,
541 237_820_880,
542 1_002_897_798,
543 1_657_007_234,
544 1_412_011_072,
545 ];
546 for want in expected {
547 assert_eq!(rng.next_raw(), want);
548 }
549 }
550}