Skip to content

Instantly share code, notes, and snippets.

@RandyMcMillan
Forked from rust-play/Playground.toml
Last active August 1, 2026 01:53
Show Gist options
  • Select an option

  • Save RandyMcMillan/827a2e6a8863a09512d5b1416dbacbd0 to your computer and use it in GitHub Desktop.

Select an option

Save RandyMcMillan/827a2e6a8863a09512d5b1416dbacbd0 to your computer and use it in GitHub Desktop.
Xoroshiro128PlusPlus.rs
#![no_std]
// Conditionally link `std` when compiling an executable target (non-test binary)
#[cfg(not(test))]
extern crate std;
/// A lightweight, fast, `#![no_std]` Pseudo-Random Number Generator (PRNG)
/// based on the Xoroshiro128++ algorithm.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Xoroshiro128PlusPlus {
s: [u64; 2],
}
impl Xoroshiro128PlusPlus {
/// Creates a new generator using a 64-bit seed.
///
/// Uses a SplitMix64 PRNG internally to expand a single `u64` seed
/// into the full 128-bit internal state.
pub const fn from_seed(seed: u64) -> Self {
let /* mut */ sm = SplitMix64::new(seed);
let (s0, sm) = sm.next_u64();
let (s1, _) = sm.next_u64();
Self { s: [s0, s1] }
}
/// Creates a generator directly from a 128-bit state (`[u64; 2]`).
/// Note: State cannot be entirely zero.
pub const fn from_state(state: [u64; 2]) -> Self {
if state[0] == 0 && state[1] == 0 {
Self {
s: [0x8A5CD789635D2DFF, 0x121FD2155C472F96],
}
} else {
Self { s: state }
}
}
/// Generates the next random `u64`.
pub fn next_u64(&mut self) -> u64 {
let s0 = self.s[0];
let mut s1 = self.s[1];
let result = s0.wrapping_add(s1).rotate_left(17).wrapping_add(s0);
s1 ^= s0;
self.s[0] = s0.rotate_left(49) ^ s1 ^ (s1 << 21);
self.s[1] = s1.rotate_left(28);
result
}
/// Generates the next random `u32`.
pub fn next_u32(&mut self) -> u32 {
(self.next_u64() >> 32) as u32
}
/// Generates a random boolean with 50% probability.
pub fn gen_bool(&mut self) -> bool {
(self.next_u64() & 1) == 1
}
/// Generates a random integer within a range `[low, high)`.
pub fn gen_range(&mut self, low: u64, high: u64) -> u64 {
assert!(low < high, "low must be strictly less than high");
let range = high - low;
low + (self.next_u64() % range)
}
/// Generates a floating-point number in the uniform range `[0.0, 1.0)`.
pub fn gen_f32(&mut self) -> f32 {
let bits = (self.next_u32() >> 8) as f32;
bits * (1.0 / (1 << 24) as f32)
}
/// Generates a 64-bit floating point number in `[0.0, 1.0)`.
pub fn gen_f64(&mut self) -> f64 {
let bits = (self.next_u64() >> 11) as f64;
bits * (1.0 / (1u64 << 53) as f64)
}
}
/// Helper SplitMix64 generator used solely for state initialization.
#[derive(Debug, Clone, Copy)]
struct SplitMix64 {
state: u64,
}
impl SplitMix64 {
const fn new(seed: u64) -> Self {
Self { state: seed }
}
/// Pure `const fn` progression returning the generated `u64` and updated state.
const fn next_u64(self) -> (u64, Self) {
let next_state = self.state.wrapping_add(0x9E3779B97F4A7C15);
let mut z = next_state;
z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9);
z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB);
let val = z ^ (z >> 31);
(val, Self { state: next_state })
}
}
fn main() {
let mut rng = Xoroshiro128PlusPlus::from_seed(0xDEAD_BEEF_1234_5678);
std::println!("Random u64: {}", rng.next_u64());
std::println!("Random u32: {}", rng.next_u32());
std::println!("Random Bool: {}", rng.gen_bool());
std::println!("Range [1,10): {}", rng.gen_range(1, 10));
std::println!("Random f32: {}", rng.gen_f32());
std::println!("Random f64: {}", rng.gen_f64());
}
@RandyMcMillan

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment