author | unC0Rr |
Tue, 28 Jan 2025 10:37:46 +0100 | |
changeset 16072 | a4cbc6926439 |
parent 16057 | 106674bb21b1 |
permissions | -rw-r--r-- |
16072 | 1 |
use rand::{RngCore, SeedableRng}; |
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
2 |
|
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
3 |
pub struct LaggedFibonacciPRNG { |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
4 |
circular_buffer: [u32; 64], |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
5 |
index: usize, |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
6 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
7 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
8 |
impl LaggedFibonacciPRNG { |
14027 | 9 |
pub fn new(init_values: &[u8]) -> Self { |
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
10 |
let mut buf = [0xa98765; 64]; |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
11 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
12 |
for i in 0..std::cmp::min(init_values.len(), 54) { |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
13 |
buf[i] = init_values[i] as u32; |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
14 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
15 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
16 |
let mut prng = Self { |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
17 |
circular_buffer: buf, |
16057
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
18 |
index: 0, |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
19 |
}; |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
20 |
|
15115 | 21 |
prng.discard(2048); |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
22 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
23 |
prng |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
24 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
25 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
26 |
#[inline] |
15115 | 27 |
pub fn discard(&mut self, count: usize) { |
28 |
for _i in 0..count { |
|
29 |
self.get_next(); |
|
30 |
} |
|
31 |
} |
|
32 |
||
33 |
#[inline] |
|
14029 | 34 |
fn get_next(&mut self) -> u32 { |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
35 |
self.index = (self.index + 1) & 0x3f; |
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
36 |
let next_value = self.circular_buffer[(self.index + 40) & 0x3f] |
16057
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
37 |
.wrapping_add(self.circular_buffer[(self.index + 9) & 0x3f]); |
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
38 |
|
16057
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
39 |
self.circular_buffer[self.index] = next_value; |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
40 |
|
16057
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
41 |
next_value |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
42 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
43 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
44 |
#[inline] |
14027 | 45 |
pub fn get_random(&mut self, modulo: u32) -> u32 { |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
46 |
self.get_next(); |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
47 |
self.get_next() % modulo |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
48 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
49 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
50 |
#[inline] |
14027 | 51 |
pub fn add_randomness(&mut self, value: u32) { |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
52 |
self.index = (self.index + 1) & 0x3f; |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
53 |
self.circular_buffer[self.index] ^= value; |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
54 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
55 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
56 |
|
13904 | 57 |
impl Iterator for LaggedFibonacciPRNG { |
58 |
type Item = u32; |
|
59 |
||
13935
75eaf7c71789
Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents:
13904
diff
changeset
|
60 |
fn next(&mut self) -> Option<Self::Item> { |
13904 | 61 |
self.get_next(); |
62 |
Some(self.get_next()) |
|
63 |
} |
|
64 |
} |
|
65 |
||
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
66 |
impl RngCore for LaggedFibonacciPRNG { |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
67 |
fn next_u32(&mut self) -> u32 { |
16072 | 68 |
self.get_next(); |
69 |
self.get_next() |
|
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
70 |
} |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
71 |
|
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
72 |
fn next_u64(&mut self) -> u64 { |
16072 | 73 |
((self.get_next() as u64) << 32) | self.get_next() as u64 |
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
74 |
} |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
75 |
|
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
76 |
fn fill_bytes(&mut self, dest: &mut [u8]) { |
16072 | 77 |
let mut chunks = dest.chunks_exact_mut(4); |
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
78 |
|
16072 | 79 |
for chunk in chunks.by_ref() { |
80 |
let value = self.get_next(); |
|
81 |
let bytes = value.to_le_bytes(); |
|
82 |
chunk.copy_from_slice(&bytes); |
|
83 |
} |
|
84 |
||
85 |
let remainder = chunks.into_remainder(); |
|
86 |
if !remainder.is_empty() { |
|
87 |
let value = self.next_u32(); |
|
88 |
let bytes = value.to_le_bytes(); |
|
89 |
remainder.copy_from_slice(&bytes[..remainder.len()]); |
|
90 |
} |
|
15902
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
91 |
} |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
92 |
} |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
93 |
|
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
94 |
impl SeedableRng for LaggedFibonacciPRNG { |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
95 |
type Seed = [u8; 32]; |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
96 |
|
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
97 |
fn from_seed(seed: Self::Seed) -> Self { |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
98 |
LaggedFibonacciPRNG::new(&seed) |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
99 |
} |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
100 |
} |
9b73594ac986
Update lfprng for better distribution, make it conform 'rand' package traits
unC0Rr
parents:
15115
diff
changeset
|
101 |
|
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
102 |
#[cfg(test)] |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
103 |
#[test] |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
104 |
fn compatibility() { |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
105 |
let mut prng = LaggedFibonacciPRNG::new("{052e2aee-ce41-4720-97bd-559a413bf866}".as_bytes()); |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
106 |
|
16057
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
107 |
assert_eq!(prng.get_random(1000), 145); |
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
108 |
assert_eq!(prng.get_random(1000000), 385411); |
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
109 |
assert_eq!(prng.get_random(0xffffffff), 3099784309); |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
110 |
|
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
111 |
prng.add_randomness(123); |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
112 |
|
16057
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
113 |
for _ in 0..=100000 { |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
114 |
prng.get_random(2); |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
115 |
} |
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
116 |
|
16057
106674bb21b1
Revert the idea of using prime number in hedgewars prng
unC0Rr
parents:
15902
diff
changeset
|
117 |
assert_eq!(prng.get_random(0xffffffff), 633923935); |
13886
b6c35ac1c5ba
Implement lagged Fibonacci PRNG in rust, compatible with hwengine
unc0rr
parents:
diff
changeset
|
118 |
} |