[go: up one dir, main page]

randomize 3.0.1

randomization routines
Documentation
#![allow(clippy::unreadable_literal)]
#![forbid(unsafe_code)]

//! Various generator and conversion formulas. This module is a "junk drawer" of
//! stuff.
//!
//! For common usage of the library you **do not** need to read or understand
//! anything here, except perhaps the float conversions as described in the
//! [crate root](../index.html). Most of it is provided for sake of completeness
//! only.

/// The `u8` LCG.
///
/// Basically never use this one, it's just here for completeness.
#[inline]
pub const fn lcg8(state: u8, mult: u8, inc: u8) -> u8 {
  state.wrapping_mul(mult).wrapping_add(inc)
}

/// The `u16` LCG.
///
/// Basically never use this one, it's just here for completeness.
#[inline]
pub const fn lcg16(state: u16, mult: u16, inc: u16) -> u16 {
  state.wrapping_mul(mult).wrapping_add(inc)
}

/// The `u32` LCG.
///
/// Insufficiently random. Use _only_ in 32-bit environments when you can't be
/// bothered to do a 64-bit software multiply. At least discard the low 16-bits
/// of output if you can, and if possible run a full `u32` -> `u16` permutation.
#[inline]
pub const fn lcg32(state: u32, mult: u32, inc: u32) -> u32 {
  state.wrapping_mul(mult).wrapping_add(inc)
}

/// The `u64` LCG.
///
/// Insufficient on its own, but with a `u64` -> `u32` permutation applied this
/// is good enough for most any common randomization purposes.
#[inline]
pub const fn lcg64(state: u64, mult: u64, inc: u64) -> u64 {
  state.wrapping_mul(mult).wrapping_add(inc)
}

/// The `u128` LCG.
///
/// This is actually sufficient as a PRNG all on its own. The major downsides
/// are that 128-bit math is slower than 64-bit math, and also that without a
/// permutation the random quality of the bits leans towards the high bits.
#[inline]
pub const fn lcg128(state: u128, mult: u128, inc: u128) -> u128 {
  state.wrapping_mul(mult).wrapping_add(inc)
}

macro_rules! make_jump_lcgX {
  ($(#[$attr:meta])* $f:ident, $u:ty) => {
    $(#[$attr])*
    pub fn $f(mut delta: $u, state: $u, mult: $u, inc: $u) -> $u {
      let mut cur_mult: $u = mult;
      let mut cur_plus: $u = inc;
      let mut acc_mult: $u = 1;
      let mut acc_plus: $u = 0;
      while delta > 0 {
        if (delta & 1) > 0 {
          acc_mult = acc_mult.wrapping_mul(cur_mult);
          acc_plus = acc_plus.wrapping_mul(cur_mult).wrapping_add(cur_plus);
        }
        cur_plus = cur_mult.wrapping_add(1).wrapping_mul(cur_plus);
        cur_mult = cur_mult.wrapping_mul(cur_mult);
        delta /= 2;
      }
      acc_mult.wrapping_mul(state).wrapping_add(acc_plus)
    }
  };
}

make_jump_lcgX! {
  /// Gives the `lcg8` output `delta` steps from now in log(delta) time.
  jump_lcg8, u8
}
make_jump_lcgX! {
  /// Gives the `lcg16` output `delta` steps from now in log(delta) time.
  jump_lcg16, u16
}
make_jump_lcgX! {
  /// Gives the `lcg32` output `delta` steps from now in log(delta) time.
  jump_lcg32, u32
}
make_jump_lcgX! {
  /// Gives the `lcg64` output `delta` steps from now in log(delta) time.
  jump_lcg64, u64
}
make_jump_lcgX! {
  /// Gives the `lcg128` output `delta` steps from now in log(delta) time.
  jump_lcg128, u128
}

/// The Super Mario 64 PRNG. Only use this as a joke.
///
/// Watch the [Youtube video](https://www.youtube.com/watch?v=MiuLeTE2MeQ) for
/// an explanation of what's going on here.
pub fn sm64(mut input: u16) -> u16 {
  if input == 0x560A {
    input = 0;
  }
  let mut s0: u16 = input << 8;
  s0 ^= input;
  input = s0.swap_bytes();
  s0 = ((s0 & 0xFF) << 1) ^ input;
  let s1 = (s0 >> 1) ^ 0xFF80;
  if (s0 & 1) == 0 {
    if s1 == 0xAA55 {
      input = 0;
    } else {
      input = s1 ^ 0x1FF4;
    }
  } else {
    input = s1 ^ 0x8180;
  }
  input
}

/// The LCG from a game with "colosseum" in its name.
#[inline]
pub const fn pkmn_colosseum(state: u32) -> u32 {
  lcg32(state, 0x000343FD, 0x00269EC3)
}

/// The LCG from the gen3 and gen4 games.
#[inline]
pub const fn pkmn_gen3gen4(state: u32) -> u32 {
  lcg32(state, 0x41C64E6D, 0x00006073)
}

/// The alternate LCG from the gen4 games.
#[inline]
pub const fn pkmn_gen4alt(state: u32) -> u32 {
  lcg32(state, 0x6C078965, 0x00000001)
}

/// The LCG from the gen5 and gen6 games.
#[inline]
pub const fn pkmn_gen5gen6(state: u64) -> u64 {
  lcg64(state, 0x5D588B656C078965, 0x0000000000269EC3)
}

/// `u32` to `[0.0, 1.0)`
#[inline]
pub fn f32_half_open_right(u: u32) -> f32 {
  f32::from_bits(0x3f80_0000 | (u & 0x7fffff)) - 1.0
}

/// `u32` to `(0.0, 1.0]`
#[inline]
pub fn f32_half_open_left(mut u: u32) -> f32 {
  const TOTAL_BITS: u32 = 32;
  const MANTISSA_SCALE: f32 = 1.0 / ((1 << core::f32::MANTISSA_DIGITS) as f32);
  u >>= TOTAL_BITS - core::f32::MANTISSA_DIGITS;
  u += 1;
  u as f32 * MANTISSA_SCALE
}

/// `u32` to `(0.0, 1.0)`
#[inline]
pub fn f32_open(mut u: u32) -> f32 {
  const TOTAL_BITS: u32 = 32;
  const SMALL_MANTISSA: u32 = core::f32::MANTISSA_DIGITS - 1;
  const ZERO_EXPONENT_BITS: u32 = 127 << SMALL_MANTISSA;
  u >>= TOTAL_BITS - SMALL_MANTISSA;
  f32::from_bits(u | ZERO_EXPONENT_BITS) - (1.0 - core::f32::EPSILON / 2.0)
}

/// `u32` to `[0.0, 1.0]`
#[inline]
pub fn f32_closed(u: u32) -> f32 {
  const U32_MAX_AS_FLOAT: f32 = core::u32::MAX as f32;
  u as f32 / U32_MAX_AS_FLOAT
}

/// `u32` to `[-1.0, 1.0]`
#[inline]
pub fn f32_closed_neg_pos(u: u32) -> f32 {
  const U32_MAX_AS_FLOAT: f32 = core::u32::MAX as f32;
  ((u as f32 / U32_MAX_AS_FLOAT) - 0.5) * 2.0
}

/// `u64` to `[0.0, 1.0)`
#[inline]
pub fn f64_half_open_right(u: u64) -> f64 {
  f64::from_bits(0x3ff0000000000000 | (u & 0xFFFFFFFFFFFFF)) - 1.0
}

/// `u64` to `(0.0, 1.0]`
#[inline]
pub fn f64_half_open_left(mut u: u64) -> f64 {
  const TOTAL_BITS: u32 = 64;
  const MANTISSA_SCALE: f64 = 1.0 / ((1u64 << core::f64::MANTISSA_DIGITS) as f64);
  u >>= TOTAL_BITS - core::f64::MANTISSA_DIGITS;
  u += 1;
  u as f64 * MANTISSA_SCALE
}

/// `u64` to `(0.0, 1.0)`
#[inline]
pub fn f64_open(mut u: u64) -> f64 {
  const TOTAL_BITS: u32 = 64;
  const SMALL_MANTISSA: u32 = core::f64::MANTISSA_DIGITS - 1;
  const ZERO_EXPONENT_BITS: u64 = 1023 << SMALL_MANTISSA;
  u >>= TOTAL_BITS - SMALL_MANTISSA;
  f64::from_bits(u | ZERO_EXPONENT_BITS) - (1.0 - core::f64::EPSILON / 2.0)
}

/// `u64` to `[0.0, 1.0]`
#[inline]
pub fn f64_closed(u: u64) -> f64 {
  const U64_MAX_AS_DOUBLE: f64 = core::u64::MAX as f64;
  u as f64 / U64_MAX_AS_DOUBLE
}

/// `u64` to `[-1.0, 1.0]`
#[inline]
pub fn f64_closed_neg_pos(u: u64) -> f64 {
  const U64_MAX_AS_DOUBLE: f64 = core::u64::MAX as f64;
  ((u as f64 / U64_MAX_AS_DOUBLE) - 0.5) * 2.0
}

/// The PCG multiplier for 8 bits of state
pub const PCG_MULTIPLIER_8: u8 = 141;

/// The PCG multiplier for 16 bits of state
pub const PCG_MULTIPLIER_16: u16 = 12829;

/// The PCG multiplier for 32 bits of state
pub const PCG_MULTIPLIER_32: u32 = 747796405;

/// The PCG multiplier for 64 bits of state
pub const PCG_MULTIPLIER_64: u64 = 6364136223846793005;

/// The PCG multiplier for 128 bits of state
pub const PCG_MULTIPLIER_128: u128 = 47026247687942121848144207491837523525;

/// A suggested default seed for a PCG.
///
/// The number is `u128`, but just downcast to any smaller bit width.
pub const DEFAULT_PCG_SEED: u128 = 201526561274146932589719779721328219291;

/// A suggested default increment for a PCG.
///
/// The number is `u128`, but just downcast to any smaller bit width.
pub const DEFAULT_PCG_INC: u128 = 34172814569070222299;

/// Advances a PCG with 8 bits of state
#[inline]
pub const fn pcg_core_state8(state: u8, inc: u8) -> u8 {
  lcg8(state, PCG_MULTIPLIER_8, inc)
}

/// Advances a PCG with 16 bits of state
#[inline]
pub const fn pcg_core_state16(state: u16, inc: u16) -> u16 {
  lcg16(state, PCG_MULTIPLIER_16, inc)
}

/// Advances a PCG with 32 bits of state
#[inline]
pub const fn pcg_core_state32(state: u32, inc: u32) -> u32 {
  lcg32(state, PCG_MULTIPLIER_32, inc)
}

/// Advances a PCG with 64 bits of state
#[inline]
pub const fn pcg_core_state64(state: u64, inc: u64) -> u64 {
  lcg64(state, PCG_MULTIPLIER_64, inc)
}

/// Advances a PCG with 128 bits of state
#[inline]
pub const fn pcg_core_state128(state: u128, inc: u128) -> u128 {
  lcg128(state, PCG_MULTIPLIER_128, inc)
}

/// Permutation: XSH RR `u16` to `u8`
#[inline]
pub const fn xsh_rr_16_8(state: u16) -> u8 {
  ((((state >> 5) ^ state) >> 5) as u8).rotate_right((state >> 13) as u32)
}

/// Permutation: XSH RR `u32` to `u16`
#[inline]
pub const fn xsh_rr_32_16(state: u32) -> u16 {
  ((((state >> 10) ^ state) >> 12) as u16).rotate_right((state >> 28) as u32)
}

/// Permutation: XSH RR `u64` to `u32`
#[inline]
pub const fn xsh_rr_64_32(state: u64) -> u32 {
  ((((state >> 18) ^ state) >> 27) as u32).rotate_right((state >> 59) as u32)
}

/// Permutation: XSH RR `u128` to `u64`
#[inline]
pub const fn xsh_rr_128_64(state: u128) -> u64 {
  ((((state >> 29) ^ state) >> 58) as u64).rotate_right((state >> 122) as u32)
}

/// Permutation: XSH RS `u16` to `u8`
#[inline]
pub const fn xsh_rs_16_8(state: u16) -> u8 {
  (((state >> 7) ^ state) >> ((state >> 14) + 3)) as u8
}

/// Permutation: XSH RS `u32` to `u16`
#[inline]
pub const fn xsh_rs_32_16(state: u32) -> u16 {
  (((state >> 11) ^ state) >> ((state >> 30) + 11)) as u16
}

/// Permutation: XSH RS `u64` to `u32`
#[inline]
pub const fn xsh_rs_64_32(state: u64) -> u32 {
  (((state >> 22) ^ state) >> ((state >> 61) + 22)) as u32
}

/// Permutation: XSH RS `u128` to `u64`
#[inline]
pub const fn xsh_rs_128_64(state: u128) -> u64 {
  (((state >> 43) ^ state) >> ((state >> 124) + 45)) as u64
}

/// Permutation: RXS M XS `u8`
#[inline]
pub const fn rxs_m_xs_8_8(state: u8) -> u8 {
  let w = (state >> ((state >> 6).wrapping_add(2)) ^ state).wrapping_mul(217);
  w >> 6 ^ w
}

/// Permutation: RXS M XS `u16`
#[inline]
pub const fn rxs_m_xs_16_16(state: u16) -> u16 {
  let w = (state >> ((state >> 13).wrapping_add(3)) ^ state).wrapping_mul(62169);
  w >> 11 ^ w
}

/// Permutation: RXS M XS `u32`
#[inline]
pub const fn rxs_m_xs_32_32(state: u32) -> u32 {
  let w = (state >> ((state >> 28).wrapping_add(4)) ^ state).wrapping_mul(277803737);
  w >> 22 ^ w
}

/// Permutation: RXS M XS `u64`
#[inline]
pub const fn rxs_m_xs_64_64(state: u64) -> u64 {
  let w = (state >> ((state >> 59).wrapping_add(5)) ^ state).wrapping_mul(12605985483714917081);
  w >> 43 ^ w
}

/// Permutation: RXS M XS `u128`
#[inline]
pub const fn rxs_m_xs_128_128(state: u128) -> u128 {
  let w = (state >> ((state >> 122).wrapping_add(6)) ^ state)
    .wrapping_mul(327738287884841127335028083622016905945);
  w >> 86 ^ w
}

/// Permutation: XSL RR `u64` to `u32`
#[inline]
pub const fn xsl_rr_64_32(state: u64) -> u32 {
  ((state >> 32) as u32 ^ (state as u32)).rotate_right((state >> 59) as u32)
}

/// Permutation: XSL RR `u128` to `u64`
#[inline]
pub const fn xsl_rr_128_64(state: u128) -> u64 {
  ((state >> 64) as u64 ^ (state as u64)).rotate_right((state >> 122) as u32)
}

/// Permutation: XSL RR RR `u64`
#[inline]
pub const fn xsl_rr_rr_64_64(state: u64) -> u64 {
  let rot1: u32 = (state >> 59) as u32;
  let high: u32 = (state >> 32) as u32;
  let low: u32 = state as u32;
  let xor_d: u32 = high ^ low;
  let new_low: u32 = xor_d.rotate_right(rot1);
  let new_high: u32 = high.rotate_right(new_low & 31);
  ((new_high as u64) << 32) | new_low as u64
}

/// Permutation: XSL RR RR `u128`
#[inline]
pub const fn xsl_rr_rr_128_128(state: u128) -> u128 {
  let rot1: u32 = (state >> 122) as u32;
  let high: u64 = (state >> 64) as u64;
  let low: u64 = state as u64;
  let xor_d: u64 = high ^ low;
  let new_low: u64 = xor_d.rotate_right(rot1);
  let new_high: u64 = high.rotate_right((new_low & 63) as u32);
  ((new_high as u128) << 64) | new_low as u128
}