Skip to content

Commit a2980f2

Browse files
committed
Add pcg
1 parent 9043863 commit a2980f2

File tree

2 files changed

+74
-0
lines changed

2 files changed

+74
-0
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub mod math;
1919
pub mod misc;
2020
pub mod modulo;
2121
pub mod monoid;
22+
pub mod pcg;
2223
pub mod rc_list;
2324
pub mod rolling_hash;
2425
pub mod seg_lazy;

src/pcg.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
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

Comments
 (0)