rand_xoshiro/
common.rs

1// Copyright 2018 Developers of the Rand project.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9/// Initialize a RNG from a `u64` seed using `SplitMix64`.
10macro_rules! from_splitmix {
11    ($seed:expr) => { {
12        let mut rng = ::SplitMix64::seed_from_u64($seed);
13        Self::from_rng(&mut rng).unwrap()
14    } }
15}
16
17/// Apply the ** scrambler used by some RNGs from the xoshiro family.
18macro_rules! starstar_u64 {
19    ($x:expr) => {
20        $x.wrapping_mul(5).rotate_left(7).wrapping_mul(9)
21    }
22}
23
24/// Apply the ** scrambler used by some RNGs from the xoshiro family.
25macro_rules! starstar_u32 {
26    ($x:expr) => {
27        $x.wrapping_mul(0x9E3779BB).rotate_left(5).wrapping_mul(5)
28    }
29}
30
31/// Implement a jump function for an RNG from the xoshiro family.
32macro_rules! impl_jump {
33    (u32, $self:expr, [$j0:expr, $j1:expr]) => {
34        const JUMP: [u32; 2] = [$j0, $j1];
35        let mut s0 = 0;
36        let mut s1 = 0;
37        for j in &JUMP {
38            for b in 0..32 {
39                if (j & 1 << b) != 0 {
40                    s0 ^= $self.s0;
41                    s1 ^= $self.s1;
42                }
43                $self.next_u32();
44            }
45        }
46        $self.s0 = s0;
47        $self.s1 = s1;
48    };
49    (u64, $self:expr, [$j0:expr, $j1:expr]) => {
50        const JUMP: [u64; 2] = [$j0, $j1];
51        let mut s0 = 0;
52        let mut s1 = 0;
53        for j in &JUMP {
54            for b in 0..64 {
55                if (j & 1 << b) != 0 {
56                    s0 ^= $self.s0;
57                    s1 ^= $self.s1;
58                }
59                $self.next_u64();
60            }
61        }
62        $self.s0 = s0;
63        $self.s1 = s1;
64    };
65    (u32, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
66        const JUMP: [u32; 4] = [$j0, $j1, $j2, $j3];
67        let mut s0 = 0;
68        let mut s1 = 0;
69        let mut s2 = 0;
70        let mut s3 = 0;
71        for j in &JUMP {
72            for b in 0..32 {
73                if (j & 1 << b) != 0 {
74                    s0 ^= $self.s[0];
75                    s1 ^= $self.s[1];
76                    s2 ^= $self.s[2];
77                    s3 ^= $self.s[3];
78                }
79                $self.next_u32();
80            }
81        }
82        $self.s[0] = s0;
83        $self.s[1] = s1;
84        $self.s[2] = s2;
85        $self.s[3] = s3;
86    };
87    (u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr]) => {
88        const JUMP: [u64; 4] = [$j0, $j1, $j2, $j3];
89        let mut s0 = 0;
90        let mut s1 = 0;
91        let mut s2 = 0;
92        let mut s3 = 0;
93        for j in &JUMP {
94            for b in 0..64 {
95                if (j & 1 << b) != 0 {
96                    s0 ^= $self.s[0];
97                    s1 ^= $self.s[1];
98                    s2 ^= $self.s[2];
99                    s3 ^= $self.s[3];
100                }
101                $self.next_u64();
102            }
103        }
104        $self.s[0] = s0;
105        $self.s[1] = s1;
106        $self.s[2] = s2;
107        $self.s[3] = s3;
108    };
109    (u64, $self:expr, [$j0:expr, $j1:expr, $j2:expr, $j3:expr,
110                       $j4:expr, $j5:expr, $j6:expr, $j7:expr]) => {
111        const JUMP: [u64; 8] = [$j0, $j1, $j2, $j3, $j4, $j5, $j6, $j7];
112        let mut s = [0; 8];
113        for j in &JUMP {
114            for b in 0..64 {
115                if (j & 1 << b) != 0 {
116                    s[0] ^= $self.s[0];
117                    s[1] ^= $self.s[1];
118                    s[2] ^= $self.s[2];
119                    s[3] ^= $self.s[3];
120                    s[4] ^= $self.s[4];
121                    s[5] ^= $self.s[5];
122                    s[6] ^= $self.s[6];
123                    s[7] ^= $self.s[7];
124                }
125                $self.next_u64();
126            }
127        }
128        $self.s = s;
129    };
130}
131
132/// Implement the xoroshiro iteration.
133macro_rules! impl_xoroshiro_u32 {
134    ($self:expr) => {
135        $self.s1 ^= $self.s0;
136        $self.s0 = $self.s0.rotate_left(26) ^ $self.s1 ^ ($self.s1 << 9);
137        $self.s1 = $self.s1.rotate_left(13);
138    }
139}
140
141/// Implement the xoroshiro iteration.
142macro_rules! impl_xoroshiro_u64 {
143    ($self:expr) => {
144        $self.s1 ^= $self.s0;
145        $self.s0 = $self.s0.rotate_left(24) ^ $self.s1 ^ ($self.s1 << 16);
146        $self.s1 = $self.s1.rotate_left(37);
147    }
148}
149
150/// Implement the xoshiro iteration for `u32` output.
151macro_rules! impl_xoshiro_u32 {
152    ($self:expr) => {
153        let t = $self.s[1] << 9;
154
155        $self.s[2] ^= $self.s[0];
156        $self.s[3] ^= $self.s[1];
157        $self.s[1] ^= $self.s[2];
158        $self.s[0] ^= $self.s[3];
159
160        $self.s[2] ^= t;
161
162        $self.s[3] = $self.s[3].rotate_left(11);
163    }
164}
165
166/// Implement the xoshiro iteration for `u64` output.
167macro_rules! impl_xoshiro_u64 {
168    ($self:expr) => {
169        let t = $self.s[1] << 17;
170
171        $self.s[2] ^= $self.s[0];
172        $self.s[3] ^= $self.s[1];
173        $self.s[1] ^= $self.s[2];
174        $self.s[0] ^= $self.s[3];
175
176        $self.s[2] ^= t;
177
178        $self.s[3] = $self.s[3].rotate_left(45);
179    }
180}
181
182/// Implement the large-state xoshiro iteration.
183macro_rules! impl_xoshiro_large {
184    ($self:expr) => {
185        let t = $self.s[1] << 11;
186
187        $self.s[2] ^= $self.s[0];
188        $self.s[5] ^= $self.s[1];
189        $self.s[1] ^= $self.s[2];
190        $self.s[7] ^= $self.s[3];
191        $self.s[3] ^= $self.s[4];
192        $self.s[4] ^= $self.s[5];
193        $self.s[0] ^= $self.s[6];
194        $self.s[6] ^= $self.s[7];
195
196        $self.s[6] ^= t;
197
198        $self.s[7] = $self.s[7].rotate_left(21);
199    }
200}
201
202/// Map an all-zero seed to a different one.
203macro_rules! deal_with_zero_seed {
204    ($seed:expr, $Self:ident) => {
205        if $seed.iter().all(|&x| x == 0) {
206            return $Self::seed_from_u64(0);
207        }
208    }
209}
210
211/// 512-bit seed for a generator.
212///
213/// This wrapper is necessary, because some traits required for a seed are not
214/// implemented on large arrays.
215#[derive(Clone)]
216pub struct Seed512(pub [u8; 64]);
217
218use core;
219impl Seed512 {
220    /// Return an iterator over the seed.
221    pub fn iter(&self) -> core::slice::Iter<u8> {
222        self.0.iter()
223    }
224}
225
226impl core::fmt::Debug for Seed512 {
227    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
228        self.0[..].fmt(f)
229    }
230}
231
232impl Default for Seed512 {
233    fn default() -> Seed512 {
234        Seed512([0; 64])
235    }
236}
237
238impl AsMut<[u8]> for Seed512 {
239    fn as_mut(&mut self) -> &mut [u8] {
240        &mut self.0
241    }
242}
243