psychopath/sub_crates/rrand/src/lib.rs

122 lines
3.6 KiB
Rust

//! Sources of deterministic "randomness" for rendering applications.
/// Convert a `u32` to a float in [0.0, 1.0).
///
/// Use for getting f32 values from random u32 sources.
///
/// Note: this is a linear mapping from [0, int_max] to [0.0, 1.0).
#[inline(always)]
pub fn u32_to_f32_norm(n: u32) -> f32 {
f32::from_bits((n >> 9) | 0x3f800000) - 1.0
}
//-------------------------------------------------------------
/// A fast RNG.
///
#[derive(Debug, Copy, Clone)]
pub struct Rng {
state: u64,
}
impl Rng {
/// Creates a new Rng from a seed.
///
/// A seed of zero is perfectly fine, and does not affect the quality
/// of the generator.
#[inline]
pub fn new(seed: u64) -> Self {
Self { state: seed }
}
/// Gets the nth relative RNG stream from this one.
///
/// The returned stream will be at the same point in its sequence as
/// this one.
#[inline]
pub fn nth_stream(&self, n: u64) -> Self {
Self {
// We just jump forward 2^40*n states. This gives us 2^24
// unique streams, each of which is 2^40 numbers long.
state: self
.state
.wrapping_add(0xa0761d6478bd642f_u64.wrapping_mul(1 << 40).wrapping_mul(n)),
}
}
/// Returns a random u32 in [0, int_max].
#[inline(always)]
pub fn u32(&mut self) -> u32 {
self.u64() as u32
}
/// Returns a random u64 in [0, int_max].
#[inline(always)]
pub fn u64(&mut self) -> u64 {
// The wyrand RNG.
self.state = self.state.wrapping_add(0xa0761d6478bd642f);
let t = (self.state as u128).wrapping_mul(self.state as u128 ^ 0xe7037ed1a0b428db);
((t >> 64) ^ t) as u64
}
}
//-------------------------------------------------------------
/// A fast 32-bit mixing function.
///
/// Scrambles the input number to produce a different deterministic
/// "random" number.
#[inline(always)]
pub fn mix_u32(mut n: u32) -> u32 {
// From https://github.com/skeeto/hash-prospector
n ^= n >> 16;
n = n.wrapping_mul(0x21f0aaad);
n ^= n >> 15;
n = n.wrapping_mul(0xd35a2d97);
n ^= n >> 15;
// Xor by a random number so input zero doesn't map to output zero.
// The particular number used here isn't special.
n ^ 0xe6fe3beb
}
/// A fast seedable 32-bit mixing function.
///
/// Same as `mix_u32()` but takes a seed.
#[inline(always)]
pub fn mix_seed_u32(n: u32, seed: u32) -> u32 {
// We rotate the bits of `seed` so it's unlikely to interact with `n`
// in bad ways if they're both e.g. incrementing. The particular
// rotation constant used here isn't special.
mix_u32(n ^ seed.rotate_left(23))
}
/// A fast 64-bit mixing function.
///
/// Scrambles the input number to produce a different deterministic
/// "random" number.
#[inline(always)]
pub fn mix_u64(mut n: u64) -> u64 {
// From https://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html
n ^= n >> 30;
n = n.wrapping_mul(0xbf58476d1ce4e5b9);
n ^= n >> 27;
n = n.wrapping_mul(0x94d049bb133111eb);
n ^= n >> 31;
// Xor by a random number so input zero doesn't map to output zero.
// The particular number used here isn't special.
n ^ 0x4acc3f27cc712c9d
}
/// A fast seedable 64-bit mixing function.
///
/// Same as `mix_u64()` but takes a seed.
#[inline(always)]
pub fn mix_seed_u64(n: u64, seed: u64) -> u64 {
// We rotate the bits of `seed` so it's unlikely to interact with `n`
// in bad ways if they're both e.g. incrementing. The particular
// rotation constant used here isn't special.
mix_u64(n ^ seed.rotate_left(47))
}