use rand::{Rng, RngExt};
#[inline]
pub fn gen_unit_f32() -> f32 {
let mut rng = rand::rng();
gen_unit_f32_with_rng(&mut rng)
}
#[inline]
pub fn gen_unit_f32_with_rng<R>(rng: &mut R) -> f32
where
R: Rng + ?Sized,
{
rng.random::<f32>()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gen_unit_f32() {
for _ in 0..100 {
let v = gen_unit_f32();
assert!((0.0..1.0).contains(&v));
}
}
#[test]
fn test_gen_unit_f32_range() {
for _ in 0..10_000 {
let val = gen_unit_f32();
assert!(val >= 0.0);
assert!(val < 1.0);
}
}
#[test]
fn test_gen_unit_f32_multithreaded() {
use std::thread;
let mut handles = vec![];
for _ in 0..8 {
let handle = thread::spawn(|| {
for _ in 0..1000 {
let val = gen_unit_f32();
assert!(val >= 0.0);
assert!(val < 1.0);
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
#[test]
fn test_gen_unit_f32_with_rng_seeded_is_deterministic() {
use rand::SeedableRng;
use rand::rngs::StdRng;
const N: usize = 2_048;
let mut a = StdRng::seed_from_u64(42);
let mut b = StdRng::seed_from_u64(42);
let seq_a: Vec<f32> = (0..N).map(|_| gen_unit_f32_with_rng(&mut a)).collect();
let seq_b: Vec<f32> = (0..N).map(|_| gen_unit_f32_with_rng(&mut b)).collect();
assert_eq!(seq_a, seq_b);
assert!(seq_a.iter().all(|&v| (0.0..1.0).contains(&v)));
assert!(
seq_a.windows(2).any(|w| w[0] != w[1]),
"seeded stream should vary across draws"
);
let mut c = StdRng::seed_from_u64(43);
let seq_c: Vec<f32> = (0..N).map(|_| gen_unit_f32_with_rng(&mut c)).collect();
assert_ne!(seq_a, seq_c);
}
}