1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#![feature(test)]
extern crate test;
extern crate rand;
extern crate rand_core;
use rand::SeedableRng;
use rand_core::{impls, Error, RngCore};
pub struct RomuPrng {
xstate: u64,
ystate: u64,
}
impl RomuPrng {
pub fn new(xstate: u64, ystate: u64) -> Self {
return Self { xstate, ystate };
}
}
impl SeedableRng for RomuPrng {
type Seed = [u8; 16];
fn from_seed(seed: [u8; 16]) -> RomuPrng {
if seed == [0; 16] {
return RomuPrng::new(0x0DDB1A5E5BAD5EEDu64, 0x519fb20ce6a199bbu64);
}
let x = u64::from_le_bytes([
seed[0], seed[1], seed[2], seed[3], seed[4], seed[5], seed[6], seed[7],
]);
let y = u64::from_le_bytes([
seed[8], seed[9], seed[10], seed[11], seed[12], seed[13], seed[14], seed[15],
]);
return RomuPrng::new(x, y);
}
}
impl RngCore for RomuPrng {
fn next_u32(&mut self) -> u32 {
self.next_u64() as u32
}
fn next_u64(&mut self) -> u64 {
let xp = self.xstate;
self.xstate = 15241094284759029579u64.wrapping_mul(self.ystate);
self.ystate = self.ystate.wrapping_sub(xp);
self.ystate = self.ystate.rotate_left(27);
return xp;
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
impls::fill_bytes_via_next(self, dest)
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Ok(self.fill_bytes(dest))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vector() {
let x = 0x3c91b13ee3913664u64;
let y = 0x863f0e37c2637d1fu64;
let mut prng = RomuPrng::new(x, y);
assert_eq!(0x3c91b13ee3913664, prng.next_u64());
assert_eq!(0xdc1980b78df3115, prng.next_u64());
assert_eq!(0x1c163b704996d2ad, prng.next_u64());
assert_eq!(0xa000c594bb28313b, prng.next_u64());
assert_eq!(0xfb6c42e69a523526, prng.next_u64());
assert_eq!(0x1fcebd6988ab21d8, prng.next_u64());
assert_eq!(0x5e0a8abf025f8f02, prng.next_u64());
assert_eq!(0x29554b00ffab0263, prng.next_u64());
assert_eq!(0xff5b6bb1551cf66, prng.next_u64());
}
use super::RomuPrng;
use crate::rand::rngs::StdRng;
use crate::rand::RngCore;
use rand_pcg::Pcg64Mcg;
use test::Bencher;
#[bench]
fn bench_romu(b: &mut Bencher) {
b.iter(|| {
let mut prng = RomuPrng::seed_from_u64(12345);
let n = test::black_box(10_000);
test::black_box((0..n).fold(0, |old, _i| old ^ prng.next_u64()));
});
}
#[bench]
fn bench_std(b: &mut Bencher) {
b.iter(|| {
let mut prng = StdRng::seed_from_u64(12345);
let n = test::black_box(10_000);
test::black_box((0..n).fold(0, |old, _i| old ^ prng.next_u64()));
});
}
#[bench]
fn bench_pcg(b: &mut Bencher) {
b.iter(|| {
let mut prng = Pcg64Mcg::seed_from_u64(12345);
let n = test::black_box(10_000);
test::black_box((0..n).fold(0, |old, _i| old ^ prng.next_u64()));
});
}
}