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 | //! The xorshift random number generator. |
10 | |
11 | #![doc (html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png" , |
12 | html_favicon_url = "https://www.rust-lang.org/favicon.ico" , |
13 | html_root_url = "https://docs.rs/rand_xorshift/0.3.0" )] |
14 | |
15 | #![deny (missing_docs)] |
16 | #![deny (missing_debug_implementations)] |
17 | |
18 | #![no_std ] |
19 | |
20 | use core::num::Wrapping as w; |
21 | use core::fmt; |
22 | use rand_core::{RngCore, SeedableRng, Error, impls, le}; |
23 | #[cfg (feature="serde1" )] use serde::{Serialize, Deserialize}; |
24 | |
25 | /// An Xorshift random number generator. |
26 | /// |
27 | /// The Xorshift[^1] algorithm is not suitable for cryptographic purposes |
28 | /// but is very fast. If you do not know for sure that it fits your |
29 | /// requirements, use a more secure one such as `StdRng` or `OsRng`. |
30 | /// |
31 | /// [^1]: Marsaglia, George (July 2003). |
32 | /// ["Xorshift RNGs"](https://www.jstatsoft.org/v08/i14/paper). |
33 | /// *Journal of Statistical Software*. Vol. 8 (Issue 14). |
34 | #[derive (Clone, PartialEq, Eq)] |
35 | #[cfg_attr (feature="serde1" , derive(Serialize,Deserialize))] |
36 | pub struct XorShiftRng { |
37 | x: w<u32>, |
38 | y: w<u32>, |
39 | z: w<u32>, |
40 | w: w<u32>, |
41 | } |
42 | |
43 | // Custom Debug implementation that does not expose the internal state |
44 | impl fmt::Debug for XorShiftRng { |
45 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
46 | write!(f, "XorShiftRng {{}}" ) |
47 | } |
48 | } |
49 | |
50 | impl RngCore for XorShiftRng { |
51 | #[inline ] |
52 | fn next_u32(&mut self) -> u32 { |
53 | let x = self.x; |
54 | let t = x ^ (x << 11); |
55 | self.x = self.y; |
56 | self.y = self.z; |
57 | self.z = self.w; |
58 | let w_ = self.w; |
59 | self.w = w_ ^ (w_ >> 19) ^ (t ^ (t >> 8)); |
60 | self.w.0 |
61 | } |
62 | |
63 | #[inline ] |
64 | fn next_u64(&mut self) -> u64 { |
65 | impls::next_u64_via_u32(self) |
66 | } |
67 | |
68 | #[inline ] |
69 | fn fill_bytes(&mut self, dest: &mut [u8]) { |
70 | impls::fill_bytes_via_next(self, dest) |
71 | } |
72 | |
73 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { |
74 | self.fill_bytes(dest); |
75 | Ok(()) |
76 | } |
77 | } |
78 | |
79 | impl SeedableRng for XorShiftRng { |
80 | type Seed = [u8; 16]; |
81 | |
82 | fn from_seed(seed: Self::Seed) -> Self { |
83 | let mut seed_u32 = [0u32; 4]; |
84 | le::read_u32_into(&seed, &mut seed_u32); |
85 | |
86 | // Xorshift cannot be seeded with 0 and we cannot return an Error, but |
87 | // also do not wish to panic (because a random seed can legitimately be |
88 | // 0); our only option is therefore to use a preset value. |
89 | if seed_u32.iter().all(|&x| x == 0) { |
90 | seed_u32 = [0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED, 0xBAD_5EED]; |
91 | } |
92 | |
93 | XorShiftRng { |
94 | x: w(seed_u32[0]), |
95 | y: w(seed_u32[1]), |
96 | z: w(seed_u32[2]), |
97 | w: w(seed_u32[3]), |
98 | } |
99 | } |
100 | |
101 | fn from_rng<R: RngCore>(mut rng: R) -> Result<Self, Error> { |
102 | let mut b = [0u8; 16]; |
103 | loop { |
104 | rng.try_fill_bytes(&mut b[..])?; |
105 | if !b.iter().all(|&x| x == 0) { |
106 | break; |
107 | } |
108 | } |
109 | |
110 | Ok(XorShiftRng { |
111 | x: w(u32::from_le_bytes([b[0], b[1], b[2], b[3]])), |
112 | y: w(u32::from_le_bytes([b[4], b[5], b[6], b[7]])), |
113 | z: w(u32::from_le_bytes([b[8], b[9], b[10], b[11]])), |
114 | w: w(u32::from_le_bytes([b[12], b[13], b[14], b[15]])), |
115 | }) |
116 | } |
117 | } |
118 | |