1#[cfg(test)]
2pub mod xorshift {
3 use crate::NoiseSource;
4
5 struct BaseGenerator {
7 bit_buffer: u32,
8 bit_count: i32,
9 seed: u32,
10 }
11
12 impl BaseGenerator {
13 pub fn reset(&mut self, seed: u32) {
14 self.bit_buffer = 0;
15 self.bit_count = 0;
16 self.seed = seed;
17 }
18 }
19
20 pub struct XorShift128 {
21 x: u64,
22 y: u64,
23 bytes_available: bool,
24 base: BaseGenerator,
25 }
26
27 const SEED_X: u64 = 521288629 << 32;
28 const SEED_Y: u64 = 362436069;
29
30 impl XorShift128 {
31 pub fn new(seed: u32) -> XorShift128 {
32 let mut gen = XorShift128 {
33 base: BaseGenerator {
34 bit_buffer: 0,
35 bit_count: 0,
36 seed: seed,
37 },
38 x: 0,
39 y: 0,
40 bytes_available: false,
41 };
42
43 gen.reset(seed);
45
46 gen
48 }
49
50 pub fn next_f64(&mut self) -> f64 {
51 let mut tx = self.x;
52 let ty = self.y;
53 self.x = ty;
54 tx ^= tx << 23;
55 tx ^= tx >> 17;
56 tx ^= ty ^ (ty >> 26);
57 self.y = tx;
58 self.bytes_available = false;
59
60 let result = to_f64(tx.overflowing_add(ty).0);
61 assert!(result >= 0.0 && result <= 1.0);
62 result
63 }
64
65 pub fn next_u64(&mut self) -> u64 {
66 let mut tx = self.x;
67 let ty = self.y;
68 self.x = ty;
69 tx ^= tx << 23;
70 tx ^= tx >> 17;
71 tx ^= ty ^ (ty >> 26);
72 self.y = tx;
73 self.bytes_available = false;
74 tx.overflowing_add(ty).0
75 }
76
77 pub fn reset(&mut self, seed: u32) {
78 self.base.reset(seed);
80
81 self.x = SEED_X + seed as u64;
83 self.y = SEED_Y.overflowing_mul((seed as u64) << 32).0;
84 self.bytes_available = false;
85
86 self.next_u64();
87 }
88 }
89
90 impl NoiseSource<f64> for XorShift128 {
91 fn noise(&mut self) -> f64 {
92 self.next_f64()
93 }
94 }
95
96 fn to_f64(mut value: u64) -> f64 {
97 value = (value >> 12) | 0x3FF0000000000000;
98 let res = unsafe { std::mem::transmute::<u64, f64>(value) };
99 res - 1.0
100 }
101
102 mod tests {
103 use super::*;
105
106 #[test]
107 fn reproducible() {
108 let mut generator = XorShift128::new(9452);
109 let vals: Vec<f64> = (0..461456).map(|_| generator.next_f64()).collect();
110 assert_eq!(format!("{:.10}", vals.last().unwrap()), "0.5612585810");
111 }
112 }
113}