122 lines
3.6 KiB
Rust
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))
|
|
}
|