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