use std::cmp;
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
static SEED: AtomicU32 = AtomicU32::new(0);
fn rand_seed() -> u32 {
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos() as u32;
return seed;
}
pub fn rand(n: u64) -> Vec<f64> {
let _ = SEED.compare_exchange(0, rand_seed(), Ordering::Relaxed, Ordering::Relaxed);
let a: u32 = 22_695_477;
let c: u32 = 1;
let mut x: u32 = SEED.load(Ordering::Relaxed) & 0x7FFFFFFF;
let mut r: Vec<f64> = Vec::new();
for _ in 0..n {
x = x.wrapping_mul(a).wrapping_add(c) & 0x7FFFFFFF;
SEED.store(x, Ordering::Relaxed);
r.push((x >> 16) as f64 / 32768.0);
}
return r;
}
pub fn rand1() -> f64 {
let r = rand(1);
return r[0];
}
pub fn randi(n: u64, start: i64, end: i64) -> Vec<i64> {
let min = cmp::min(start, end) as i64;
let max = cmp::max(start, end) as i64 + 1;
let length = (max - min) as f64;
let r = rand(n);
return r
.into_iter()
.map(|x| min + (length * x).floor() as i64)
.collect();
}
pub fn randi1(start: i64, end: i64) -> i64 {
return randi(1, start, end)[0];
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
#[test]
fn check_rand1() {
let n = 1000_000;
for _ in 0..n {
let r = rand1();
assert!(r >= 0.);
assert!(r < 1.);
}
}
#[test]
fn check_rand() {
let r: Vec<f64> = rand(1000_000);
let count: usize = r.iter().len();
let mu: f64 = r.iter().sum::<f64>() / count as f64;
let var = r
.iter()
.map(|v| {
let distance = *v - mu;
distance * distance
})
.sum::<f64>()
/ count as f64;
let er_mu = (0.5 - (mu * 1e4).round() / 1e4).abs();
assert!(er_mu < 0.01);
let er_var = (1. / 12. - (var * 1e4).round() / 1e4).abs();
assert!(er_var < 0.001);
}
#[test]
fn check_randi() {
let n = 1000_000;
let a = -2;
let b = 3;
let r = randi(n, a, b);
let set_test: HashSet<i64> = r.iter().clone().into_iter().map(|x| *x).collect();
let set_true: HashSet<i64> = HashSet::from([-2, -1, 0, 1, 2, 3]);
assert_eq!(set_test, set_true);
}
#[test]
fn check_randi1() {
let a = -10;
let b = 10;
let n = 10_000;
for _ in 0..n {
let r = randi1(a, b);
assert!((a..=b).contains(&r));
}
}
}