#[derive(Copy, Clone, Debug)]
pub struct Rng {
random: u32,
}
impl Rng {
#[must_use]
pub fn new() -> Self {
Self {
random: Self::seed(), }
}
#[must_use]
pub fn new_from_seed(seed: u32) -> Self {
Self { random: seed }
}
#[cfg(not(tarpaulin_include))]
#[allow(clippy::cast_possible_truncation)]
fn seed() -> u32 {
use std::hash::{BuildHasher, Hasher};
let seed = std::collections::hash_map::RandomState::new()
.build_hasher()
.finish() as u32;
if seed == 0 {
1 } else {
seed
}
}
#[must_use]
pub fn urand(&mut self) -> u32 {
self.random ^= self.random.wrapping_shl(13);
self.random ^= self.random.wrapping_shr(17);
self.random ^= self.random.wrapping_shl(5);
self.random
}
#[allow(clippy::cast_possible_wrap)]
#[must_use]
pub fn irand(&mut self) -> i32 {
self.urand() as i32
}
#[must_use]
pub fn frand(&mut self) -> f64 {
f64::from(self.urand()) / f64::from(u32::MAX)
}
#[must_use]
pub fn urand_between(&mut self, min: u32, max: u32) -> u32 {
if min == max {
return min;
}
if min > max {
return self.urand_between(max, min);
}
min + self.urand() % (max - min + 1)
}
#[must_use]
pub fn irand_between(&mut self, min: i32, max: i32) -> i32 {
if min == max {
return min;
}
if min > max {
return self.irand_between(max, min);
}
min + ((self.irand() % (max - min + 1)) + (max - min + 1)) % (max - min + 1)
}
#[must_use]
pub fn frand_between(&mut self, min: f64, max: f64) -> f64 {
if (min - max).abs() < 0.000_000_1 {
return min;
}
if min > max {
return self.frand_between(max, min);
}
min + self.frand() * (max - min)
}
pub fn shuffle<T>(&mut self, data: &mut [T]) {
for i in (1..data.len()).rev() {
let j = (self.urand() as usize) % (i + 1);
data.swap(i, j);
}
}
#[must_use]
pub fn sample<T: Clone>(&mut self, data: &[T], n: usize) -> Vec<T> {
assert!(!data.is_empty(), "cannot sample from empty data");
let mut data: Vec<T> = data.to_vec();
let mut sample = Vec::with_capacity(n);
while sample.len() < n {
self.shuffle(&mut data);
sample.extend(data.iter().take(n - sample.len()).cloned());
}
#[cfg(not(tarpaulin_include))] {
sample
}
}
}
impl Default for Rng {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rng_new() {
let rng = Rng::new();
assert_ne!(rng.random, 0);
}
#[test]
fn rng_default() {
let rng = Rng::default();
assert_ne!(rng.random, 0);
}
#[test]
fn rng_seeded() {
let rng = Rng::new_from_seed(92);
assert_eq!(rng.random, 92);
}
#[test]
fn rng_seeded_is_deterministic() {
let mut rng = Rng::new_from_seed(92);
let mut numbers = Vec::with_capacity(20);
for _ in 0..20 {
numbers.push(rng.urand());
}
assert_eq!(
numbers,
[
24_873_849,
1_921_449_235,
163_429_281,
1_743_871_077,
3_284_570_427,
769_573_035,
1_286_640_526,
2_263_802_158,
61_506_859,
855_005_484,
3_282_509_157,
561_906_016,
3_407_628_521,
36_205_769,
2_593_849_521,
2_871_452_439,
2_680_368_661,
3_124_728_245,
1_227_596_689,
2_523_544_221
]
);
}
#[test]
fn rng_urand() {
let mut rng = Rng::new();
for _ in 0..100_000 {
_ = rng.urand();
}
}
#[test]
fn rng_irand() {
let mut rng = Rng::new();
for _ in 0..100_000 {
_ = rng.irand();
}
}
#[test]
fn rng_frand() {
let mut rng = Rng::new();
for _ in 0..100_000 {
_ = rng.frand();
}
}
#[test]
fn rng_urand_between() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.urand_between(10, 20);
assert!((10..=20).contains(&res), "min=10, max=20, res={res}");
}
}
#[test]
fn rng_urand_between_min_eq_max() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.urand_between(20, 20);
assert_eq!(res, 20, "min=20, max=20, res={res}");
}
}
#[test]
fn rng_urand_between_min_gt_max() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.urand_between(20, 10);
assert!((10..=20).contains(&res), "min=10, max=20, res={res}");
}
}
#[test]
fn rng_irand_between_positive() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.irand_between(10, 20);
assert!((10..=20).contains(&res), "min=10, max=20, res={res}");
}
}
#[test]
fn rng_irand_between_negative() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.irand_between(-20, -10);
assert!((-20..=-10).contains(&res), "min=-20, max=-10, res={res}");
}
}
#[test]
fn rng_irand_between_negative_and_positive() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.irand_between(-20, 10);
assert!((-20..=10).contains(&res), "min=-20, max=10, res={res}");
}
}
#[test]
fn rng_irand_between_min_eq_max() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.irand_between(20, 20);
assert_eq!(res, 20, "min=20, max=20, res={res}");
}
}
#[test]
fn rng_irand_between_min_gt_max() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.irand_between(20, 10);
assert!((10..=20).contains(&res), "min=10, max=20, res={res}");
}
}
#[test]
fn rng_frand_between_positive() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.frand_between(1.5, 3.5);
assert!((1.5..=3.5).contains(&res), "min=1.5, max=3.5, res={res:.2}");
}
}
#[test]
fn rng_frand_between_negative() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.frand_between(-3.5, -1.5);
assert!(
(-3.5..=-1.5).contains(&res),
"min=-3.5, max=-1.5, res={res:.2}"
);
}
}
#[test]
fn rng_frand_between_negative_and_positive() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.frand_between(-3.5, 1.5);
assert!(
(-3.5..=1.5).contains(&res),
"min=-3.5, max=1.5, res={res:.2}"
);
}
}
#[test]
fn rng_frand_between_min_eq_max() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.frand_between(3.5, 3.5);
assert!(
(res - 3.5).abs() < 0.000_000_1,
"min=3.5, max=3.5, res={res:.2}"
);
}
}
#[test]
fn rng_frand_between_min_gt_max() {
let mut rng = Rng::new();
for _ in 0..100_000 {
let res = rng.frand_between(3.5, 1.5);
assert!((1.5..=3.5).contains(&res), "min=1.5, max=3.5, res={res:.2}");
}
}
#[test]
fn rng_shuffle() {
let mut rng = Rng::new_from_seed(92);
let mut numbers = vec![0, 1, 2, 3, 4, 5];
rng.shuffle(&mut numbers);
assert_ne!(numbers, [0, 1, 2, 3, 4, 5]);
assert_eq!(numbers.len(), 6);
numbers.sort_unstable();
assert_eq!(numbers, [0, 1, 2, 3, 4, 5]);
}
#[test]
fn rng_sample() {
let mut rng = Rng::new();
let numbers = vec![0, 1, 2, 3, 4, 5];
let sample = rng.sample(&numbers, 3);
assert_eq!(sample.len(), 3);
for x in sample {
assert!(numbers.contains(&x));
}
}
#[test]
fn rng_sample_n_gt_data_len() {
let mut rng = Rng::new();
let numbers = vec![0, 1, 2, 3, 4, 5];
let sample = rng.sample(&numbers, 10_000);
assert_eq!(sample.len(), 10_000);
for x in sample {
assert!(numbers.contains(&x));
}
}
#[test]
#[should_panic(expected = "cannot sample from empty data")]
fn rng_sample_empty_data_panics() {
let mut rng = Rng::new();
let numbers: Vec<i32> = Vec::new();
_ = rng.sample(&numbers, 10);
}
}