rand_xoshiro/xoshiro512plus.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
9use rand_core::impls::fill_bytes_via_next;
10use rand_core::le::read_u64_into;
11use rand_core::{RngCore, SeedableRng};
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15use crate::Seed512;
16
17/// A xoshiro512+ random number generator.
18///
19/// The xoshiro512+ algorithm is not suitable for cryptographic purposes, but
20/// is very fast and has good statistical properties, besides a low linear
21/// complexity in the lowest bits.
22///
23/// The algorithm used here is translated from [the `xoshiro512plus.c`
24/// reference source code](http://xoshiro.di.unimi.it/xoshiro512plus.c) by
25/// David Blackman and Sebastiano Vigna.
26#[derive(Debug, Clone, PartialEq, Eq)]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28pub struct Xoshiro512Plus {
29 s: [u64; 8],
30}
31
32impl Xoshiro512Plus {
33 /// Jump forward, equivalently to 2^256 calls to `next_u64()`.
34 ///
35 /// This can be used to generate 2^256 non-overlapping subsequences for
36 /// parallel computations.
37 ///
38 /// ```
39 /// use rand_xoshiro::rand_core::SeedableRng;
40 /// use rand_xoshiro::Xoshiro512Plus;
41 ///
42 /// let rng1 = Xoshiro512Plus::seed_from_u64(0);
43 /// let mut rng2 = rng1.clone();
44 /// rng2.jump();
45 /// let mut rng3 = rng2.clone();
46 /// rng3.jump();
47 /// ```
48 pub fn jump(&mut self) {
49 impl_jump!(
50 u64,
51 self,
52 [
53 0x33ed89b6e7a353f9,
54 0x760083d7955323be,
55 0x2837f2fbb5f22fae,
56 0x4b8c5674d309511c,
57 0xb11ac47a7ba28c25,
58 0xf1be7667092bcc1c,
59 0x53851efdb6df0aaf,
60 0x1ebbc8b23eaf25db
61 ]
62 );
63 }
64
65 /// Jump forward, equivalently to 2^384 calls to `next_u64()`.
66 ///
67 /// This can be used to generate 2^128 starting points, from each of which
68 /// `jump()` will generate 2^128 non-overlapping subsequences for parallel
69 /// distributed computations.
70 pub fn long_jump(&mut self) {
71 impl_jump!(
72 u64,
73 self,
74 [
75 0x11467fef8f921d28,
76 0xa2a819f2e79c8ea8,
77 0xa8299fc284b3959a,
78 0xb4d347340ca63ee1,
79 0x1cb0940bedbff6ce,
80 0xd956c5c4fa1f8e17,
81 0x915e38fd4eda93bc,
82 0x5b3ccdfa5d7daca5
83 ]
84 );
85 }
86}
87
88impl SeedableRng for Xoshiro512Plus {
89 type Seed = Seed512;
90
91 /// Create a new `Xoshiro512Plus`. If `seed` is entirely 0, it will be
92 /// mapped to a different seed.
93 #[inline]
94 fn from_seed(seed: Seed512) -> Xoshiro512Plus {
95 deal_with_zero_seed!(seed, Self);
96 let mut state = [0; 8];
97 read_u64_into(&seed.0, &mut state);
98 Xoshiro512Plus { s: state }
99 }
100
101 /// Seed a `Xoshiro512Plus` from a `u64` using `SplitMix64`.
102 fn seed_from_u64(seed: u64) -> Xoshiro512Plus {
103 from_splitmix!(seed)
104 }
105}
106
107impl RngCore for Xoshiro512Plus {
108 #[inline]
109 fn next_u32(&mut self) -> u32 {
110 // The lowest bits have some linear dependencies, so we use the
111 // upper bits instead.
112 (self.next_u64() >> 32) as u32
113 }
114
115 #[inline]
116 fn next_u64(&mut self) -> u64 {
117 let result_plus = self.s[0].wrapping_add(self.s[2]);
118 impl_xoshiro_large!(self);
119 result_plus
120 }
121
122 #[inline]
123 fn fill_bytes(&mut self, dest: &mut [u8]) {
124 fill_bytes_via_next(self, dest);
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131
132 #[test]
133 fn reference() {
134 #[rustfmt::skip]
135 let mut rng = Xoshiro512Plus::from_seed(Seed512(
136 [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
137 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,
138 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0,
139 7, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0]));
140 // These values were produced with the reference implementation:
141 // http://xoshiro.di.unimi.it/xoshiro512plus.c
142 let expected = [
143 4,
144 8,
145 4113,
146 25169936,
147 52776585412635,
148 57174648719367,
149 9223482039571869716,
150 9331471677901559830,
151 9340533895746033672,
152 14078399799840753678,
153 ];
154 for &e in &expected {
155 assert_eq!(rng.next_u64(), e);
156 }
157 }
158}