use std::fmt;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::{Arc, Mutex};
#[cfg(test)]
mod tests;
extern "C" {
fn __ieee754_sqrt(x: f64) -> f64;
fn __ieee754_log(x: f64) -> f64;
}
const MULTIPLIER: i64 = 0x0005_deec_e66d;
const INCREMENT: i64 = 0xb;
const MASK: i64 = (1 << 48) - 1;
pub struct Random {
state: AtomicI64,
next_next_gaussian: Arc<Mutex<Option<f64>>>,
}
impl Random {
#[must_use]
pub fn new(seed: i64) -> Self {
Self {
state: AtomicI64::new(Self::initalize_state(seed)),
next_next_gaussian: Arc::new(Mutex::new(None)),
}
}
const fn initalize_state(seed: i64) -> i64 {
seed ^ MULTIPLIER & MASK
}
fn next(&mut self, bits: u8) -> i32 {
assert!(bits <= 32, "can't return more than 32 random bits");
let mut previous_state = self.state.load(Ordering::Acquire);
loop {
let new_state = previous_state
.wrapping_mul(MULTIPLIER)
.wrapping_add(INCREMENT)
& MASK;
match self.state.compare_exchange_weak(
previous_state,
new_state,
Ordering::AcqRel,
Ordering::Relaxed,
) {
Ok(_) => return (new_state >> (48 - bits)) as i32,
Err(state) => previous_state = state,
}
}
}
pub fn next_i32(&mut self) -> i32 {
self.next(32)
}
pub fn next_i32_bounded(&mut self, bound: i32) -> i32 {
assert!(bound > 0, "bound must be positive");
if (bound & -bound) == bound {
let bound_i64 = i64::from(bound);
let next_i64 = i64::from(self.next(31));
let result = bound_i64.wrapping_mul(next_i64) >> 31;
result as i32
} else {
loop {
let bits = self.next(31);
let val = bits % bound;
if !bits.wrapping_sub(val).wrapping_add(bound.wrapping_sub(1)) < 0 {
return val;
}
}
}
}
pub fn next_i64(&mut self) -> i64 {
(i64::from(self.next(32)) << 32) + i64::from(self.next(32))
}
pub fn next_bool(&mut self) -> bool {
self.next(1) != 0
}
pub fn next_f32(&mut self) -> f32 {
self.next(24) as f32 / ((1 << 24) as f32)
}
pub fn next_f64(&mut self) -> f64 {
(((i64::from(self.next(26)) << 27) + i64::from(self.next(27))) as f64)
/ ((1_i64 << 53) as f64)
}
pub fn next_bytes(&mut self, bytes: &mut [i8]) {
let max = bytes.len() & !0x3;
for i in (0..max).step_by(4) {
let random = self.next(32);
bytes[i] = random as i8;
bytes[i + 1] = (random >> 8) as i8;
bytes[i + 2] = (random >> 16) as i8;
bytes[i + 3] = (random >> 24) as i8;
}
if max < bytes.len() {
let mut random = self.next(32);
for byte in bytes.iter_mut().skip(max) {
*byte = random as i8;
random >>= 8;
}
}
}
pub fn next_gaussian(&mut self) -> f64 {
let mutex = self.next_next_gaussian.clone();
let mut next_gaussian = mutex.lock().unwrap();
if let Some(gaussian) = *next_gaussian {
*next_gaussian = None;
gaussian
} else {
let mut s;
let mut v1;
let mut v2;
loop {
v1 = 2_f64 * self.next_f64() - 1_f64;
v2 = 2_f64 * self.next_f64() - 1_f64;
s = v1 * v1 + v2 * v2;
if !(s >= 1_f64 || s == 0_f64) {
break;
}
}
let multiplier;
unsafe {
multiplier = __ieee754_sqrt(-2_f64 * __ieee754_log(s) / s);
}
*next_gaussian = Some(v2 * multiplier);
v1 * multiplier
}
}
}
impl fmt::Debug for Random {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"Random number generator implemented with the same algorithm as java.util.Random"
)
}
}
static SEED_UNIQUFIER: AtomicI64 = AtomicI64::new(8_682_522_807_148_012);
impl Default for Random {
#[inline]
fn default() -> Self {
use std::time::{SystemTime, UNIX_EPOCH};
const MULTIPLIER: i64 = 1181783497276652981;
let mut current = SEED_UNIQUFIER.load(Ordering::Acquire);
loop {
let new = current.wrapping_mul(MULTIPLIER);
match SEED_UNIQUFIER.compare_exchange_weak(
current,
new,
Ordering::AcqRel,
Ordering::Relaxed,
) {
Ok(_) => {
let elapsed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("SystemTime returned value earlier than UNIX_EPOCH");
return Self::new(new ^ (elapsed.as_nanos() as i64));
}
Err(uniquifier) => current = uniquifier,
}
}
}
}