quantre/random/
rng_uniform.rs1use std::cmp;
4use std::sync::atomic::AtomicU32;
5use std::sync::atomic::Ordering;
6use std::time::SystemTime;
7use std::time::UNIX_EPOCH;
8
9static SEED: AtomicU32 = AtomicU32::new(0);
11
12fn rand_seed() -> u32 {
14 let seed = SystemTime::now()
15 .duration_since(UNIX_EPOCH)
16 .unwrap()
17 .as_nanos() as u32;
18 return seed;
19}
20
21pub fn rand(n: u64) -> Vec<f64> {
30 let _ = SEED.compare_exchange(0, rand_seed(), Ordering::Relaxed, Ordering::Relaxed);
32
33 let a: u32 = 22_695_477;
34 let c: u32 = 1;
35
36 let mut x: u32 = SEED.load(Ordering::Relaxed) & 0x7FFFFFFF;
38 let mut r: Vec<f64> = Vec::new();
39 for _ in 0..n {
40 x = x.wrapping_mul(a).wrapping_add(c) & 0x7FFFFFFF;
42 SEED.store(x, Ordering::Relaxed);
43
44 r.push((x >> 16) as f64 / 32768.0);
49 }
50 return r;
51}
52
53pub fn rand1() -> f64 {
55 let r = rand(1);
56 return r[0];
57}
58
59pub fn randi(n: u64, start: i64, end: i64) -> Vec<i64> {
61 let min = cmp::min(start, end) as i64;
62 let max = cmp::max(start, end) as i64 + 1;
63 let length = (max - min) as f64;
64 let r = rand(n);
65 return r
66 .into_iter()
67 .map(|x| min + (length * x).floor() as i64)
68 .collect();
69}
70
71pub fn randi1(start: i64, end: i64) -> i64 {
73 return randi(1, start, end)[0];
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use std::collections::HashSet;
80
81 #[test]
83 fn check_rand1() {
84 let n = 1000_000;
85 for _ in 0..n {
86 let r = rand1();
87 assert!(r >= 0.);
88 assert!(r < 1.);
89 }
90 }
91
92 #[test]
94 fn check_rand() {
95 let r: Vec<f64> = rand(1000_000);
96 let count: usize = r.iter().len();
97 let mu: f64 = r.iter().sum::<f64>() / count as f64;
98 let var = r
99 .iter()
100 .map(|v| {
101 let distance = *v - mu;
102 distance * distance
103 })
104 .sum::<f64>()
105 / count as f64;
106
107 let er_mu = (0.5 - (mu * 1e4).round() / 1e4).abs();
109 assert!(er_mu < 0.01);
110
111 let er_var = (1. / 12. - (var * 1e4).round() / 1e4).abs();
113 assert!(er_var < 0.001);
114 }
115
116 #[test]
118 fn check_randi() {
119 let n = 1000_000;
120 let a = -2;
121 let b = 3;
122 let r = randi(n, a, b);
123 let set_test: HashSet<i64> = r.iter().clone().into_iter().map(|x| *x).collect();
124 let set_true: HashSet<i64> = HashSet::from([-2, -1, 0, 1, 2, 3]);
125 assert_eq!(set_test, set_true);
126 }
127
128 #[test]
130 fn check_randi1() {
131 let a = -10;
132 let b = 10;
133 let n = 10_000;
134 for _ in 0..n {
135 let r = randi1(a, b);
136 assert!((a..=b).contains(&r));
137 }
138 }
139}