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/// random xorshift, mcg multiply
132#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
133pub struct RxsM;
134
135impl Output<u16, u8> for RxsM {
136	#[inline]
137	fn output(s: u16) -> u8 {
138		let shift = 2 + (s >> 14);
139		let rxs = s ^ (s >> shift);
140		(rxs.wrapping_mul(0xf2d9) >> 8) as u8
141	}
142}
143
144impl Output<u32, u16> for RxsM {
145	#[inline]
146	fn output(s: u32) -> u16 {
147		let shift = 3 + (s >> 29);
148		let rxs = s ^ (s >> shift);
149		(rxs.wrapping_mul(0x108ef2d9) >> 16) as u16
150	}
151}
152
153impl Output<u64, u32> for RxsM {
154	#[inline]
155	fn output(s: u64) -> u32 {
156		let shift = 4 + (s >> 60);
157		let rxs = s ^ (s >> shift);
158		(rxs.wrapping_mul(0xaef17502108ef2d9) >> 32) as u32
159	}
160}
161
162impl Output<u128, u64> for RxsM {
163	#[inline]
164	fn output(s: u128) -> u64 {
165		let shift = 5 + (s >> 123);
166		let rxs = s ^ (s >> shift);
167		(rxs.wrapping_mul(0xf69019274d7f699caef17502108ef2d9) >> 64) as u64
168	}
169}
170
171/// double xorshift multiply
172#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
173pub struct Dxsm;
174
175impl Output<u16, u8> for Dxsm {
176	#[inline]
177	fn output(s: u16) -> u8 {
178		let mut h = (s >> 8) as u8;
179		h ^= h >> 4;
180		h = h.wrapping_mul(0x1d);
181		h ^= h >> 6;
182		h.wrapping_mul(s as u8 | 1)
183	}
184}
185
186impl Output<u32, u16> for Dxsm {
187	#[inline]
188	fn output(s: u32) -> u16 {
189		let mut h = (s >> 16) as u16;
190		h ^= h >> 8;
191		h = h.wrapping_mul(0x77b5);
192		h ^= h >> 12;
193		h.wrapping_mul(s as u16 | 1)
194	}
195}
196
197impl Output<u64, u32> for Dxsm {
198	#[inline]
199	fn output(s: u64) -> u32 {
200		let mut h = (s >> 32) as u32;
201		h ^= h >> 16;
202		h = h.wrapping_mul(0x4c957f2d);
203		h ^= h >> 24;
204		h.wrapping_mul(s as u32 | 1)
205	}
206}
207
208impl Output<u128, u64> for Dxsm {
209	#[inline]
210	fn output(s: u128) -> u64 {
211		let mut h = (s >> 64) as u64;
212		h ^= h >> 32;
213		h = h.wrapping_mul(0xda942042e4dd58b5);
214		h ^= h >> 48;
215		h.wrapping_mul(s as u64 | 1)
216	}
217}
218
219/// fixed xorshift (to low bits), random rotate
220#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
221pub struct XslRr;
222
223impl Output<u64, u32> for XslRr {
224	#[inline]
225	fn output(s: u64) -> u32 {
226		let xsl = s ^ (s >> 32);
227		(xsl as u32).rotate_right((s >> 59) as u32)
228	}
229}
230
231impl Output<u128, u64> for XslRr {
232	#[inline]
233	fn output(s: u128) -> u64 {
234		let xsl = s ^ (s >> 64);
235		(xsl as u64).rotate_right((s >> 122) as u32)
236	}
237}
238
239/// fixed xorshift (to low bits), random rotate (both parts)
240#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
241pub struct XslRrRr;
242
243impl Output<u64, u64> for XslRrRr {
244	#[inline]
245	fn output(s: u64) -> u64 {
246		let xsl = s ^ (s >> 32);
247		let l = (xsl as u32).rotate_right((s >> 59) as u32);
248		let h = ((xsl >> 32) as u32).rotate_right(l & 0b11111);
249		u64::from(l) | (u64::from(h) << 32)
250	}
251}
252
253impl Output<u128, u128> for XslRrRr {
254	#[inline]
255	fn output(s: u128) -> u128 {
256		let xsl = s ^ (s >> 64);
257		let l = (xsl as u64).rotate_right((s >> 122) as u32);
258		let h = ((xsl >> 64) as u64).rotate_right((l & 0b111111) as u32);
259		u128::from(l) | (u128::from(h) << 64)
260	}
261}
262
263#[cfg(test)]
264mod tests {
265	use crate::DefaultCheapLcgParameters;
266
267	#[test]
268	#[ignore]
269	fn xsh_rs() {
270		const NAME: &str = "XshRs";
271
272		#[allow(clippy::cast_possible_wrap, clippy::int_plus_one)]
273		fn print(bits: u32, x_bits: u32) {
274			let spare = bits - x_bits;
275
276			let op = if spare as i32 - 5 >= 64 {
277				5
278			} else if spare as i32 - 4 >= 32 {
279				4
280			} else if spare as i32 - 3 >= 16 {
281				3
282			} else if spare as i32 - 2 >= 4 {
283				2
284			} else if spare as i32 - 1 >= 1 {
285				1
286			} else {
287				0
288			};
289
290			let mask = (1 << op) - 1;
291			let max_rand_shift = mask;
292			let top_spare = op;
293			let bottom_spare = spare - top_spare;
294			let x_shift = top_spare + (x_bits + max_rand_shift) / 2;
295
296			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
297			println!("	#[inline]");
298			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
299			println!("		let xsh = s ^ (s >> {x_shift});");
300			println!(
301				"		(xsh >> ({} + (s >> {}))) as u{x_bits}",
302				bottom_spare - max_rand_shift,
303				bits - op
304			);
305			println!("	}}");
306			println!("}}");
307			println!();
308		}
309
310		println!("/// high xorshift, followed by a random shift");
311		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
312		println!("pub struct {NAME};");
313		println!();
314
315		print(16, 8);
316		print(32, 16);
317		print(64, 32);
318		print(128, 64);
319	}
320
321	#[test]
322	#[ignore]
323	fn xsh_rr() {
324		const NAME: &str = "XshRr";
325
326		fn print(bits: u32, x_bits: u32) {
327			let spare = bits - x_bits;
328
329			let wanted_op = if x_bits >= 128 {
330				7
331			} else if x_bits >= 64 {
332				6
333			} else if x_bits >= 32 {
334				5
335			} else if x_bits >= 16 {
336				4
337			} else {
338				3
339			};
340
341			let op = if spare >= wanted_op { wanted_op } else { spare };
342			let amplifier = wanted_op - op;
343			assert!(amplifier == 0);
344			let top_spare = op;
345			let bottom_spare = spare - top_spare;
346			let x_shift = (top_spare + x_bits) / 2;
347
348			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
349			println!("	#[inline]");
350			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
351			println!("		let xsh = ((s ^ (s >> {x_shift})) >> {bottom_spare}) as u{x_bits};");
352			println!("		xsh.rotate_right((s >> {}) as u32)", bits - op);
353			println!("	}}");
354			println!("}}");
355			println!();
356		}
357
358		println!("/// high xorshift, followed by a random shift");
359		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
360		println!("pub struct {NAME};");
361		println!();
362
363		print(16, 8);
364		print(32, 16);
365		print(64, 32);
366		print(128, 64);
367	}
368
369	fn multiplier(bits: u32) -> String {
370		const M: u128 = 0xf69019274d7f699caef17502108ef2d9;
371
372		match bits {
373			8 => format!("0x{:02x}", M as u8),
374			16 => format!("0x{:04x}", M as u16),
375			32 => format!("0x{:08x}", M as u32),
376			64 => format!("0x{:016x}", M as u64),
377			128 => format!("0x{M:032x}"),
378			_ => panic!()
379		}
380	}
381
382	#[test]
383	#[ignore]
384	fn rxs_m_xs() {
385		const NAME: &str = "RxsMXs";
386
387		fn print(bits: u32, x_bits: u32) {
388			let op = if x_bits >= 128 {
389				6
390			} else if x_bits >= 64 {
391				5
392			} else if x_bits >= 32 {
393				4
394			} else if x_bits >= 16 {
395				3
396			} else {
397				2
398			};
399
400			let shift = bits - x_bits;
401			assert!(shift == 0);
402
403			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
404			println!("	#[inline]");
405			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
406			println!("		let shift = {} + (s >> {});", op, bits - op);
407			println!("		let rxs = s ^ (s >> shift);");
408			println!("		let m = rxs.wrapping_mul({});", multiplier(bits));
409			println!("		m ^ (m >> {})", (x_bits * 2).div_ceil(3));
410			println!("	}}");
411			println!("}}");
412			println!();
413		}
414
415		println!("/// random xorshift, mcg multiply, fixed xorshift");
416		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
417		println!("pub struct {NAME};");
418		println!();
419
420		print(8, 8);
421		print(16, 16);
422		print(32, 32);
423		print(64, 64);
424		print(128, 128);
425	}
426
427	#[test]
428	#[ignore]
429	fn rxs_m() {
430		const NAME: &str = "RxsM";
431
432		fn print(bits: u32, x_bits: u32) {
433			let op = if x_bits >= 128 {
434				6
435			} else if x_bits >= 64 {
436				5
437			} else if x_bits >= 32 {
438				4
439			} else if x_bits >= 16 {
440				3
441			} else {
442				2
443			};
444
445			let shift = bits - x_bits;
446
447			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
448			println!("	#[inline]");
449			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
450			println!("		let shift = {} + (s >> {});", op, bits - op);
451			println!("		let rxs = s ^ (s >> shift);");
452			println!("		(rxs.wrapping_mul({}) >> {shift}) as u{x_bits}", multiplier(bits));
453			println!("	}}");
454			println!("}}");
455			println!();
456		}
457
458		println!("/// random xorshift, mcg multiply");
459		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
460		println!("pub struct {NAME};");
461		println!();
462
463		print(16, 8);
464		print(32, 16);
465		print(64, 32);
466		print(128, 64);
467	}
468
469	#[test]
470	#[ignore]
471	fn dxsm() {
472		const NAME: &str = "Dxsm";
473
474		fn print(bits: u32, x_bits: u32) {
475			assert!(x_bits == bits / 2);
476
477			let multiplier = match bits {
478				16 => format!("0x{:02x}", DefaultCheapLcgParameters::<u16>::multiplier() as u8),
479				32 => format!("0x{:04x}", DefaultCheapLcgParameters::<u32>::multiplier() as u16),
480				64 => {
481					format!("0x{:08x}", DefaultCheapLcgParameters::<u64>::multiplier() as u32)
482				}
483				128 => {
484					format!("0x{:016x}", DefaultCheapLcgParameters::<u128>::multiplier() as u64)
485				}
486				_ => panic!()
487			};
488
489			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
490			println!("	#[inline]");
491			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
492			println!("		let mut h = (s >> {}) as u{x_bits};", x_bits);
493			println!("		h ^= h >> {};", x_bits / 2);
494			println!("		h = h.wrapping_mul({multiplier});");
495			println!("		h ^= h >> {};", (x_bits / 4) * 3);
496			println!("		h.wrapping_mul(s as u{x_bits} | 1)");
497			println!("	}}");
498			println!("}}");
499			println!();
500		}
501
502		println!("/// double xorshift multiply");
503		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
504		println!("pub struct {NAME};");
505		println!();
506
507		print(16, 8);
508		print(32, 16);
509		print(64, 32);
510		print(128, 64);
511	}
512
513	#[test]
514	#[ignore]
515	fn xsl_rr() {
516		const NAME: &str = "XslRr";
517
518		fn print(bits: u32, x_bits: u32) {
519			let spare = bits - x_bits;
520
521			let wanted_op = if x_bits >= 128 {
522				7
523			} else if x_bits >= 64 {
524				6
525			} else if x_bits >= 32 {
526				5
527			} else if x_bits >= 16 {
528				4
529			} else {
530				3
531			};
532
533			let op = if spare >= wanted_op { wanted_op } else { spare };
534			let amplifier = wanted_op - op;
535			assert!(amplifier == 0);
536			let top_spare = spare;
537			let bottom_spare = spare - top_spare;
538			assert!(bottom_spare == 0);
539			let x_shift = (top_spare + x_bits) / 2;
540
541			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
542			println!("	#[inline]");
543			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
544			println!("		let xsl = s ^ (s >> {x_shift});");
545			println!("		(xsl as u{x_bits}).rotate_right((s >> {}) as u32)", bits - op);
546			println!("	}}");
547			println!("}}");
548			println!();
549		}
550
551		println!("/// fixed xorshift (to low bits), random rotate");
552		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
553		println!("pub struct {NAME};");
554		println!();
555
556		print(64, 32);
557		print(128, 64);
558	}
559
560	#[test]
561	#[ignore]
562	fn xsl_rr_rr() {
563		const NAME: &str = "XslRrRr";
564
565		fn print(bits: u32, x_bits: u32) {
566			assert!(bits == x_bits);
567			let spare = bits - bits / 2;
568
569			let wanted_op = if bits / 2 >= 128 {
570				7
571			} else if bits / 2 >= 64 {
572				6
573			} else if bits / 2 >= 32 {
574				5
575			} else if bits / 2 >= 16 {
576				4
577			} else {
578				3
579			};
580
581			let op = if spare >= wanted_op { wanted_op } else { spare };
582			let amplifier = wanted_op - op;
583			assert!(amplifier == 0);
584			let top_spare = spare;
585			let x_shift = (top_spare + bits / 2) / 2;
586
587			println!("impl Output<u{bits}, u{x_bits}> for {NAME} {{");
588			println!("	#[inline]");
589			println!("	fn output(s: u{bits}) -> u{x_bits} {{");
590			println!("		let xsl = s ^ (s >> {x_shift});");
591			println!("		let l = (xsl as u{}).rotate_right((s >> {}) as u32);", bits / 2, bits - op);
592			println!(
593				"		let h = ((xsl >> {top_spare}) as u{}).rotate_right((l & 0b{:b}) as u32);",
594				bits / 2,
595				(1 << op) - 1
596			);
597			println!("		u{x_bits}::from(l) | (u{x_bits}::from(h) << {top_spare})");
598			println!("	}}");
599			println!("}}");
600			println!();
601		}
602
603		println!("/// fixed xorshift (to low bits), random rotate (both parts)");
604		println!("#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]");
605		println!("pub struct {NAME};");
606		println!();
607
608		print(64, 64);
609		print(128, 128);
610	}
611}