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) -> f6431fn 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() -> f3245pub fn thread_rng() -> impl Fn() -> f32 { 46 || RNG.with(|rng| rng.borrow_mut().next_f64() as f32) 47 } 48 49 #[test] test_rng()50fn 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