rust/lfprng/src/lib.rs
author unC0Rr
Tue, 28 Jan 2025 10:37:46 +0100
changeset 16072 a4cbc6926439
parent 16057 106674bb21b1
permissions -rw-r--r--
- Adopt newest version of rand crate - Rework fill_bytes() method to use full generated values
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
16072
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
     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
cef0c685fda8 make useful stuff public
alfadur
parents: 13935
diff changeset
     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
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    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
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    27
    pub fn discard(&mut self, count: usize) {
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    28
        for _i in 0..count {
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    29
            self.get_next();
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    30
        }
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    31
    }
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    32
de32299de704 Add 'discard' method for lfprng
unc0rr
parents: 14152
diff changeset
    33
    #[inline]
14029
259175ab7e8c hide get_next back
alfadur
parents: 14027
diff changeset
    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
cef0c685fda8 make useful stuff public
alfadur
parents: 13935
diff changeset
    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
cef0c685fda8 make useful stuff public
alfadur
parents: 13935
diff changeset
    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
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    57
impl Iterator for LaggedFibonacciPRNG {
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    58
    type Item = u32;
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    59
13935
75eaf7c71789 Introduce integral-geometry crate, implement LinePoints iterator
unc0rr
parents: 13904
diff changeset
    60
    fn next(&mut self) -> Option<Self::Item> {
13904
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    61
        self.get_next();
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    62
        Some(self.get_next())
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    63
    }
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    64
}
3f0576157749 Implement Iterator trait for LaggedFibonacciPRNG
unc0rr
parents: 13886
diff changeset
    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
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    68
        self.get_next();
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    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
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    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
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    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
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    79
        for chunk in chunks.by_ref() {
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    80
            let value = self.get_next();
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    81
            let bytes = value.to_le_bytes();
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    82
            chunk.copy_from_slice(&bytes);
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    83
        }
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    84
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    85
        let remainder = chunks.into_remainder();
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    86
        if !remainder.is_empty() {
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    87
            let value = self.next_u32();
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    88
            let bytes = value.to_le_bytes();
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    89
            remainder.copy_from_slice(&bytes[..remainder.len()]);
a4cbc6926439 - Adopt newest version of rand crate
unC0Rr
parents: 16057
diff changeset
    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
}