#![no_std]
use core::num::Wrapping;
#[derive(Default)]
pub struct Prns {
i: Wrapping<u64>,
}
const PRNS_MIX_S0: usize = 31;
const PRNS_MIX_S1: usize = 27;
const PRNS_MIX_S2: usize = 33;
const PRNS_MIX_M0: u64 = 0x7fb5d329728ea185;
const PRNS_MIX_M1: u64 = 0x81dadef4bc2dd44d;
const PRNS_WEYL: Wrapping<u64> = Wrapping(0x61c8864680b583eb);
const PRNS_WEYL_I: Wrapping<u64> = Wrapping(0x0e217c1e66c88cc3);
impl Prns {
pub fn mix(mut x: Wrapping<u64>) -> u64 {
x ^= x >> PRNS_MIX_S0;
x *= PRNS_MIX_M0;
x ^= x >> PRNS_MIX_S1;
x *= PRNS_MIX_M1;
x ^= x >> PRNS_MIX_S2;
x.0
}
pub fn tell(&self) -> u64 {
(self.i * PRNS_WEYL_I).0
}
pub fn at(n: u64) -> u64 {
Self::mix(PRNS_WEYL * Wrapping(n))
}
pub fn peek(&self) -> u64 {
Self::mix(self.i)
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> u64 {
let r = Self::mix(self.i);
self.i += PRNS_WEYL;
r
}
pub fn prev(&mut self) -> u64 {
let r = Self::mix(self.i);
self.i -= PRNS_WEYL;
r
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let mut rng = Prns::default();
assert_eq!(rng.next(), 0);
assert_eq!(rng.next(), 16997136850213553216);
assert_eq!(rng.next(), 16093987548892232582);
assert_eq!(rng.next(), 7101631883897567084);
assert_eq!(rng.next(), 197735962506217616);
assert_eq!(rng.tell(), 5);
assert_eq!(Prns::at(5), 12951196477222847639);
assert_eq!(rng.peek(), 12951196477222847639);
assert_eq!(rng.prev(), 12951196477222847639);
}
}