|
| 1 | +/* |
| 2 | +Permuted Congruential Generator |
| 3 | +https://en.wikipedia.org/wiki/Permuted_congruential_generator |
| 4 | +
|
| 5 | +Note that this is _NOT_ intended for serious applications. Use this generator |
| 6 | +at your own risk and only use your own values instead of the default ones if |
| 7 | +you really know what you are doing. |
| 8 | + */ |
| 9 | +pub struct PCG32 { |
| 10 | + state: u64, |
| 11 | + multiplier: u64, |
| 12 | + increment: u64, |
| 13 | +} |
| 14 | + |
| 15 | +pub const PCG32_MULTIPLIER: u64 = 6364136223846793005_u64; |
| 16 | +pub const PCG32_INCREMENT: u64 = 1442695040888963407_u64; |
| 17 | + |
| 18 | +pub struct IterMut<'a> { |
| 19 | + pcg: &'a mut PCG32, |
| 20 | +} |
| 21 | + |
| 22 | +impl PCG32 { |
| 23 | + /// `stream` should be less than 1 << 63 |
| 24 | + pub fn new(seed: u64, multiplier: u64, stream: u64) -> Self { |
| 25 | + // We should make sure that increment is odd |
| 26 | + let increment = (stream << 1) | 1; |
| 27 | + let mut pcg = PCG32 { |
| 28 | + state: seed.wrapping_add(increment), |
| 29 | + multiplier, |
| 30 | + increment, |
| 31 | + }; |
| 32 | + pcg.next(); |
| 33 | + pcg |
| 34 | + } |
| 35 | + pub fn new_default(seed: u64) -> Self { |
| 36 | + let multiplier = PCG32_MULTIPLIER; |
| 37 | + let increment = PCG32_INCREMENT; |
| 38 | + let mut pcg = PCG32 { |
| 39 | + state: seed.wrapping_add(increment), |
| 40 | + multiplier, |
| 41 | + increment, |
| 42 | + }; |
| 43 | + pcg.next(); |
| 44 | + pcg |
| 45 | + } |
| 46 | + #[inline] |
| 47 | + pub fn next(&mut self) { |
| 48 | + self.state = self |
| 49 | + .state |
| 50 | + .wrapping_mul(self.multiplier) |
| 51 | + .wrapping_add(self.increment); |
| 52 | + } |
| 53 | + #[inline] |
| 54 | + /// Advance the PCG by `delta` steps in O(lg(`delta`)) time. By passing |
| 55 | + /// a negative i64 as u64, it can go back too. |
| 56 | + pub fn advance(&mut self, mut delta: u64) { |
| 57 | + let mut acc_mult = 1u64; |
| 58 | + let mut acc_incr = 0u64; |
| 59 | + let mut curr_mlt = self.multiplier; |
| 60 | + let mut curr_inc = self.increment; |
| 61 | + while delta > 0 { |
| 62 | + if delta & 1 != 0 { |
| 63 | + acc_mult = acc_mult.wrapping_mul(curr_mlt); |
| 64 | + acc_incr = acc_incr.wrapping_mul(curr_mlt).wrapping_add(curr_inc); |
| 65 | + } |
| 66 | + curr_inc = curr_mlt.wrapping_add(1).wrapping_mul(curr_inc); |
| 67 | + curr_mlt = curr_mlt.wrapping_mul(curr_mlt); |
| 68 | + delta >>= 1; |
| 69 | + } |
| 70 | + self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_incr); |
| 71 | + } |
| 72 | + #[inline] |
| 73 | + pub fn get_u32(&mut self) -> u32 { |
| 74 | + let mut x = self.state; |
| 75 | + let count = (x >> 59) as u32; |
| 76 | + |
| 77 | + self.next(); |
| 78 | + |
| 79 | + x ^= x >> 18; |
| 80 | + ((x >> 27) as u32).rotate_right(count) |
| 81 | + } |
| 82 | + #[inline] |
| 83 | + pub fn get_u64(&mut self) -> u64 { |
| 84 | + self.get_u32() as u64 ^ ((self.get_u32() as u64) << 32) |
| 85 | + } |
| 86 | + #[inline] |
| 87 | + pub fn get_u16(&mut self) -> (u16, u16) { |
| 88 | + let res = self.get_u32(); |
| 89 | + (res as u16, (res >> 16) as u16) |
| 90 | + } |
| 91 | + #[inline] |
| 92 | + pub fn get_u8(&mut self) -> (u8, u8, u8, u8) { |
| 93 | + let res = self.get_u32(); |
| 94 | + ( |
| 95 | + res as u8, |
| 96 | + (res >> 8) as u8, |
| 97 | + (res >> 16) as u8, |
| 98 | + (res >> 24) as u8, |
| 99 | + ) |
| 100 | + } |
| 101 | + #[inline] |
| 102 | + pub fn get_state(&self) -> u64 { |
| 103 | + self.state |
| 104 | + } |
| 105 | + pub fn iter_mut(&mut self) -> IterMut { |
| 106 | + IterMut { pcg: self } |
| 107 | + } |
| 108 | +} |
| 109 | + |
| 110 | +impl<'a> Iterator for IterMut<'a> { |
| 111 | + type Item = u32; |
| 112 | + fn next(&mut self) -> Option<Self::Item> { |
| 113 | + Some(self.pcg.get_u32()) |
| 114 | + } |
| 115 | +} |
| 116 | + |
| 117 | +#[cfg(test)] |
| 118 | +mod tests { |
| 119 | + use super::*; |
| 120 | + |
| 121 | + #[test] |
| 122 | + fn no_birthday() { |
| 123 | + // If the distribution is not almost uniform, the probability of |
| 124 | + // birthday paradox increases. For n=2^32 and k=1e5, the probability |
| 125 | + // of not having a collision is about (1 - (k+1)/n) ^ (k/2) which is |
| 126 | + // 0.3121 for this (n, k). |
| 127 | + // So this test is a (dumb) test for distribution, and for speed. This |
| 128 | + // is only basic sanity checking, as the actual algorithm was |
| 129 | + // rigorously tested by others before. |
| 130 | + let numbers = 1e5 as usize; |
| 131 | + let mut pcg = PCG32::new_default(314159); |
| 132 | + let mut pcg2 = PCG32::new_default(314159); |
| 133 | + assert_eq!(pcg.get_u32(), pcg2.get_u32()); |
| 134 | + let mut randoms: Vec<u32> = pcg.iter_mut().take(numbers).collect::<Vec<u32>>(); |
| 135 | + pcg2.advance(1000); |
| 136 | + assert_eq!(pcg2.get_u32(), randoms[1000]); |
| 137 | + pcg2.advance((-1001_i64) as u64); |
| 138 | + assert_eq!(pcg2.get_u32(), randoms[0]); |
| 139 | + randoms.sort_unstable(); |
| 140 | + randoms.dedup(); |
| 141 | + assert_eq!(randoms.len(), numbers); |
| 142 | + } |
| 143 | +} |
0 commit comments