Skip to main content

vec_rac/
rng.rs

1#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
2pub struct Rng {
3    state: u64,
4}
5
6impl Rng {
7    pub const RAND_MAX: u64 = MODULUS - 1;
8
9    pub fn with_seed(seed: u64) -> Rng {
10        Rng {
11            state: seed % MODULUS,
12        }
13    }
14
15    // NOTE: I'm just hoping the wrapping arithmetic doesn't interfere with the math!
16
17    pub fn forward(&mut self) -> u64 {
18        let here = self.state;
19        self.state = MULTIPLIER.wrapping_mul(self.state).wrapping_add(INCREMENT) % MODULUS;
20        here
21    }
22
23    pub fn backward(&mut self) -> u64 {
24        // From https://stackoverflow.com/a/29585823/11815766
25        self.state = INVERSE_MULTIPLIER.wrapping_mul(self.state.wrapping_sub(INCREMENT)) % MODULUS;
26        self.state
27    }
28}
29
30// Taken from https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
31// This is apparently used by C implementations.
32const MULTIPLIER: u64 = 1103515245;
33const INCREMENT: u64 = 12345;
34const MODULUS: u64 = 2147483648;
35const INVERSE_MULTIPLIER: u64 = 1857678181;
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn rng_goes_both_ways() {
43        let mut rng = Rng::with_seed(12304);
44        rng.backward();
45        rng.backward();
46        let forward = std::iter::repeat_with(|| rng.forward())
47            .take(5)
48            .collect::<Vec<_>>();
49        let mut backward = std::iter::repeat_with(|| rng.backward())
50            .take(5)
51            .collect::<Vec<_>>();
52        backward.reverse();
53        assert_eq!(forward, backward);
54    }
55
56    #[test]
57    fn inverse_multiplier_is_correct() {
58        assert!(MULTIPLIER * INVERSE_MULTIPLIER % MODULUS == 1);
59    }
60
61    #[test]
62    fn no_overflow() {
63        let mut rng = Rng::with_seed(17700000001);
64        rng.forward();
65    }
66}