1use std::hash::{Hash, Hasher};
4use std::ops::Range;
5
6use crate::Vector2;
7
8#[derive(Clone, Debug)]
25pub struct Random {
26 state: u64,
27}
28
29impl Random {
30 pub fn from_key(key: impl Hash) -> Self {
32 let mut hasher = KeyHasher(0xcbf29ce484222325);
33 key.hash(&mut hasher);
34 Self {
35 state: hasher.finish(),
36 }
37 }
38
39 pub fn for_particle(seed: u64, index: u64, step: u64) -> Self {
42 fn mix(mut value: u64) -> u64 {
43 value = (value ^ (value >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
44 value = (value ^ (value >> 27)).wrapping_mul(0x94d049bb133111eb);
45 value ^ (value >> 31)
46 }
47 Self {
48 state: mix(seed
49 ^ mix(index.wrapping_add(0x9e3779b97f4a7c15))
50 ^ mix(step.wrapping_add(0xd1b54a32d192ed03))),
51 }
52 }
53
54 fn next_bits(&mut self) -> u64 {
55 self.state = self.state.wrapping_add(0x9e3779b97f4a7c15);
56 let mut value = self.state;
57 value = (value ^ (value >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
58 value = (value ^ (value >> 27)).wrapping_mul(0x94d049bb133111eb);
59 value ^ (value >> 31)
60 }
61
62 pub fn next_float(&mut self) -> f64 {
64 (self.next_bits() >> 11) as f64 / (1_u64 << 53) as f64
65 }
66
67 pub fn range(&mut self, range: Range<f64>) -> f64 {
72 assert!(
73 range.start.is_finite() && range.end.is_finite() && range.start < range.end,
74 "random range must have finite, strictly increasing endpoints"
75 );
76 let progress = self.next_float();
77 let value = range.start * (1.0 - progress) + range.end * progress;
78 value.max(range.start).min(range.end.next_down())
79 }
80
81 pub fn unit_vector(&mut self) -> Vector2 {
83 let angle = self.next_float() * std::f64::consts::TAU;
84 Vector2::new(libm::cos(angle), libm::sin(angle))
85 }
86
87 pub fn choose<'a, Value>(&mut self, values: &'a [Value]) -> Option<&'a Value> {
89 if values.is_empty() {
90 return None;
91 }
92 let count = u64::try_from(values.len()).expect("slice length fits u64");
93 let threshold = count.wrapping_neg() % count;
94 loop {
95 let bits = self.next_bits();
96 if bits >= threshold {
97 return Some(&values[(bits % count) as usize]);
98 }
99 }
100 }
101}
102
103struct KeyHasher(u64);
104
105impl Hasher for KeyHasher {
106 fn finish(&self) -> u64 {
107 self.0
108 }
109
110 fn write(&mut self, bytes: &[u8]) {
111 for byte in bytes {
112 self.0 = (self.0 ^ u64::from(*byte)).wrapping_mul(0x100000001b3);
113 }
114 }
115
116 fn write_u8(&mut self, value: u8) {
117 self.write(&value.to_le_bytes());
118 }
119
120 fn write_u16(&mut self, value: u16) {
121 self.write(&value.to_le_bytes());
122 }
123
124 fn write_u32(&mut self, value: u32) {
125 self.write(&value.to_le_bytes());
126 }
127
128 fn write_u64(&mut self, value: u64) {
129 self.write(&value.to_le_bytes());
130 }
131
132 fn write_u128(&mut self, value: u128) {
133 self.write(&value.to_le_bytes());
134 }
135
136 fn write_usize(&mut self, value: usize) {
137 self.write_u64(value as u64);
138 }
139
140 fn write_i8(&mut self, value: i8) {
141 self.write(&value.to_le_bytes());
142 }
143
144 fn write_i16(&mut self, value: i16) {
145 self.write(&value.to_le_bytes());
146 }
147
148 fn write_i32(&mut self, value: i32) {
149 self.write(&value.to_le_bytes());
150 }
151
152 fn write_i64(&mut self, value: i64) {
153 self.write(&value.to_le_bytes());
154 }
155
156 fn write_i128(&mut self, value: i128) {
157 self.write(&value.to_le_bytes());
158 }
159
160 fn write_isize(&mut self, value: isize) {
161 self.write_i64(value as i64);
162 }
163}
164
165#[cfg(test)]
166mod tests {
167 use super::*;
168
169 #[test]
170 fn fixed_sequence_matches_independent_integer_reference() {
171 let mut random = Random::from_key(42_u64);
172 assert_eq!(random.state, 0xff3add6b3789daef);
173 for expected in [
174 0xa4e6579fd9ba8f6d,
175 0x14e9a1cc21726518,
176 0x29700e43bfeb9b12,
177 0xebc4f50c4cfbc8c4,
178 ] {
179 assert_eq!(random.next_bits(), expected);
180 }
181 let mut random = Random::from_key(42_u64);
182 assert_eq!(random.next_float(), 0.6441397443065658);
183 assert_eq!(
184 Random::from_key(42_usize).state,
185 Random::from_key(42_u64).state
186 );
187 assert_eq!(
188 Random::from_key(-42_isize).state,
189 Random::from_key(-42_i64).state
190 );
191 }
192
193 #[test]
194 fn equal_keys_and_cloned_streams_are_repeatable_without_global_state() {
195 let mut first = Random::from_key(("spark", 27_u32));
196 let mut same = first.clone();
197 let mut different = Random::from_key(("spark", 28_u32));
198 for _ in 0..1024 {
199 let value = first.next_float();
200 assert!((0.0..1.0).contains(&value));
201 assert_eq!(value, same.next_float());
202 }
203 assert_ne!(same.next_float(), different.next_float());
204 let expected = Random::from_key("parallel").next_float();
205 std::thread::scope(|scope| {
206 let handles: Vec<_> = (0..8)
207 .map(|_| scope.spawn(|| Random::from_key("parallel").next_float()))
208 .collect();
209 for handle in handles {
210 assert_eq!(handle.join().unwrap(), expected);
211 }
212 });
213 }
214
215 #[test]
216 fn ranges_vectors_and_choices_obey_their_domains() {
217 let mut random = Random::from_key("domains");
218 let ranges = [
219 -f64::MAX..f64::MAX,
220 f64::MAX.next_down()..f64::MAX,
221 -f64::MAX..(-f64::MAX).next_up(),
222 0.0..f64::from_bits(1),
223 -f64::from_bits(1)..0.0,
224 1.0..1.0_f64.next_up(),
225 -3.0..7.0,
226 ];
227 let choices = [2, 5, 9];
228 let mut seen = [false; 3];
229 for _ in 0..2048 {
230 for range in &ranges {
231 let value = random.range(range.clone());
232 assert!(range.contains(&value), "{range:?}: {value:?}");
233 }
234 let vector = random.unit_vector();
235 assert!((vector.x * vector.x + vector.y * vector.y - 1.0).abs() <= 4.0 * f64::EPSILON);
236 let choice = random.choose(&choices).unwrap();
237 seen[choices.iter().position(|value| value == choice).unwrap()] = true;
238 }
239 assert_eq!(seen, [true; 3]);
240 assert_eq!(random.choose::<u32>(&[]), None);
241 assert_eq!(random.choose(&[7]), Some(&7));
242 }
243
244 #[test]
245 fn invalid_ranges_fail_explicitly() {
246 for range in [
247 0.0..0.0,
248 2.0..1.0,
249 f64::NAN..1.0,
250 0.0..f64::INFINITY,
251 f64::NEG_INFINITY..0.0,
252 ] {
253 assert!(std::panic::catch_unwind(|| Random::from_key(0_u32).range(range)).is_err());
254 }
255 }
256}