|
1 pub struct LaggedFibonacciPRNG { |
|
2 circular_buffer: [u32; 64], |
|
3 index: usize, |
|
4 } |
|
5 |
|
6 impl LaggedFibonacciPRNG { |
|
7 pub fn new(init_values: &[u8]) -> Self { |
|
8 let mut buf = [0xa98765 + 68; 64]; |
|
9 |
|
10 for i in 0..std::cmp::min(init_values.len(), 54) { |
|
11 buf[i] = init_values[i] as u32; |
|
12 } |
|
13 |
|
14 let mut prng = Self { |
|
15 circular_buffer: buf, |
|
16 index: 54, |
|
17 }; |
|
18 |
|
19 prng.discard(2048); |
|
20 |
|
21 prng |
|
22 } |
|
23 |
|
24 #[inline] |
|
25 pub fn discard(&mut self, count: usize) { |
|
26 for _i in 0..count { |
|
27 self.get_next(); |
|
28 } |
|
29 } |
|
30 |
|
31 #[inline] |
|
32 fn get_next(&mut self) -> u32 { |
|
33 self.index = (self.index + 1) & 0x3f; |
|
34 self.circular_buffer[self.index] = (self.circular_buffer[(self.index + 40) & 0x3f] |
|
35 + self.circular_buffer[(self.index + 9) & 0x3f]) |
|
36 & 0x7fffffff; |
|
37 |
|
38 self.circular_buffer[self.index] |
|
39 } |
|
40 |
|
41 #[inline] |
|
42 pub fn get_random(&mut self, modulo: u32) -> u32 { |
|
43 self.get_next(); |
|
44 self.get_next() % modulo |
|
45 } |
|
46 |
|
47 #[inline] |
|
48 pub fn add_randomness(&mut self, value: u32) { |
|
49 self.index = (self.index + 1) & 0x3f; |
|
50 self.circular_buffer[self.index] ^= value; |
|
51 } |
|
52 } |
|
53 |
|
54 impl Iterator for LaggedFibonacciPRNG { |
|
55 type Item = u32; |
|
56 |
|
57 fn next(&mut self) -> Option<Self::Item> { |
|
58 self.get_next(); |
|
59 Some(self.get_next()) |
|
60 } |
|
61 } |
|
62 |
|
63 #[cfg(test)] |
|
64 #[test] |
|
65 fn compatibility() { |
|
66 let mut prng = LaggedFibonacciPRNG::new("{052e2aee-ce41-4720-97bd-559a413bf866}".as_bytes()); |
|
67 |
|
68 assert_eq!(prng.get_random(1000), 418); |
|
69 assert_eq!(prng.get_random(1000000), 554064); |
|
70 assert_eq!(prng.get_random(0xffffffff), 239515837); |
|
71 |
|
72 prng.add_randomness(123); |
|
73 |
|
74 for i in 0..=100000 { |
|
75 prng.get_random(2); |
|
76 } |
|
77 |
|
78 assert_eq!(prng.get_random(0xffffffff), 525333582); |
|
79 } |