#![no_std]
#![doc = include_str!("../README.md")]
mod seed;
pub use rand_core;
use rand_core::{RngCore, SeedableRng};
pub use seed::Seed;
pub struct CLRRandom {
inext: usize,
inextp: usize,
seed_array: [i32; 56],
}
impl CLRRandom {
const MBIG: i32 = i32::MAX;
const MSEED: i32 = 161803398;
fn initialize(seed: i32) -> Self {
let mut rng = CLRRandom {
inext: 0,
inextp: 0,
seed_array: [0; 56],
};
let subtraction = if seed == i32::MIN {
i32::MAX
} else {
seed.abs()
};
let mut mj = Self::MSEED.wrapping_sub(subtraction);
rng.seed_array[55] = mj;
let mut mk = 1;
for i in 1..55 {
let ii = (21 * i) % 55;
rng.seed_array[ii] = mk;
mk = mj.wrapping_sub(mk);
if mk < 0 {
mk = mk.wrapping_add(Self::MBIG);
}
mj = rng.seed_array[ii];
}
for _k in 1..5 {
for i in 1..56 {
rng.seed_array[i] =
rng.seed_array[i].wrapping_sub(rng.seed_array[1 + ((i + 30) % 55)]);
if rng.seed_array[i] < 0 {
rng.seed_array[i] = rng.seed_array[i].wrapping_add(Self::MBIG);
}
}
}
rng.inextp = 21;
rng
}
fn internal_sample(&mut self) -> i32 {
let mut loc_inext = self.inext;
let mut loc_inextp = self.inextp;
loc_inext = loc_inext.wrapping_add(1);
if loc_inext >= 56 {
loc_inext = 1;
}
loc_inextp = loc_inextp.wrapping_add(1);
if loc_inextp >= 56 {
loc_inextp = 1;
}
let mut ret_val = self.seed_array[loc_inext].wrapping_sub(self.seed_array[loc_inextp]);
if (ret_val) == Self::MBIG {
ret_val = ret_val.wrapping_sub(1);
}
if ret_val < 0 {
ret_val = ret_val.wrapping_add(Self::MBIG);
}
self.seed_array[loc_inext] = ret_val;
self.inext = loc_inext;
self.inextp = loc_inextp;
ret_val
}
fn sample(&mut self) -> f64 {
self.internal_sample() as f64 * (1.0 / Self::MBIG as f64)
}
pub fn next_i32(&mut self) -> i32 {
self.internal_sample()
}
pub fn next_i64(&mut self) -> i64 {
let high = self.internal_sample() as i64;
let low = (self.internal_sample() as u32) as i64;
high << 32 | low
}
pub fn next_f64(&mut self) -> f64 {
let res = self.sample();
assert!(res < 1.0 && res >= 0.0);
res
}
}
impl RngCore for CLRRandom {
fn next_u32(&mut self) -> u32 {
self.internal_sample() as u32
}
fn next_u64(&mut self) -> u64 {
let high = self.internal_sample() as u64;
let low = self.internal_sample() as u64;
high << 32 | low
}
fn fill_bytes(&mut self, dst: &mut [u8]) {
for b in dst.iter_mut() {
*b = (self.internal_sample() % 256) as u8;
}
}
}
impl SeedableRng for CLRRandom {
type Seed = Seed;
fn from_seed(seed: Self::Seed) -> Self {
Self::initialize(seed.seed)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn simple() {
let mut rand = CLRRandom::from_seed(0.into());
assert_eq!(rand.next_i32(), 1559595546);
assert_eq!(rand.next_i32(), 1755192844);
}
#[test]
fn simple_float() {
let mut rand = CLRRandom::from_seed(42.into());
assert_eq!(rand.next_f64(), 0.6681064659115423);
assert_eq!(rand.next_f64(), 0.14090729837348093);
}
#[test]
fn complex() {
let mut rand = CLRRandom::from_seed(1919810.into());
assert_eq!(rand.next_i32(), 147482110);
assert_eq!(rand.next_i32(), 1747108798);
assert_eq!(rand.next_i32(), 1937076328);
let mut array = [0; 10];
rand.fill_bytes(&mut array);
assert_eq!(array, [255, 178, 141, 186, 113, 4, 147, 197, 124, 251]);
assert_eq!(rand.next_i32(), 1584818534);
assert_eq!(rand.next_i32(), 2082382094);
}
}