rand_pcg/
pcg64.rs

1// Copyright 2018 Developers of the Rand project.
2// Copyright 2017 Paul Dicker.
3// Copyright 2014-2017 Melissa O'Neill and PCG Project contributors
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! PCG random number generators
12
13use core::fmt;
14use core::mem::transmute;
15use rand_core::{RngCore, SeedableRng, Error, le, impls};
16
17// This is the default multiplier used by PCG for 64-bit state.
18const MULTIPLIER: u64 = 6364136223846793005;
19
20/// A PCG random number generator (XSH RR 64/32 (LCG) variant).
21/// 
22/// Permuted Congruential Generator with 64-bit state, internal Linear
23/// Congruential Generator, and 32-bit output via "xorshift high (bits),
24/// random rotation" output function.
25/// 
26/// This is a 64-bit LCG with explicitly chosen stream with the PCG-XSH-RR
27/// output function. This combination is the standard `pcg32`.
28/// 
29/// Despite the name, this implementation uses 16 bytes (128 bit) space
30/// comprising 64 bits of state and 64 bits stream selector. These are both set
31/// by `SeedableRng`, using a 128-bit seed.
32#[derive(Clone)]
33#[cfg_attr(feature="serde1", derive(Serialize,Deserialize))]
34pub struct Lcg64Xsh32 {
35    state: u64,
36    increment: u64,
37}
38
39/// `Lcg64Xsh32` is also officially known as `pcg32`.
40pub type Pcg32 = Lcg64Xsh32;
41
42impl Lcg64Xsh32 {
43    /// Construct an instance compatible with PCG seed and stream.
44    /// 
45    /// Note that PCG specifies default values for both parameters:
46    /// 
47    /// - `state = 0xcafef00dd15ea5e5`
48    /// - `stream = 721347520444481703`
49    pub fn new(state: u64, stream: u64) -> Self {
50        // The increment must be odd, hence we discard one bit:
51        let increment = (stream << 1) | 1;
52        Lcg64Xsh32::from_state_incr(state, increment)
53    }
54    
55    #[inline]
56    fn from_state_incr(state: u64, increment: u64) -> Self {
57        let mut pcg = Lcg64Xsh32 { state, increment };
58        // Move away from inital value:
59        pcg.state = pcg.state.wrapping_add(pcg.increment);
60        pcg.step();
61        pcg
62    }
63    
64    #[inline]
65    fn step(&mut self) {
66        // prepare the LCG for the next round
67        self.state = self.state
68            .wrapping_mul(MULTIPLIER)
69            .wrapping_add(self.increment);
70    }
71}
72
73// Custom Debug implementation that does not expose the internal state
74impl fmt::Debug for Lcg64Xsh32 {
75    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        write!(f, "Lcg64Xsh32 {{}}")
77    }
78}
79
80/// We use a single 127-bit seed to initialise the state and select a stream.
81/// One `seed` bit (lowest bit of `seed[8]`) is ignored.
82impl SeedableRng for Lcg64Xsh32 {
83    type Seed = [u8; 16];
84
85    fn from_seed(seed: Self::Seed) -> Self {
86        let mut seed_u64 = [0u64; 2];
87        le::read_u64_into(&seed, &mut seed_u64);
88
89        // The increment must be odd, hence we discard one bit:
90        Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1)
91    }
92}
93
94impl RngCore for Lcg64Xsh32 {
95    #[inline]
96    fn next_u32(&mut self) -> u32 {
97        let state = self.state;
98        self.step();
99
100        // Output function XSH RR: xorshift high (bits), followed by a random rotate
101        // Constants are for 64-bit state, 32-bit output
102        const ROTATE: u32 = 59; // 64 - 5
103        const XSHIFT: u32 = 18; // (5 + 32) / 2
104        const SPARE: u32 = 27;  // 64 - 32 - 5
105
106        let rot = (state >> ROTATE) as u32;
107        let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32;
108        xsh.rotate_right(rot)
109    }
110
111    #[inline]
112    fn next_u64(&mut self) -> u64 {
113        impls::next_u64_via_u32(self)
114    }
115
116    #[inline]
117    fn fill_bytes(&mut self, dest: &mut [u8]) {
118        // specialisation of impls::fill_bytes_via_next; approx 40% faster
119        let mut left = dest;
120        while left.len() >= 4 {
121            let (l, r) = {left}.split_at_mut(4);
122            left = r;
123            let chunk: [u8; 4] = unsafe {
124                transmute(self.next_u32().to_le())
125            };
126            l.copy_from_slice(&chunk);
127        }
128        let n = left.len();
129        if n > 0 {
130            let chunk: [u8; 4] = unsafe {
131                transmute(self.next_u32().to_le())
132            };
133            left.copy_from_slice(&chunk[..n]);
134        }
135    }
136
137    #[inline]
138    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
139        Ok(self.fill_bytes(dest))
140    }
141}
142
143#[cfg(test)]
144mod tests {
145    use ::rand_core::{RngCore, SeedableRng};
146    use super::*;
147
148    #[test]
149    fn test_lcg64xsh32_construction() {
150        // Test that various construction techniques produce a working RNG.
151        let seed = [1,2,3,4, 5,6,7,8, 9,10,11,12, 13,14,15,16];
152        let mut rng1 = Lcg64Xsh32::from_seed(seed);
153        assert_eq!(rng1.next_u64(), 1204678643940597513);
154
155        let mut rng2 = Lcg64Xsh32::from_rng(&mut rng1).unwrap();
156        assert_eq!(rng2.next_u64(), 12384929573776311845);
157
158        let mut rng3 = Lcg64Xsh32::seed_from_u64(0);
159        assert_eq!(rng3.next_u64(), 18195738587432868099);
160
161        // This is the same as Lcg64Xsh32, so we only have a single test:
162        let mut rng4 = Pcg32::seed_from_u64(0);
163        assert_eq!(rng4.next_u64(), 18195738587432868099);
164    }
165
166    #[test]
167    fn test_lcg64xsh32_true_values() {
168        // Numbers copied from official test suite.
169        let mut rng = Lcg64Xsh32::new(42, 54);
170
171        let mut results = [0u32; 6];
172        for i in results.iter_mut() { *i = rng.next_u32(); }
173        let expected: [u32; 6] = [0xa15c02b7, 0x7b47f409, 0xba1d3330,
174            0x83d2f293, 0xbfa4784b, 0xcbed606e];
175        assert_eq!(results, expected);
176    }
177
178    #[cfg(feature="serde1")]
179    #[test]
180    fn test_lcg64xsh32_serde() {
181        use bincode;
182        use std::io::{BufWriter, BufReader};
183
184        let mut rng = Lcg64Xsh32::seed_from_u64(0);
185
186        let buf: Vec<u8> = Vec::new();
187        let mut buf = BufWriter::new(buf);
188        bincode::serialize_into(&mut buf, &rng).expect("Could not serialize");
189
190        let buf = buf.into_inner().unwrap();
191        let mut read = BufReader::new(&buf[..]);
192        let mut deserialized: Lcg64Xsh32 = bincode::deserialize_from(&mut read).expect("Could not deserialize");
193
194        assert_eq!(rng.state, deserialized.state);
195
196        for _ in 0..16 {
197            assert_eq!(rng.next_u64(), deserialized.next_u64());
198        }
199    }
200}