pub struct XorShift32 {
state: u32,
}
impl XorShift32 {
pub fn new(seed: u32) -> Self {
Self {
state: if seed == 0 { 1 } else { seed },
}
}
pub fn next_u32(&mut self) -> u32 {
let mut x = self.state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
self.state = x;
x
}
pub fn next_f32(&mut self) -> f32 {
let v = self.next_u32() as f32 / (u32::MAX as f32);
(v * 2.0) - 1.0
}
pub fn next_range_usize(&mut self, max: usize) -> usize {
if max == 0 {
return 0;
}
(self.next_u32() as usize) % max
}
}
pub fn approx_eq(a: f32, b: f32, eps: f32) -> bool {
if a.is_nan() && b.is_nan() {
return true;
}
if a.is_infinite() || b.is_infinite() {
return a == b;
}
(a - b).abs() <= eps
}
pub fn all_finite(slice: &[f32]) -> bool {
slice.iter().all(|v| v.is_finite())
}
pub fn saturating_add_f32(a: f32, b: f32) -> f32 {
let r = a + b;
if r.is_infinite() {
if b.is_sign_positive() {
f32::MAX
} else {
f32::MIN
}
} else if r.is_nan() {
a
} else {
r
}
}
#[cfg(test)]
mod self_usage {
use super::*;
use native_neural_network_std::std::engine_std::{
get_compute_backend, set_compute_backend, ComputeBackend,
};
#[test]
fn cpu_backend_abstraction_real() {
let previous = get_compute_backend();
set_compute_backend(ComputeBackend::Cpu);
assert_eq!(get_compute_backend(), ComputeBackend::Cpu);
set_compute_backend(previous);
}
#[test]
fn utils_are_used_here() {
let mut rng = XorShift32::new(0x1);
let _u = rng.next_u32();
let _f = rng.next_f32();
let _r = rng.next_range_usize(10);
assert!(_r < 10);
let a = 1.0f32;
let b = 1.0f32 + 1e-8;
assert!(approx_eq(a, b, 1e-6));
let arr = [0.0f32, 1.0, -2.0];
assert!(all_finite(&arr));
let s = saturating_add_f32(1.0, 2.0);
assert_eq!(s, 3.0f32);
}
}