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