equal
deleted
inserted
replaced
|
1 use rand::{Error, RngCore, SeedableRng}; |
|
2 |
1 pub struct LaggedFibonacciPRNG { |
3 pub struct LaggedFibonacciPRNG { |
2 circular_buffer: [u32; 64], |
4 circular_buffer: [u32; 64], |
3 index: usize, |
5 index: usize, |
4 } |
6 } |
5 |
7 |
6 impl LaggedFibonacciPRNG { |
8 impl LaggedFibonacciPRNG { |
7 pub fn new(init_values: &[u8]) -> Self { |
9 pub fn new(init_values: &[u8]) -> Self { |
8 let mut buf = [0xa98765 + 68; 64]; |
10 let mut buf = [0xa98765; 64]; |
9 |
11 |
10 for i in 0..std::cmp::min(init_values.len(), 54) { |
12 for i in 0..std::cmp::min(init_values.len(), 54) { |
11 buf[i] = init_values[i] as u32; |
13 buf[i] = init_values[i] as u32; |
12 } |
14 } |
13 |
15 |
28 } |
30 } |
29 } |
31 } |
30 |
32 |
31 #[inline] |
33 #[inline] |
32 fn get_next(&mut self) -> u32 { |
34 fn get_next(&mut self) -> u32 { |
|
35 const PRIME_NUM: u32 = 2147483629; |
|
36 |
33 self.index = (self.index + 1) & 0x3f; |
37 self.index = (self.index + 1) & 0x3f; |
34 self.circular_buffer[self.index] = (self.circular_buffer[(self.index + 40) & 0x3f] |
38 let next_value = self.circular_buffer[(self.index + 40) & 0x3f] |
35 + self.circular_buffer[(self.index + 9) & 0x3f]) |
39 + self.circular_buffer[(self.index + 9) & 0x3f]; |
36 & 0x7fffffff; |
40 |
|
41 self.circular_buffer[self.index] = if next_value > PRIME_NUM { |
|
42 next_value - PRIME_NUM |
|
43 } else { |
|
44 next_value |
|
45 }; |
37 |
46 |
38 self.circular_buffer[self.index] |
47 self.circular_buffer[self.index] |
39 } |
48 } |
40 |
49 |
41 #[inline] |
50 #[inline] |
58 self.get_next(); |
67 self.get_next(); |
59 Some(self.get_next()) |
68 Some(self.get_next()) |
60 } |
69 } |
61 } |
70 } |
62 |
71 |
|
72 impl RngCore for LaggedFibonacciPRNG { |
|
73 fn next_u32(&mut self) -> u32 { |
|
74 self.get_next().wrapping_add(self.get_next()) |
|
75 } |
|
76 |
|
77 fn next_u64(&mut self) -> u64 { |
|
78 ((self.next_u32() as u64) << 32) | self.next_u32() as u64 |
|
79 } |
|
80 |
|
81 fn fill_bytes(&mut self, dest: &mut [u8]) { |
|
82 dest.iter_mut().for_each(|x| *x = self.next_u32() as u8); |
|
83 } |
|
84 |
|
85 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
|
86 Ok(self.fill_bytes(dest)) |
|
87 } |
|
88 } |
|
89 |
|
90 impl SeedableRng for LaggedFibonacciPRNG { |
|
91 type Seed = [u8; 32]; |
|
92 |
|
93 fn from_seed(seed: Self::Seed) -> Self { |
|
94 LaggedFibonacciPRNG::new(&seed) |
|
95 } |
|
96 } |
|
97 |
63 #[cfg(test)] |
98 #[cfg(test)] |
64 #[test] |
99 #[test] |
65 fn compatibility() { |
100 fn compatibility() { |
66 let mut prng = LaggedFibonacciPRNG::new("{052e2aee-ce41-4720-97bd-559a413bf866}".as_bytes()); |
101 let mut prng = LaggedFibonacciPRNG::new("{052e2aee-ce41-4720-97bd-559a413bf866}".as_bytes()); |
67 |
102 |