-
Notifications
You must be signed in to change notification settings - Fork 0
/
rand.rs
103 lines (84 loc) · 2.19 KB
/
rand.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// https://burtleburtle.net/bob/rand/smallprng.html
use std::cell::RefCell;
use std::num::Wrapping;
thread_local! { static RAND: RefCell<Rand> = RefCell::new(Rand::new_from_time()); }
#[derive(Copy, Clone)]
pub struct Rand {
a: Wrapping<u32>,
b: Wrapping<u32>,
c: Wrapping<u32>,
d: Wrapping<u32>,
}
impl Rand {
pub fn new(seed: u32) -> Self {
#[allow(clippy::unreadable_literal)]
let mut rand = Rand {
a: Wrapping(0xf1ea5eed),
d: Wrapping(seed),
c: Wrapping(seed),
b: Wrapping(seed),
};
for _ in 0..20 {
rand.next();
}
rand
}
pub fn new_from_time() -> Self {
use std::time::SystemTime;
let seed = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
Rand::new(seed as _)
}
pub fn next(&mut self) -> u32 {
let rot = |x, k| (x << k) | (x >> (32 - k));
let e = self.a - rot(self.b, 27);
self.a = self.b ^ rot(self.c, 17);
self.b = self.c + self.d;
self.c = self.d + e;
self.d = e + self.a;
self.d.0
}
pub fn next_f32(&mut self) -> f32 {
self.next() as f32 / u32::MAX as f32
}
pub fn next_between_f32(&mut self, min: f32, max: f32) -> f32 {
min + (max - min) * self.next_f32()
}
}
pub fn rand() -> f32 {
RAND.with(|r| r.borrow_mut().next_f32())
}
pub fn rand_between(min: f32, max: f32) -> f32 {
RAND.with(|r| r.borrow_mut().next_between_f32(min, max))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tests_rand() {
let seed = 42;
let mut rand = Rand::new(seed);
let mut v = 0;
for _ in 0..100 {
v = rand.next();
}
assert_eq!(v, 3863832633);
}
#[test]
fn tests_rand_next_f32() {
let seed = 42;
let mut rand = Rand::new(seed);
let mut v = 0.0;
for _ in 0..100 {
v = rand.next_f32();
}
assert_eq!(v, 0.8996186);
}
#[test]
fn tests_rand_time_seed() {
let mut rand = Rand::new_from_time();
assert_ne!(rand.next(), 0);
}
}