use crate::random;
pub fn random_real() -> f64 {
let mut exponent: i32 = 0;
let mut significand: u64 = 0;
while significand == 0 {
exponent -= 64;
significand = random::get_random_u64();
if exponent < -1074 {
return 0.0;
}
}
let shift = significand.leading_zeros() as i32;
if shift != 0 {
let r = random::get_random_u64();
exponent -= shift;
significand <<= shift;
significand |= r >> (64 - shift);
}
significand |= 1;
(significand as f64) * (exponent as f64).exp2()
}
pub fn random_real_max(max: f64) -> f64 {
random_real() * max
}
pub fn random_real_range(min: f64, max: f64) -> f64 {
min + random_real() * (max - min)
}
pub fn random_real_53() -> f64 {
let a = random::get_random_u32() >> 5;
let b = random::get_random_u32() >> 6;
(a as f64 * 67108864.0 + b as f64) * (1.0 / 9007199254740992.0)
}
pub fn math_random_real(args: &[f64]) -> Result<f64, String> {
match args.len() {
0 => Ok(random_real_53()),
1 => {
let max = args[0];
if max <= 0.0 {
return Err("random: max must be positive".to_string());
}
Ok(random_real_max(max))
}
2 => {
let min = args[0];
let max = args[1];
if max <= min {
return Err("random: max must be greater than min".to_string());
}
Ok(random_real_range(min, max))
}
_ => Err("random: too many arguments".to_string()),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_random_real_range() {
for _ in 0..100 {
let r = random_real();
assert!((0.0..1.0).contains(&r));
}
}
#[test]
fn test_random_real_max() {
for _ in 0..100 {
let r = random_real_max(10.0);
assert!((0.0..10.0).contains(&r));
}
}
#[test]
fn test_random_real_min_max() {
for _ in 0..100 {
let r = random_real_range(5.0, 10.0);
assert!((5.0..10.0).contains(&r));
}
}
#[test]
fn test_random_real_53() {
for _ in 0..100 {
let r = random_real_53();
assert!((0.0..1.0).contains(&r));
}
}
#[test]
fn test_math_random_real_no_args() {
let result = math_random_real(&[]);
assert!(result.is_ok());
let r = result.unwrap();
assert!((0.0..1.0).contains(&r));
}
#[test]
fn test_math_random_real_one_arg() {
let result = math_random_real(&[100.0]);
assert!(result.is_ok());
let r = result.unwrap();
assert!((0.0..100.0).contains(&r));
}
#[test]
fn test_math_random_real_two_args() {
let result = math_random_real(&[10.0, 20.0]);
assert!(result.is_ok());
let r = result.unwrap();
assert!((10.0..20.0).contains(&r));
}
#[test]
fn test_math_random_real_invalid() {
assert!(math_random_real(&[-1.0]).is_err());
assert!(math_random_real(&[10.0, 5.0]).is_err());
assert!(math_random_real(&[1.0, 2.0, 3.0]).is_err());
}
}