/rust/registry/src/index.crates.io-1949cf8c6b5b557f/rand_pcg-0.2.1/src/pcg128.rs
Line | Count | Source |
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 | | |
13 | | // This is the default multiplier used by PCG for 64-bit state. |
14 | | const MULTIPLIER: u128 = 0x2360_ED05_1FC6_5DA4_4385_DF64_9FCC_F645; |
15 | | |
16 | | use core::fmt; |
17 | | use rand_core::{RngCore, SeedableRng, Error, le}; |
18 | | #[cfg(feature="serde1")] use serde::{Serialize, Deserialize}; |
19 | | |
20 | | /// A PCG random number generator (XSL RR 128/64 (LCG) variant). |
21 | | /// |
22 | | /// Permuted Congruential Generator with 128-bit state, internal Linear |
23 | | /// Congruential Generator, and 64-bit output via "xorshift low (bits), |
24 | | /// random rotation" output function. |
25 | | /// |
26 | | /// This is a 128-bit LCG with explicitly chosen stream with the PCG-XSL-RR |
27 | | /// output function. This combination is the standard `pcg64`. |
28 | | /// |
29 | | /// Despite the name, this implementation uses 32 bytes (256 bit) space |
30 | | /// comprising 128 bits of state and 128 bits stream selector. These are both |
31 | | /// set by `SeedableRng`, using a 256-bit seed. |
32 | | #[derive(Clone)] |
33 | | #[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] |
34 | | pub struct Lcg128Xsl64 { |
35 | | state: u128, |
36 | | increment: u128, |
37 | | } |
38 | | |
39 | | /// `Lcg128Xsl64` is also officially known as `pcg64`. |
40 | | pub type Pcg64 = Lcg128Xsl64; |
41 | | |
42 | | impl Lcg128Xsl64 { |
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 = 0xa02bdbf7bb3c0a7ac28fa16a64abf96` |
49 | 0 | pub fn new(state: u128, stream: u128) -> Self { |
50 | | // The increment must be odd, hence we discard one bit: |
51 | 0 | let increment = (stream << 1) | 1; |
52 | 0 | Lcg128Xsl64::from_state_incr(state, increment) |
53 | 0 | } |
54 | | |
55 | | #[inline] |
56 | 0 | fn from_state_incr(state: u128, increment: u128) -> Self { |
57 | 0 | let mut pcg = Lcg128Xsl64 { state, increment }; |
58 | | // Move away from inital value: |
59 | 0 | pcg.state = pcg.state.wrapping_add(pcg.increment); |
60 | 0 | pcg.step(); |
61 | 0 | pcg |
62 | 0 | } |
63 | | |
64 | | #[inline] |
65 | 0 | fn step(&mut self) { |
66 | | // prepare the LCG for the next round |
67 | 0 | self.state = self.state |
68 | 0 | .wrapping_mul(MULTIPLIER) |
69 | 0 | .wrapping_add(self.increment); |
70 | 0 | } |
71 | | } |
72 | | |
73 | | // Custom Debug implementation that does not expose the internal state |
74 | | impl fmt::Debug for Lcg128Xsl64 { |
75 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
76 | 0 | write!(f, "Lcg128Xsl64 {{}}") |
77 | 0 | } |
78 | | } |
79 | | |
80 | | /// We use a single 255-bit seed to initialise the state and select a stream. |
81 | | /// One `seed` bit (lowest bit of `seed[8]`) is ignored. |
82 | | impl SeedableRng for Lcg128Xsl64 { |
83 | | type Seed = [u8; 32]; |
84 | | |
85 | 0 | fn from_seed(seed: Self::Seed) -> Self { |
86 | 0 | let mut seed_u64 = [0u64; 4]; |
87 | 0 | le::read_u64_into(&seed, &mut seed_u64); |
88 | 0 | let state = u128::from(seed_u64[0]) | (u128::from(seed_u64[1]) << 64); |
89 | 0 | let incr = u128::from(seed_u64[2]) | (u128::from(seed_u64[3]) << 64); |
90 | | |
91 | | // The increment must be odd, hence we discard one bit: |
92 | 0 | Lcg128Xsl64::from_state_incr(state, incr | 1) |
93 | 0 | } |
94 | | } |
95 | | |
96 | | impl RngCore for Lcg128Xsl64 { |
97 | | #[inline] |
98 | 0 | fn next_u32(&mut self) -> u32 { |
99 | 0 | self.next_u64() as u32 |
100 | 0 | } |
101 | | |
102 | | #[inline] |
103 | 0 | fn next_u64(&mut self) -> u64 { |
104 | 0 | self.step(); |
105 | 0 | output_xsl_rr(self.state) |
106 | 0 | } |
107 | | |
108 | | #[inline] |
109 | 0 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
110 | 0 | fill_bytes_impl(self, dest) |
111 | 0 | } |
112 | | |
113 | | #[inline] |
114 | 0 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
115 | 0 | self.fill_bytes(dest); |
116 | 0 | Ok(()) |
117 | 0 | } |
118 | | } |
119 | | |
120 | | |
121 | | /// A PCG random number generator (XSL 128/64 (MCG) variant). |
122 | | /// |
123 | | /// Permuted Congruential Generator with 128-bit state, internal Multiplicative |
124 | | /// Congruential Generator, and 64-bit output via "xorshift low (bits), |
125 | | /// random rotation" output function. |
126 | | /// |
127 | | /// This is a 128-bit MCG with the PCG-XSL-RR output function, also known as |
128 | | /// `pcg64_fast`. |
129 | | /// Note that compared to the standard `pcg64` (128-bit LCG with PCG-XSL-RR |
130 | | /// output function), this RNG is faster, also has a long cycle, and still has |
131 | | /// good performance on statistical tests. |
132 | | #[derive(Clone)] |
133 | | #[cfg_attr(feature="serde1", derive(Serialize,Deserialize))] |
134 | | pub struct Mcg128Xsl64 { |
135 | | state: u128, |
136 | | } |
137 | | |
138 | | /// A friendly name for `Mcg128Xsl64` (also known as `pcg64_fast`). |
139 | | pub type Pcg64Mcg = Mcg128Xsl64; |
140 | | |
141 | | impl Mcg128Xsl64 { |
142 | | /// Construct an instance compatible with PCG seed. |
143 | | /// |
144 | | /// Note that PCG specifies a default value for the parameter: |
145 | | /// |
146 | | /// - `state = 0xcafef00dd15ea5e5` |
147 | 0 | pub fn new(state: u128) -> Self { |
148 | | // Force low bit to 1, as in C version (C++ uses `state | 3` instead). |
149 | 0 | Mcg128Xsl64 { state: state | 1 } |
150 | 0 | } |
151 | | } |
152 | | |
153 | | // Custom Debug implementation that does not expose the internal state |
154 | | impl fmt::Debug for Mcg128Xsl64 { |
155 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
156 | 0 | write!(f, "Mcg128Xsl64 {{}}") |
157 | 0 | } |
158 | | } |
159 | | |
160 | | /// We use a single 126-bit seed to initialise the state and select a stream. |
161 | | /// Two `seed` bits (lowest order of last byte) are ignored. |
162 | | impl SeedableRng for Mcg128Xsl64 { |
163 | | type Seed = [u8; 16]; |
164 | | |
165 | 0 | fn from_seed(seed: Self::Seed) -> Self { |
166 | | // Read as if a little-endian u128 value: |
167 | 0 | let mut seed_u64 = [0u64; 2]; |
168 | 0 | le::read_u64_into(&seed, &mut seed_u64); |
169 | 0 | let state = u128::from(seed_u64[0]) | |
170 | 0 | u128::from(seed_u64[1]) << 64; |
171 | 0 | Mcg128Xsl64::new(state) |
172 | 0 | } |
173 | | } |
174 | | |
175 | | impl RngCore for Mcg128Xsl64 { |
176 | | #[inline] |
177 | 0 | fn next_u32(&mut self) -> u32 { |
178 | 0 | self.next_u64() as u32 |
179 | 0 | } |
180 | | |
181 | | #[inline] |
182 | 0 | fn next_u64(&mut self) -> u64 { |
183 | 0 | self.state = self.state.wrapping_mul(MULTIPLIER); |
184 | 0 | output_xsl_rr(self.state) |
185 | 0 | } |
186 | | |
187 | | #[inline] |
188 | 0 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
189 | 0 | fill_bytes_impl(self, dest) |
190 | 0 | } |
191 | | |
192 | | #[inline] |
193 | 0 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
194 | 0 | self.fill_bytes(dest); |
195 | 0 | Ok(()) |
196 | 0 | } |
197 | | } |
198 | | |
199 | | #[inline(always)] |
200 | 0 | fn output_xsl_rr(state: u128) -> u64 { |
201 | | // Output function XSL RR ("xorshift low (bits), random rotation") |
202 | | // Constants are for 128-bit state, 64-bit output |
203 | | const XSHIFT: u32 = 64; // (128 - 64 + 64) / 2 |
204 | | const ROTATE: u32 = 122; // 128 - 6 |
205 | | |
206 | 0 | let rot = (state >> ROTATE) as u32; |
207 | 0 | let xsl = ((state >> XSHIFT) as u64) ^ (state as u64); |
208 | 0 | xsl.rotate_right(rot) |
209 | 0 | } |
210 | | |
211 | | #[inline(always)] |
212 | 0 | fn fill_bytes_impl<R: RngCore + ?Sized>(rng: &mut R, dest: &mut [u8]) { |
213 | 0 | let mut left = dest; |
214 | 0 | while left.len() >= 8 { |
215 | 0 | let (l, r) = {left}.split_at_mut(8); |
216 | 0 | left = r; |
217 | 0 | let chunk: [u8; 8] = rng.next_u64().to_le_bytes(); |
218 | 0 | l.copy_from_slice(&chunk); |
219 | 0 | } |
220 | 0 | let n = left.len(); |
221 | 0 | if n > 0 { |
222 | 0 | let chunk: [u8; 8] = rng.next_u64().to_le_bytes(); |
223 | 0 | left.copy_from_slice(&chunk[..n]); |
224 | 0 | } |
225 | 0 | } |