use core::fmt;
use rand_core::{Error, le, RngCore, SeedableRng};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
const MULTIPLIER: u64 = 0xfeb3_4465_7c0a_f413;
#[derive(Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct Mwc256XXA64 {
x1: u64,
x2: u64,
x3: u64,
c: u64,
}
impl Mwc256XXA64 {
pub fn new(k1: u64, k2: u64) -> Self {
Mwc256XXA64::from_state_incr(k1, k2, 0xcafef00dd15ea5e5, 0x14057B7EF767814F)
}
#[inline]
fn from_state_incr(x1: u64, x2: u64, x3: u64, c: u64) -> Self {
let mut pcg = Mwc256XXA64 { x1, x2, x3, c };
pcg.gen6();
pcg
}
#[inline]
fn gen6(&mut self) -> [u64; 6] {
let mut result = [0; 6];
let (low, hi) = multiply(self.x3);
result[0] = permute(self.x1, self.x2, self.x3, self.c, low, hi);
let (r1, b) = low.overflowing_add(self.c);
let c = hi.wrapping_add(b as u64);
let (low, hi) = multiply(self.x2);
result[1] = permute(r1, self.x1, self.x2, c, low, hi);
let (r2, b) = low.overflowing_add(c);
let c = hi.wrapping_add(b as u64);
let (low, hi) = multiply(self.x1);
result[2] = permute(r2, r1, self.x1, c, low, hi);
let (r3, b) = low.overflowing_add(c);
let c = hi.wrapping_add(b as u64);
let (low, hi) = multiply(r1);
result[3] = permute(r3, r2, r1, c, low, hi);
let (r1, b) = low.overflowing_add(c);
let c = hi.wrapping_add(b as u64);
let (low, hi) = multiply(r2);
result[4] = permute(r1, r3, r2, c, low, hi);
let (r2, b) = low.overflowing_add(c);
let c = hi.wrapping_add(b as u64);
let (low, hi) = multiply(r3);
result[5] = permute(r2, r1, r3, c, low, hi);
let (r3, b) = low.overflowing_add(c);
let c = hi.wrapping_add(b as u64);
self.c = c;
self.x1 = r3;
self.x2 = r2;
self.x3 = r1;
return result;
}
#[inline]
fn step(&mut self) -> u64 {
let (low, hi) = multiply(self.x3);
let result = permute(self.x1, self.x2, self.x3, self.c, low, hi);
let (x1, b) = low.overflowing_add(self.c);
self.x3 = self.x2;
self.x2 = self.x1;
self.x1 = x1;
self.c = hi.wrapping_add(b as u64);
result
}
}
#[inline(always)]
fn multiply(val: u64) -> (u64, u64) {
let t = (val as u128).wrapping_mul(MULTIPLIER as u128);
return (t as u64, (t >> 64) as u64);
}
#[inline(always)]
fn permute(x1: u64, x2: u64, x3: u64, _c: u64, _low: u64, hi: u64) -> u64 {
(x3 ^ x2).wrapping_add(x1 ^ hi)
}
impl fmt::Debug for Mwc256XXA64 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Mwc256XXA64 {{}}")
}
}
impl SeedableRng for Mwc256XXA64 {
type Seed = [u8; 32];
fn from_seed(seed: Self::Seed) -> Self {
let mut seed_u64 = [0u64; 4];
le::read_u64_into(&seed, &mut seed_u64);
let c = (seed_u64[0] & 0x3ffffffffffffff8) | 5;
let x3 = (seed_u64[3] << 2) | 1;
Mwc256XXA64::from_state_incr(seed_u64[1], seed_u64[2], x3, c)
}
}
impl RngCore for Mwc256XXA64 {
#[inline]
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
#[inline]
fn next_u64(&mut self) -> u64 {
self.step()
}
#[inline]
fn fill_bytes(&mut self, dest: &mut [u8]) {
let mut dest_chunks = dest.chunks_exact_mut(6 * 8);
for mut dest_chunk in &mut dest_chunks {
for &num in self.gen6().iter() {
let (l, r) = dest_chunk.split_at_mut(8);
l.copy_from_slice(&num.to_le_bytes());
dest_chunk = r;
}
}
for dest_chunk in dest_chunks.into_remainder().chunks_mut(8) {
dest_chunk.copy_from_slice(&self.step().to_le_bytes()[..dest_chunk.len()]);
}
}
#[inline(always)]
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
self.fill_bytes(dest);
Ok(())
}
}