Last active
July 8, 2025 17:20
-
-
Save ttappr/4dbeb28b3499954cb96989c9654f89c6 to your computer and use it in GitHub Desktop.
Linear congruential pseudorandom number generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::time::{SystemTime, UNIX_EPOCH}; | |
/// Multiplier used by the `SimpleRng` random number generator. | |
const RAND_MULTIPLIER: u128 = 6364136223846793005; | |
/// A simple variant of a random number generator. | |
/// | |
pub struct SimpleRng(u128); | |
impl SimpleRng { | |
/// Creates a new RNG. If no seed value is provided, the RNG will be seeded | |
/// from the system clock with milliseconds since Unix epoch. | |
/// | |
pub fn new(seed: Option<u64>) -> Self { | |
let seed = seed.unwrap_or_else(|| { | |
SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() | |
as u64 | |
}); | |
Self(((seed as u128) << 64).wrapping_mul(RAND_MULTIPLIER) | |
.wrapping_add(1)) | |
} | |
/// Produce a pseudorandom integer in the range [lo, hi). | |
/// | |
pub fn randint(&mut self, lo: u64, hi: u64) -> u64 { | |
self.0 = self.0.wrapping_mul(RAND_MULTIPLIER).wrapping_add(1); | |
let range = (hi - lo) as u128; | |
let rand = self.0 >> 64; | |
(rand.wrapping_mul(range) >> 64) as u64 + lo | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Using the upper 64 bits of the seed seems to result in RNG cycles with significantly larger periods. Formal tests using cycle detection should be run to confirm this. But from observations of this being used in simple applications, it appears to be a good approach. The source of the multiplier is this article.