1 use std::cell::RefCell;
2 
3 pub struct XorShift64 {
4     a: u64,
5 }
6 
7 impl XorShift64 {
new(seed: u64) -> XorShift648     pub fn new(seed: u64) -> XorShift64 {
9         XorShift64 { a: seed }
10     }
11 
next(&mut self) -> u6412     pub fn next(&mut self) -> u64 {
13         let mut x = self.a;
14         x ^= x << 13;
15         x ^= x >> 7;
16         x ^= x << 17;
17         self.a = x;
18         x
19     }
20 
next_f64(&mut self) -> f6421     pub fn next_f64(&mut self) -> f64 {
22         sample(self.next())
23     }
24 }
25 
26 thread_local! {
27     pub static RNG: RefCell<XorShift64> = RefCell::new(XorShift64::new(1234));
28 }
29 
30 // Copied from `rand` with minor modifications.
sample(value: u64) -> f6431 fn sample(value: u64) -> f64 {
32     let fraction_bits = 52;
33 
34     // Multiply-based method; 24/53 random bits; [0, 1) interval.
35     // We use the most significant bits because for simple RNGs
36     // those are usually more random.
37     let float_size = std::mem::size_of::<f64>() as u32 * 8;
38     let precision = fraction_bits + 1;
39     let scale = 1.0 / ((1_u64 << precision) as f64);
40 
41     let value = value >> (float_size - precision);
42     scale * (value as f64)
43 }
44 
thread_rng() -> impl Fn() -> f3245 pub fn thread_rng() -> impl Fn() -> f32 {
46     || RNG.with(|rng| rng.borrow_mut().next_f64() as f32)
47 }
48 
49 #[test]
test_rng()50 fn test_rng() {
51     const ITERATIONS: usize = 10000;
52 
53     let mut rng = XorShift64::new(1234);
54     let mut sum = rng.next_f64();
55     let mut min = sum;
56     let mut max = sum;
57     for _ in 0..ITERATIONS - 1 {
58         let value = rng.next_f64();
59         sum += value;
60         if value < min {
61             min = value;
62         }
63         if value > max {
64             max = value;
65         }
66     }
67 
68     let avg = sum / ITERATIONS as f64;
69 
70     // Make sure the RNG is uniform.
71     assert!(min >= 0.000);
72     assert!(min <= 0.001);
73     assert!(max <= 1.000);
74     assert!(max >= 0.999);
75     assert!(avg >= 0.490);
76     assert!(avg <= 0.510);
77 }
78