#![no_std]
use rand_core::{RngCore, SeedableRng};
use core::num::Wrapping;
struct SplitMix64 {
state: u64,
}
impl SplitMix64 {
fn new(seed: u64) -> Self {
Self { state: seed }
}
fn next(&mut self) -> u64 {
self.state = self.state.wrapping_add(0x9e3779b97f4a7c15);
let mut z = self.state;
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
z ^ (z >> 31)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Biski64Rng {
fast_loop: Wrapping<u64>,
mix: Wrapping<u64>,
loop_mix: Wrapping<u64>,
}
impl Biski64Rng {
pub fn from_seed_for_stream(seed: u64, stream_index: u64, total_streams: u64) -> Self {
assert!(total_streams >= 1, "Total number of streams must be at least 1.");
assert!(stream_index < total_streams, "Stream index must be less than total streams.");
let mut seeder = SplitMix64::new(seed);
let mut s0 = 0;
let mut s1 = 0;
let mut s2 = 0;
while s0 == 0 && s1 == 0 && s2 == 0 {
s0 = seeder.next(); s1 = seeder.next(); s2 = seeder.next(); }
let base_fast_loop = s0;
let final_fast_loop = if total_streams > 1 {
let cycles_per_stream: u128 = (u64::MAX as u128) / (total_streams as u128);
let offset: u128 = (stream_index as u128)
.wrapping_mul(cycles_per_stream)
.wrapping_mul(0x9999999999999999 as u128);
base_fast_loop.wrapping_add(offset as u64)
} else {
base_fast_loop
};
let mut rng = Self {
fast_loop: Wrapping(final_fast_loop),
mix: Wrapping(s1),
loop_mix: Wrapping(s2),
};
for _ in 0..16 {
rng.next_u64();
}
rng
}
}
impl RngCore for Biski64Rng {
#[inline(always)]
fn next_u64(&mut self) -> u64 {
let output = self.mix + self.loop_mix;
let old_loop_mix = self.loop_mix;
self.loop_mix = self.fast_loop ^ self.mix;
self.mix = Wrapping(self.mix.0.rotate_left(16)) + Wrapping(old_loop_mix.0.rotate_left(40));
self.fast_loop += 0x9999999999999999;
output.0
}
#[inline(always)]
fn next_u32(&mut self) -> u32 {
(self.next_u64() >> 32) as u32
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
rand_core::impls::fill_bytes_via_next(self, dest)
}
}
impl SeedableRng for Biski64Rng {
type Seed = [u8; 32];
fn from_seed(seed: Self::Seed) -> Self {
let seed_for_seeder = u64::from_le_bytes(seed[0..8].try_into().unwrap());
let mut seeder = SplitMix64::new(seed_for_seeder);
let mut s0 = 0;
let mut s1 = 0;
let mut s2 = 0;
while s0 == 0 && s1 == 0 && s2 == 0 {
s0 = seeder.next();
s1 = seeder.next();
s2 = seeder.next();
}
let mut rng = Self {
fast_loop: Wrapping(s0),
mix: Wrapping(s1),
loop_mix: Wrapping(s2),
};
for _ in 0..16 {
rng.next_u64();
}
rng
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sequence_from_known_seed() {
let mut rng = Biski64Rng::seed_from_u64(12345);
assert_eq!(rng.next_u64(), 11653916018131561298);
assert_eq!(rng.next_u64(), 8879211503557437945);
assert_eq!(rng.next_u64(), 8034477089638237744);
}
#[test]
fn test_seed_from_u64_is_deterministic() {
let mut rng1 = Biski64Rng::seed_from_u64(42);
let mut rng2 = Biski64Rng::seed_from_u64(42);
assert_eq!(rng1.next_u64(), rng2.next_u64());
}
#[test]
fn test_from_seed_is_deterministic() {
let mut seed = [0u8; 32];
seed[0] = 1;
seed[5] = 5;
seed[15] = 15;
seed[31] = 31;
let mut rng1 = Biski64Rng::from_seed(seed);
let mut rng2 = Biski64Rng::from_seed(seed);
assert_eq!(rng1.next_u64(), rng2.next_u64());
}
#[test]
fn test_parallel_streams_start_differently() {
let seed = 123456789;
let mut stream0 = Biski64Rng::from_seed_for_stream(seed, 0, 4);
let mut stream1 = Biski64Rng::from_seed_for_stream(seed, 1, 4);
let mut stream2 = Biski64Rng::from_seed_for_stream(seed, 2, 4);
let val0 = stream0.next_u64();
let val1 = stream1.next_u64();
let val2 = stream2.next_u64();
assert_ne!(val0, val1, "Streams 0 and 1 should not produce the same first value");
assert_ne!(val0, val2, "Streams 0 and 2 should not produce the same first value");
assert_ne!(val1, val2, "Streams 1 and 2 should not produce the same first value");
}
}