|
| 1 | +#[repr(transparent)] |
| 2 | +pub struct PCG32si { |
| 3 | + state: u32, |
| 4 | +} |
| 5 | + |
| 6 | +impl PCG32si { |
| 7 | + const PCG_DEFAULT_MULTIPLIER_32: u32 = 747796405; |
| 8 | + const PCG_DEFAULT_INCREMENT_32: u32 = 2891336453; |
| 9 | + |
| 10 | + fn pcg_oneseq_32_step_r(&mut self) { |
| 11 | + self.state = self |
| 12 | + .state |
| 13 | + .wrapping_mul(Self::PCG_DEFAULT_MULTIPLIER_32) |
| 14 | + .wrapping_add(Self::PCG_DEFAULT_INCREMENT_32); |
| 15 | + } |
| 16 | + |
| 17 | + fn pcg_output_rxs_m_xs_32_32(state: u32) -> u32 { |
| 18 | + let word = ((state >> ((state >> 28).wrapping_add(4))) ^ state).wrapping_mul(277803737); |
| 19 | + (word >> 22) ^ word |
| 20 | + } |
| 21 | + |
| 22 | + pub fn new(seed: u32) -> Self { |
| 23 | + let mut rng = Self { state: seed }; |
| 24 | + rng.pcg_oneseq_32_step_r(); |
| 25 | + rng.state = rng.state.wrapping_add(seed); |
| 26 | + rng.pcg_oneseq_32_step_r(); |
| 27 | + rng |
| 28 | + } |
| 29 | + |
| 30 | + pub fn next_u32(&mut self) -> u32 { |
| 31 | + let old_state = self.state; |
| 32 | + self.pcg_oneseq_32_step_r(); |
| 33 | + Self::pcg_output_rxs_m_xs_32_32(old_state) |
| 34 | + } |
| 35 | + |
| 36 | + pub fn next_f32(&mut self) -> f32 { |
| 37 | + const FLOAT_SIZE: u32 = core::mem::size_of::<f32>() as u32 * 8; |
| 38 | + const PRECISION: u32 = 23 + 1; |
| 39 | + const SCALE: f32 = 1.0 / (1 << PRECISION) as f32; |
| 40 | + const SHIFT: u32 = FLOAT_SIZE - PRECISION; |
| 41 | + |
| 42 | + let value = self.next_u32(); |
| 43 | + let value = value >> SHIFT; |
| 44 | + SCALE * value as f32 |
| 45 | + } |
| 46 | + |
| 47 | + pub fn next_f32_range(&mut self, min: f32, max: f32) -> f32 { |
| 48 | + min + (max - min) * self.next_f32() |
| 49 | + } |
| 50 | +} |
| 51 | + |
| 52 | +#[test] |
| 53 | +fn test_pcg32si_next_f32() { |
| 54 | + let mut rng = PCG32si::new(0); |
| 55 | + for _ in 0..1_000_000 { |
| 56 | + let f = rng.next_f32(); |
| 57 | + assert!(f >= 0.0); |
| 58 | + assert!(f <= 1.0); |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +#[cfg(test)] |
| 63 | +use test::Bencher; |
| 64 | + |
| 65 | +#[bench] |
| 66 | +fn bench_pcg32si_next(b: &mut Bencher) { |
| 67 | + let mut rng = PCG32si::new(0); |
| 68 | + b.iter(|| { |
| 69 | + for _ in 0..1_000_000 { |
| 70 | + rng.next_u32(); |
| 71 | + } |
| 72 | + }); |
| 73 | +} |
0 commit comments