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 rand_core::{impls, le, Error, RngCore, SeedableRng};
15#[cfg(feature = "serde1")] use serde::{Deserialize, Serialize};
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///
33/// Note that two generators with different stream parameter may be closely
34/// correlated.
35#[derive(Clone, PartialEq, Eq)]
36#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
37pub struct Lcg64Xsh32 {
38    state: u64,
39    increment: u64,
40}
41
42/// [`Lcg64Xsh32`] is also officially known as `pcg32`.
43pub type Pcg32 = Lcg64Xsh32;
44
45impl Lcg64Xsh32 {
46    /// Multi-step advance functions (jump-ahead, jump-back)
47    ///
48    /// The method used here is based on Brown, "Random Number Generation
49    /// with Arbitrary Stride,", Transactions of the American Nuclear
50    /// Society (Nov. 1994).  The algorithm is very similar to fast
51    /// exponentiation.
52    ///
53    /// Even though delta is an unsigned integer, we can pass a
54    /// signed integer to go backwards, it just goes "the long way round".
55    ///
56    /// Using this function is equivalent to calling `next_32()` `delta`
57    /// number of times.
58    #[inline]
59    pub fn advance(&mut self, delta: u64) {
60        let mut acc_mult: u64 = 1;
61        let mut acc_plus: u64 = 0;
62        let mut cur_mult = MULTIPLIER;
63        let mut cur_plus = self.increment;
64        let mut mdelta = delta;
65
66        while mdelta > 0 {
67            if (mdelta & 1) != 0 {
68                acc_mult = acc_mult.wrapping_mul(cur_mult);
69                acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus);
70            }
71            cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus);
72            cur_mult = cur_mult.wrapping_mul(cur_mult);
73            mdelta /= 2;
74        }
75        self.state = acc_mult.wrapping_mul(self.state).wrapping_add(acc_plus);
76    }
77
78    /// Construct an instance compatible with PCG seed and stream.
79    ///
80    /// Note that two generators with different stream parameters may be closely
81    /// correlated.
82    ///
83    /// PCG specifies the following default values for both parameters:
84    ///
85    /// - `state = 0xcafef00dd15ea5e5`
86    /// - `stream = 0xa02bdbf7bb3c0a7`
87    // Note: stream is 1442695040888963407u64 >> 1
88    pub fn new(state: u64, stream: u64) -> Self {
89        // The increment must be odd, hence we discard one bit:
90        let increment = (stream << 1) | 1;
91        Lcg64Xsh32::from_state_incr(state, increment)
92    }
93
94    #[inline]
95    fn from_state_incr(state: u64, increment: u64) -> Self {
96        let mut pcg = Lcg64Xsh32 { state, increment };
97        // Move away from inital value:
98        pcg.state = pcg.state.wrapping_add(pcg.increment);
99        pcg.step();
100        pcg
101    }
102
103    #[inline]
104    fn step(&mut self) {
105        // prepare the LCG for the next round
106        self.state = self
107            .state
108            .wrapping_mul(MULTIPLIER)
109            .wrapping_add(self.increment);
110    }
111}
112
113// Custom Debug implementation that does not expose the internal state
114impl fmt::Debug for Lcg64Xsh32 {
115    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116        write!(f, "Lcg64Xsh32 {{}}")
117    }
118}
119
120/// We use a single 127-bit seed to initialise the state and select a stream.
121/// One `seed` bit (lowest bit of `seed[8]`) is ignored.
122impl SeedableRng for Lcg64Xsh32 {
123    type Seed = [u8; 16];
124
125    fn from_seed(seed: Self::Seed) -> Self {
126        let mut seed_u64 = [0u64; 2];
127        le::read_u64_into(&seed, &mut seed_u64);
128
129        // The increment must be odd, hence we discard one bit:
130        Lcg64Xsh32::from_state_incr(seed_u64[0], seed_u64[1] | 1)
131    }
132}
133
134impl RngCore for Lcg64Xsh32 {
135    #[inline]
136    fn next_u32(&mut self) -> u32 {
137        let state = self.state;
138        self.step();
139
140        // Output function XSH RR: xorshift high (bits), followed by a random rotate
141        // Constants are for 64-bit state, 32-bit output
142        const ROTATE: u32 = 59; // 64 - 5
143        const XSHIFT: u32 = 18; // (5 + 32) / 2
144        const SPARE: u32 = 27; // 64 - 32 - 5
145
146        let rot = (state >> ROTATE) as u32;
147        let xsh = (((state >> XSHIFT) ^ state) >> SPARE) as u32;
148        xsh.rotate_right(rot)
149    }
150
151    #[inline]
152    fn next_u64(&mut self) -> u64 {
153        impls::next_u64_via_u32(self)
154    }
155
156    #[inline]
157    fn fill_bytes(&mut self, dest: &mut [u8]) {
158        impls::fill_bytes_via_next(self, dest)
159    }
160
161    #[inline]
162    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
163        self.fill_bytes(dest);
164        Ok(())
165    }
166}