pub const LCG_M128_1: u128 = 0xde92a69f6e2f9f25fd0d90f576075fbd;
pub const LCG_M128_2: u128 = 0x576bc0a2178fcf7c619f3ebc7363f7f5;
pub const LCG_M128_3: u128 = 0x87ea3de194dd2e97074f3d0c2ea63d35;
pub const LCG_M128_4: u128 = 0xf48c0745581cf801619cd45257f0ab65;
pub const LCG_M65_1: u128 = 0x1df77a66a374e300d;
pub const LCG_M65_2: u128 = 0x1d605bbb58c8abbfd;
pub const LCG_M65_3: u128 = 0x1d7d8dd3a6a72b43d;
pub const LCG_M65_4: u128 = 0x1f20529e418340d05;
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct Rnd {
lcg0: u64,
lcg1: u64,
stream: u64,
}
impl Default for Rnd {
fn default() -> Self {
Rnd::new()
}
}
#[inline(always)]
fn origin_0(stream: u64) -> u64 {
!stream
}
#[inline(always)]
fn origin_128(stream: u64) -> u128 {
origin_0(stream) as u128
}
impl Rnd {
#[inline(always)]
fn lcg_128(&self) -> u128 {
self.lcg0 as u128 | ((self.lcg1 as u128) << 64)
}
#[inline(always)]
fn multiplier(&self) -> u64 {
LCG_M65_1 as u64
}
#[inline(always)]
fn multiplier_128(&self) -> u128 {
LCG_M65_1
}
#[inline(always)]
fn increment_128(&self) -> u128 {
((self.stream as u128) << 1) | 1
}
#[inline(always)]
fn origin_0(&self) -> u64 {
origin_0(self.stream)
}
#[inline(always)]
fn origin_128(&self) -> u128 {
origin_128(self.stream)
}
#[inline]
pub fn step(&mut self) -> u64 {
let lcg = (self.lcg0 as u128)
.wrapping_mul(self.multiplier() as u128)
.wrapping_add(self.increment_128());
self.lcg1 = ((lcg >> 64) as u64)
.wrapping_add(self.lcg1.wrapping_mul(self.multiplier()))
.wrapping_add(self.lcg0);
self.lcg0 = lcg as u64;
self.get()
}
#[inline]
pub fn get(&self) -> u64 {
let x = self.lcg1;
let x = (x ^ (x >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
let x = (x ^ (x >> 27)).wrapping_mul(0x94d049bb133111eb);
let x = (x ^ (x >> 31)).wrapping_mul(0xd6e8feb86659fd93);
x ^ (x >> 32)
}
#[inline(always)]
pub fn new() -> Self {
Rnd {
lcg0: origin_0(0),
lcg1: 0,
stream: 0,
}
}
#[inline(always)]
pub fn from_u32(seed: u32) -> Self {
Rnd::from_u64(seed as u64)
}
#[inline(always)]
pub fn from_u64(seed: u64) -> Self {
Rnd {
lcg0: origin_0(seed),
lcg1: 0,
stream: seed,
}
}
pub fn from_u128(seed: u128) -> Self {
let mut krull = Rnd::from_u64(((seed >> 64) ^ seed) as u64);
krull.set_position(seed << 64);
krull
}
#[cfg(feature = "std")]
pub fn from_time() -> Self {
let start = std::time::SystemTime::now();
let since_epoch = start
.duration_since(std::time::UNIX_EPOCH)
.expect("Time went antediluvian?");
let ns = since_epoch.as_nanos();
Self::from_u64(ns as u64)
}
pub fn jump(&mut self, steps: i128) {
let lcg = super::lcg::get_state(
self.multiplier_128(),
self.increment_128(),
self.lcg_128(),
steps as u128,
);
self.lcg0 = lcg as u64;
self.lcg1 = (lcg >> 64) as u64;
}
pub fn position(&self) -> u128 {
super::lcg::get_iterations(
self.multiplier_128(),
self.increment_128(),
self.origin_128(),
self.lcg_128(),
)
}
pub fn set_position(&mut self, position: u128) {
let lcg = super::lcg::get_state(
self.multiplier_128(),
self.increment_128(),
self.origin_128(),
position,
);
self.lcg0 = lcg as u64;
self.lcg1 = (lcg >> 64) as u64;
}
#[inline]
pub fn reset(&mut self) {
self.lcg0 = self.origin_0();
self.lcg1 = 0;
}
#[inline]
pub fn stream(&self) -> u64 {
self.stream
}
#[inline]
pub fn set_stream(&mut self, stream: u64) {
self.stream = stream;
self.reset();
}
#[inline]
pub fn u32(&mut self) -> u32 {
self.step() as u32
}
#[inline]
pub fn u64(&mut self) -> u64 {
self.step()
}
#[inline]
pub fn i32(&mut self) -> i32 {
self.step() as i32
}
#[inline]
pub fn i64(&mut self) -> i64 {
self.step() as i64
}
#[inline]
pub fn u128(&mut self) -> u128 {
self.step() as u128 | ((self.step() as u128) << 64)
}
#[inline]
pub fn u64_in(&mut self, min: u64, max: u64) -> u64 {
assert!(max >= min);
let diff = max - min;
if diff < u64::MAX {
(self.u64() % (diff + 1)).wrapping_add(min)
} else {
self.u64()
}
}
#[inline]
pub fn u32_in(&mut self, min: u32, max: u32) -> u32 {
self.u64_in(min as u64, max as u64) as u32
}
#[inline]
pub fn i64_in(&mut self, min: i64, max: i64) -> i64 {
let range = (max as u64).wrapping_sub(min as u64);
if range == u64::MAX {
self.u64() as i64
} else {
(self.u64_in(0, range).wrapping_add(min as u64)) as i64
}
}
#[inline]
pub fn i32_in(&mut self, min: i32, max: i32) -> i32 {
self.i64_in(min as i64, max as i64) as i32
}
#[inline]
pub fn u64_to(&mut self, limit: u64) -> u64 {
assert!(limit > 0);
self.u64_in(0, limit - 1)
}
#[inline]
pub fn u32_to(&mut self, limit: u32) -> u32 {
self.u64_to(limit as u64) as u32
}
#[inline]
pub fn i64_to(&mut self, limit: i64) -> i64 {
assert!(limit > 0);
self.i64_in(0, limit - 1)
}
#[inline]
pub fn i32_to(&mut self, limit: i32) -> i32 {
self.i64_to(limit as i64) as i32
}
#[inline]
pub fn f64(&mut self) -> f64 {
(self.step() as f64) / ((1u128 << 64) as f64)
}
#[inline]
pub fn f64_in(&mut self, min: f64, max: f64) -> f64 {
min + (max - min) * self.f64()
}
#[inline]
pub fn f32(&mut self) -> f32 {
(self.step() as f32) / ((1u128 << 64) as f32)
}
#[inline]
pub fn f32_in(&mut self, min: f32, max: f32) -> f32 {
min + (max - min) * self.f32()
}
#[inline]
pub fn bool(&mut self, p: f64) -> bool {
self.f64() < p
}
pub fn fill_bytes(&mut self, dest: &mut [u8]) {
let bytes = dest.len();
let mut i = 0;
while i < bytes {
let x = self.step();
let j = bytes.min(i + 8);
dest[i..j].copy_from_slice(&x.to_le_bytes()[0..(j - i)]);
i = j;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn run_tests() {
let krull64_expected: [u64; 16] = [
0x57c1b6c1df5ed4d2,
0x1efdba83398cf412,
0xa02d8dfda06ac9ce,
0xf6e3f32be5e81841,
0xc2a690083e597e0d,
0x3b1b2ed3fa6c15aa,
0x241c691340a479b2,
0x88c24c8d79bb67c1,
0x09f213c4fc2b61dc,
0xa4b6ad95c713c951,
0xa43904ae3341edf7,
0xee2dca4d5fd5f8fa,
0x27bdddbeaa4aadb0,
0x98c78e68dbf634b2,
0xf0edc57017a0d5a5,
0x8647ea5de51eca23,
];
let mut krull64 = Rnd::from_u64(0);
for x in krull64_expected {
assert_eq!(x, krull64.u64());
}
let mut r: u128 = 0;
let mut rnd = || -> u128 {
r = r.wrapping_mul(LCG_M128_1).wrapping_add(0xffff);
r
};
for _ in 0..1 << 12 {
let seed = rnd() as u64;
let mut krull1 = Rnd::new();
assert_eq!(0, krull1.stream());
assert_eq!(0, krull1.position());
krull1.set_stream(seed);
assert_eq!(seed, krull1.stream());
assert_eq!(0, krull1.position());
let mut krull2 = Rnd::from_u64(seed);
assert_eq!(seed, krull2.stream());
assert_eq!(0, krull2.position());
let pos2 = rnd();
let pos1 = pos2 & rnd();
krull1.set_position(pos1);
krull2.set_position(pos2);
assert_eq!(pos1, krull1.position());
assert_eq!(pos2, krull2.position());
krull1.jump((pos2 - pos1) as i128);
assert_eq!(pos2, krull1.position());
assert_eq!(krull1.u64(), krull2.u64());
krull1.jump(-1);
assert_eq!(pos2, krull1.position());
krull2.jump(-1);
assert_eq!(pos2, krull2.position());
krull1.jump(-((pos2 - pos1) as i128));
assert_eq!(pos1, krull1.position());
let n = 1 + (rnd() & 0x3ff);
for _ in 0..n {
krull1.u64();
}
assert_eq!(pos1 + n, krull1.position());
assert_eq!(seed, krull1.stream());
let bytes = 1 + (rnd() & 0x7f);
let mut buffer1 = [0u8; 0x80];
let mut buffer2 = [0u8; 0x80];
krull1.reset();
assert_eq!(0, krull1.position());
krull1.fill_bytes(&mut buffer1[0..bytes as usize]);
krull2.reset();
for i in 0..0x10 {
let x = krull2.u64();
buffer2[(i << 3)..((i + 1) << 3)].copy_from_slice(&x.to_le_bytes());
}
assert!(buffer1[0..bytes as usize]
.iter()
.zip(buffer2[0..bytes as usize].iter())
.all(|(x, y)| x == y));
}
}
}