pcg_random/
output.rs

1pub trait Output<S, O> {
2	fn output(s: S) -> O;
3}
4
5/// high xorshift, followed by a random shift
6#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
7pub struct XshRs;
8
9impl Output<u16, u8> for XshRs {
10	#[inline]
11	fn output(s: u16) -> u8 {
12		let xsh = s ^ (s >> 7);
13		(xsh >> (3 + (s >> 14))) as u8
14	}
15}
16
17impl Output<u32, u16> for XshRs {
18	#[inline]
19	fn output(s: u32) -> u16 {
20		let xsh = s ^ (s >> 11);
21		(xsh >> (11 + (s >> 30))) as u16
22	}
23}
24
25impl Output<u64, u32> for XshRs {
26	#[inline]
27	fn output(s: u64) -> u32 {
28		let xsh = s ^ (s >> 22);
29		(xsh >> (22 + (s >> 61))) as u32
30	}
31}
32
33impl Output<u128, u64> for XshRs {
34	#[inline]
35	fn output(s: u128) -> u64 {
36		let xsh = s ^ (s >> 43);
37		(xsh >> (45 + (s >> 124))) as u64
38	}
39}
40
41/// high xorshift, followed by a random rotate
42#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
43pub struct XshRr;
44
45impl Output<u16, u8> for XshRr {
46	#[inline]
47	fn output(s: u16) -> u8 {
48		let xsh = ((s ^ (s >> 5)) >> 5) as u8;
49		xsh.rotate_right((s >> 13).into())
50	}
51}
52
53impl Output<u32, u16> for XshRr {
54	#[inline]
55	fn output(s: u32) -> u16 {
56		let xsh = ((s ^ (s >> 10)) >> 12) as u16;
57		xsh.rotate_right(s >> 28)
58	}
59}
60
61impl Output<u64, u32> for XshRr {
62	#[inline]
63	fn output(s: u64) -> u32 {
64		let xsh = ((s ^ (s >> 18)) >> 27) as u32;
65		xsh.rotate_right((s >> 59) as u32)
66	}
67}
68
69impl Output<u128, u64> for XshRr {
70	#[inline]
71	fn output(s: u128) -> u64 {
72		let xsh = ((s ^ (s >> 35)) >> 58) as u64;
73		xsh.rotate_right((s >> 122) as u32)
74	}
75}
76
77/// random xorshift, mcg multiply, fixed xorshift
78#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
79pub struct RxsMXs;
80
81impl Output<u8, u8> for RxsMXs {
82	#[inline]
83	fn output(s: u8) -> u8 {
84		let shift = 2 + (s >> 6);
85		let rxs = s ^ (s >> shift);
86		let m = rxs.wrapping_mul(0xd9);
87		m ^ (m >> 6)
88	}
89}
90
91impl Output<u16, u16> for RxsMXs {
92	#[inline]
93	fn output(s: u16) -> u16 {
94		let shift = 3 + (s >> 13);
95		let rxs = s ^ (s >> shift);
96		let m = rxs.wrapping_mul(0xf2d9);
97		m ^ (m >> 11)
98	}
99}
100
101impl Output<u32, u32> for RxsMXs {
102	#[inline]
103	fn output(s: u32) -> u32 {
104		let shift = 4 + (s >> 28);
105		let rxs = s ^ (s >> shift);
106		let m = rxs.wrapping_mul(0x108ef2d9);
107		m ^ (m >> 22)
108	}
109}
110
111impl Output<u64, u64> for RxsMXs {
112	#[inline]
113	fn output(s: u64) -> u64 {
114		let shift = 5 + (s >> 59);
115		let rxs = s ^ (s >> shift);
116		let m = rxs.wrapping_mul(0xaef17502108ef2d9);
117		m ^ (m >> 43)
118	}
119}
120
121impl Output<u128, u128> for RxsMXs {
122	#[inline]
123	fn output(s: u128) -> u128 {
124		let shift = 6 + (s >> 122);
125		let rxs = s ^ (s >> shift);
126		let m = rxs.wrapping_mul(0xf69019274d7f699caef17502108ef2d9);
127		m ^ (m >> 86)
128	}
129}
130
131/// double xorshift multiply
132#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
133pub struct Dxsm;
134
135impl Output<u16, u8> for Dxsm {
136	#[inline]
137	fn output(s: u16) -> u8 {
138		let mut h = (s >> 8) as u8;
139		h ^= h >> 4;
140		h = h.wrapping_mul(0x1d);
141		h ^= h >> 6;
142		h.wrapping_mul(s as u8 | 1)
143	}
144}
145
146impl Output<u32, u16> for Dxsm {
147	#[inline]
148	fn output(s: u32) -> u16 {
149		let mut h = (s >> 16) as u16;
150		h ^= h >> 8;
151		h = h.wrapping_mul(0x77b5);
152		h ^= h >> 12;
153		h.wrapping_mul(s as u16 | 1)
154	}
155}
156
157impl Output<u64, u32> for Dxsm {
158	#[inline]
159	fn output(s: u64) -> u32 {
160		let mut h = (s >> 32) as u32;
161		h ^= h >> 16;
162		h = h.wrapping_mul(0x4c957f2d);
163		h ^= h >> 24;
164		h.wrapping_mul(s as u32 | 1)
165	}
166}
167
168impl Output<u128, u64> for Dxsm {
169	#[inline]
170	fn output(s: u128) -> u64 {
171		let mut h = (s >> 64) as u64;
172		h ^= h >> 32;
173		h = h.wrapping_mul(0xda942042e4dd58b5);
174		h ^= h >> 48;
175		h.wrapping_mul(s as u64 | 1)
176	}
177}
178
179/// fixed xorshift (to low bits), random rotate
180#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
181pub struct XslRr;
182
183impl Output<u64, u32> for XslRr {
184	#[inline]
185	fn output(s: u64) -> u32 {
186		let xsl = s ^ (s >> 32);
187		(xsl as u32).rotate_right((s >> 59) as u32)
188	}
189}
190
191impl Output<u128, u64> for XslRr {
192	#[inline]
193	fn output(s: u128) -> u64 {
194		let xsl = s ^ (s >> 64);
195		(xsl as u64).rotate_right((s >> 122) as u32)
196	}
197}
198
199/// fixed xorshift (to low bits), random rotate (both parts)
200#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
201pub struct XslRrRr;
202
203impl Output<u64, u64> for XslRrRr {
204	#[inline]
205	fn output(s: u64) -> u64 {
206		let xsl = s ^ (s >> 32);
207		let l = (xsl as u32).rotate_right((s >> 59) as u32);
208		let h = ((xsl >> 32) as u32).rotate_right(l & 0b11111);
209		u64::from(l) | (u64::from(h) << 32)
210	}
211}
212
213impl Output<u128, u128> for XslRrRr {
214	#[inline]
215	fn output(s: u128) -> u128 {
216		let xsl = s ^ (s >> 64);
217		let l = (xsl as u64).rotate_right((s >> 122) as u32);
218		let h = ((xsl >> 64) as u64).rotate_right((l & 0b111111) as u32);
219		u128::from(l) | (u128::from(h) << 64)
220	}
221}
222
223#[cfg(test)]
224mod tests {
225	use crate::DefaultCheapLcgParameters;
226
227	#[test]
228	#[ignore]
229	fn xsh_rs() {
230		const NAME: &str = "XshRs";
231
232		#[allow(clippy::cast_possible_wrap, clippy::int_plus_one)]
233		fn print(bits: u32, x_bits: u32) {
234			let spare = bits - x_bits;
235
236			let op = if spare as i32 - 5 >= 64 {
237				5
238			} else if spare as i32 - 4 >= 32 {
239				4
240			} else if spare as i32 - 3 >= 16 {
241				3
242			} else if spare as i32 - 2 >= 4 {
243				2
244			} else if spare as i32 - 1 >= 1 {
245				1
246			} else {
247				0
248			};
249
250			let mask = (1 << op) - 1;
251			let max_rand_shift = mask;
252			let top_spare = op;
253			let bottom_spare = spare - top_spare;
254			let x_shift = top_spare + (x_bits + max_rand_shift) / 2;
255
256			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
257			println!("	#[inline]");
258			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
259			println!("		let xsh = s ^ (s >> {x_shift});");
260			println!(
261				"		(xsh >> ({} + (s >> {}))) as u{x_bits}",
262				bottom_spare - max_rand_shift,
263				bits - op
264			);
265			println!("	}}");
266			println!("}}");
267			println!();
268		}
269
270		println!("/// high xorshift, followed by a random shift");
271		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
272		println!("pub struct {NAME};");
273		println!();
274
275		print(16, 8);
276		print(32, 16);
277		print(64, 32);
278		print(128, 64);
279	}
280
281	#[test]
282	#[ignore]
283	fn xsh_rr() {
284		const NAME: &str = "XshRr";
285
286		fn print(bits: u32, x_bits: u32) {
287			let spare = bits - x_bits;
288
289			let wanted_op = if x_bits >= 128 {
290				7
291			} else if x_bits >= 64 {
292				6
293			} else if x_bits >= 32 {
294				5
295			} else if x_bits >= 16 {
296				4
297			} else {
298				3
299			};
300
301			let op = if spare >= wanted_op { wanted_op } else { spare };
302			let amplifier = wanted_op - op;
303			assert!(amplifier == 0);
304			let top_spare = op;
305			let bottom_spare = spare - top_spare;
306			let x_shift = (top_spare + x_bits) / 2;
307
308			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
309			println!("	#[inline]");
310			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
311			println!("		let xsh = ((s ^ (s >> {x_shift})) >> {bottom_spare}) as u{x_bits};");
312			println!("		xsh.rotate_right((s >> {}) as u32)", bits - op);
313			println!("	}}");
314			println!("}}");
315			println!();
316		}
317
318		println!("/// high xorshift, followed by a random shift");
319		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
320		println!("pub struct {NAME};");
321		println!();
322
323		print(16, 8);
324		print(32, 16);
325		print(64, 32);
326		print(128, 64);
327	}
328
329	fn multiplier(bits: u32) -> String {
330		const M: u128 = 0xf69019274d7f699caef17502108ef2d9;
331
332		match bits {
333			8 => format!("0x{:02x}", M as u8),
334			16 => format!("0x{:04x}", M as u16),
335			32 => format!("0x{:08x}", M as u32),
336			64 => format!("0x{:016x}", M as u64),
337			128 => format!("0x{M:032x}"),
338			_ => panic!()
339		}
340	}
341
342	#[test]
343	#[ignore]
344	fn rxs_m_xs() {
345		const NAME: &str = "RxsMXs";
346
347		fn print(bits: u32, x_bits: u32) {
348			let op = if x_bits >= 128 {
349				6
350			} else if x_bits >= 64 {
351				5
352			} else if x_bits >= 32 {
353				4
354			} else if x_bits >= 16 {
355				3
356			} else {
357				2
358			};
359
360			let shift = bits - x_bits;
361			assert!(shift == 0);
362
363			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
364			println!("	#[inline]");
365			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
366			println!("		let shift = {} + (s >> {});", op, bits - op);
367			println!("		let rxs = s ^ (s >> shift);");
368			println!("		let m = rxs.wrapping_mul({});", multiplier(bits));
369			println!("		m ^ (m >> {})", (x_bits * 2).div_ceil(3));
370			println!("	}}");
371			println!("}}");
372			println!();
373		}
374
375		println!("/// random xorshift, mcg multiply, fixed xorshift");
376		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
377		println!("pub struct {NAME};");
378		println!();
379
380		print(8, 8);
381		print(16, 16);
382		print(32, 32);
383		print(64, 64);
384		print(128, 128);
385	}
386
387	#[test]
388	#[ignore]
389	fn dxsm() {
390		const NAME: &str = "Dxsm";
391
392		fn print(bits: u32, x_bits: u32) {
393			assert!(x_bits == bits / 2);
394
395			let multiplier = match bits {
396				16 => format!("0x{:02x}", DefaultCheapLcgParameters::<u16>::multiplier() as u8),
397				32 => format!("0x{:04x}", DefaultCheapLcgParameters::<u32>::multiplier() as u16),
398				64 => {
399					format!("0x{:08x}", DefaultCheapLcgParameters::<u64>::multiplier() as u32)
400				}
401				128 => {
402					format!("0x{:016x}", DefaultCheapLcgParameters::<u128>::multiplier() as u64)
403				}
404				_ => panic!()
405			};
406
407			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
408			println!("	#[inline]");
409			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
410			println!("		let mut h = (s >> {}) as u{x_bits};", x_bits);
411			println!("		h ^= h >> {};", x_bits / 2);
412			println!("		h = h.wrapping_mul({multiplier});");
413			println!("		h ^= h >> {};", (x_bits / 4) * 3);
414			println!("		h.wrapping_mul(s as u{x_bits} | 1)");
415			println!("	}}");
416			println!("}}");
417			println!();
418		}
419
420		println!("/// double xorshift multiply");
421		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
422		println!("pub struct {NAME};");
423		println!();
424
425		print(16, 8);
426		print(32, 16);
427		print(64, 32);
428		print(128, 64);
429	}
430
431	#[test]
432	#[ignore]
433	fn xsl_rr() {
434		const NAME: &str = "XslRr";
435
436		fn print(bits: u32, x_bits: u32) {
437			let spare = bits - x_bits;
438
439			let wanted_op = if x_bits >= 128 {
440				7
441			} else if x_bits >= 64 {
442				6
443			} else if x_bits >= 32 {
444				5
445			} else if x_bits >= 16 {
446				4
447			} else {
448				3
449			};
450
451			let op = if spare >= wanted_op { wanted_op } else { spare };
452			let amplifier = wanted_op - op;
453			assert!(amplifier == 0);
454			let top_spare = spare;
455			let bottom_spare = spare - top_spare;
456			assert!(bottom_spare == 0);
457			let x_shift = (top_spare + x_bits) / 2;
458
459			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
460			println!("	#[inline]");
461			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
462			println!("		let xsl = s ^ (s >> {x_shift});");
463			println!("		(xsl as u{x_bits}).rotate_right((s >> {}) as u32)", bits - op);
464			println!("	}}");
465			println!("}}");
466			println!();
467		}
468
469		println!("/// fixed xorshift (to low bits), random rotate");
470		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
471		println!("pub struct {NAME};");
472		println!();
473
474		print(64, 32);
475		print(128, 64);
476	}
477
478	#[test]
479	#[ignore]
480	fn xsl_rr_rr() {
481		const NAME: &str = "XslRrRr";
482
483		fn print(bits: u32, x_bits: u32) {
484			assert!(bits == x_bits);
485			let spare = bits - bits / 2;
486
487			let wanted_op = if bits / 2 >= 128 {
488				7
489			} else if bits / 2 >= 64 {
490				6
491			} else if bits / 2 >= 32 {
492				5
493			} else if bits / 2 >= 16 {
494				4
495			} else {
496				3
497			};
498
499			let op = if spare >= wanted_op { wanted_op } else { spare };
500			let amplifier = wanted_op - op;
501			assert!(amplifier == 0);
502			let top_spare = spare;
503			let x_shift = (top_spare + bits / 2) / 2;
504
505			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
506			println!("	#[inline]");
507			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
508			println!("		let xsl = s ^ (s >> {x_shift});");
509			println!("		let l = (xsl as u{}).rotate_right((s >> {}) as u32);", bits / 2, bits - op);
510			println!(
511				"		let h = ((xsl >> {top_spare}) as u{}).rotate_right((l & 0b{:b}) as u32);",
512				bits / 2,
513				(1 << op) - 1
514			);
515			println!("		u{x_bits}::from(l) | (u{x_bits}::from(h) << {top_spare})");
516			println!("	}}");
517			println!("}}");
518			println!();
519		}
520
521		println!("/// fixed xorshift (to low bits), random rotate (both parts)");
522		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
523		println!("pub struct {NAME};");
524		println!();
525
526		print(64, 64);
527		print(128, 128);
528	}
529}