use crate::{EntropySource, Rng};
#[allow(clippy::module_name_repetitions)]
pub struct Xoshiro256pp {
state: [u64; 4],
}
impl Xoshiro256pp {
pub fn from_entropy<T>(entropy_source: &mut T) -> Self
where
T: EntropySource,
{
Self {
state: core::array::from_fn(|_| entropy_source.seed::<u64>()),
}
}
#[must_use]
pub fn from_seed(seed: [u64; 4]) -> Self {
Self { state: seed }
}
#[inline]
fn next_random(&mut self) -> u64 {
let result = (self.state[0].wrapping_add(self.state[3]))
.rotate_left(23)
.wrapping_add(self.state[0]);
let t = self.state[1] << 17;
self.state[2] ^= self.state[0];
self.state[3] ^= self.state[1];
self.state[1] ^= self.state[2];
self.state[0] ^= self.state[3];
self.state[2] ^= t;
self.state[3] = self.state[3].rotate_left(45);
result
}
}
impl Rng for Xoshiro256pp {
#[allow(clippy::cast_possible_truncation)]
#[inline]
fn random_u32(&mut self) -> u32 {
self.random_u64() as u32
}
#[inline]
fn random_u64(&mut self) -> u64 {
self.next_random()
}
}
#[cfg(test)]
mod tests {
use super::Xoshiro256pp;
use crate::entropy::SplitMix;
use crate::rng::Rng;
struct DummyEntropy;
impl crate::EntropySource for DummyEntropy {
fn fill(&mut self, destination: &mut [u8]) {
for (inx, element) in destination.iter_mut().enumerate() {
*element = (inx + 42) as u8;
}
}
}
fn xoshiro() -> Xoshiro256pp {
Xoshiro256pp::from_entropy(&mut DummyEntropy {})
}
#[test]
fn test_xoshiro_output() {
let mut rng = Xoshiro256pp {
state: [1, 2, 3, 4],
};
assert_eq!(
vec![
41943041,
58720359,
3588806011781223,
3591011842654386,
9228616714210784205,
9973669472204895162,
14011001112246962877,
12406186145184390807,
15849039046786891736,
10450023813501588000,
],
rng.iter().take(10).collect::<Vec<u64>>()
);
}
#[test]
fn test_xoshiro_from_seed() {
let mut rng = Xoshiro256pp::from_entropy(&mut SplitMix::new(0u64));
assert_eq!(
vec![
5987356902031041503,
7051070477665621255,
6633766593972829180,
211316841551650330,
9136120204379184874,
379361710973160858,
15813423377499357806,
15596884590815070553,
5439680534584881407,
1369371744833522710,
],
rng.iter().take(10).collect::<Vec<u64>>()
);
}
#[test]
fn test_xoshiro_random() {
let mut rng = Xoshiro256pp::from_entropy(&mut SplitMix::new(0u64));
assert_eq!(rng.random::<u64>(), 5987356902031041503)
}
#[test]
fn test_xoshiro_range() {
let mut rng = Xoshiro256pp::from_entropy(&mut SplitMix::new(0u64));
assert_eq!(rng.range(11_u8..42), 15)
}
#[test]
fn xoshiro_generate_bools() {
let mut rng = xoshiro();
assert_eq!(
vec![true, true, false, true, true, true],
rng.iter().take(6).collect::<Vec<_>>()
);
}
#[test]
fn xoshiro_generate_u8() {
let mut rng = xoshiro();
assert_eq!(
vec![93, 199, 18, 93, 255, 159],
rng.iter().take(6).collect::<Vec<u8>>()
);
}
#[test]
fn xoshiro_generate_u16() {
let mut rng = xoshiro();
assert_eq!(
vec![23389, 17863, 786, 12381, 18687, 18079],
rng.iter().take(6).collect::<Vec<u16>>()
);
}
#[test]
fn xoshiro_generate_u32() {
let mut rng = xoshiro();
assert_eq!(
vec![1599691613, 1187268039, 3807576850, 1187065949, 2131446015, 3237824159],
rng.iter().take(6).collect::<Vec<u32>>()
);
}
#[test]
fn xoshiro_generate_u128() {
let mut rng = xoshiro();
assert_eq!(
vec![
116106803150699428516699394013734913479,
216263115653590202844377321789695537245,
328425740128965645684326511152092497567,
254561204173543679954141383040234184739,
40455170329874112030313783831106647436,
309825739868400302084046781679576737863
],
rng.iter().take(6).collect::<Vec<u128>>()
);
}
#[test]
fn xoshiro_generate_usize() {
let mut rng = xoshiro();
assert_eq!(
vec![
6294162410816756573,
4666366678484141511,
11723646991005319954,
3577826909737791581,
17803995047399213311,
17636447047143736991
],
rng.iter().take(6).collect::<Vec<usize>>()
);
}
#[test]
fn xoshiro_fill_u32() {
let mut rng = xoshiro();
let mut data = [0_u32; 4];
rng.fill(&mut data);
assert_eq!(&vec![1599691613, 1187268039, 3807576850, 1187065949], &data);
}
#[test]
fn xoshiro_fill_u8() {
let mut rng = xoshiro();
let mut data = [0_u8; 4];
rng.fill_u8(&mut data);
assert_eq!(&vec![93, 91, 89, 95], &data);
}
#[test]
fn xoshiro_bounded_range_f64() {
let mut rng = xoshiro();
let mut min = 42_f64;
let mut max = 4_f64;
for _ in 0..100 * 256 {
let value: f64 = rng.range(4.0..42.0);
assert!(value >= 4.0);
assert!(value <= 42.0);
min = min.min(value);
max = max.max(value);
}
assert!(min < 4.01);
assert!(max >= 41.99);
}
#[test]
fn xoshiro_bounded_range_f32() {
let mut rng = xoshiro();
let mut min = 42_f32;
let mut max = 4_f32;
for _ in 0..100 * 256 {
let value: f32 = rng.range(4.0..42.0);
assert!(value >= 4.0);
assert!(value <= 42.0);
min = min.min(value);
max = max.max(value);
}
assert!(min < 4.01);
assert!(max >= 41.99);
}
}