use std::println;
use std::time::Instant;
pub const T_THRESHOLD: f64 = 4.5;
#[derive(Default)]
pub struct TTest {
n0: f64,
n1: f64,
mean0: f64,
mean1: f64,
m2_0: f64,
m2_1: f64,
}
impl TTest {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, value: f64, class: u8) {
if class == 0 {
self.n0 += 1.0;
let delta = value - self.mean0;
self.mean0 += delta / self.n0;
let delta2 = value - self.mean0;
self.m2_0 += delta * delta2;
} else {
self.n1 += 1.0;
let delta = value - self.mean1;
self.mean1 += delta / self.n1;
let delta2 = value - self.mean1;
self.m2_1 += delta * delta2;
}
}
pub fn t_value(&self) -> f64 {
if self.n0 < 2.0 || self.n1 < 2.0 {
return 0.0;
}
let var0 = self.m2_0 / (self.n0 - 1.0);
let var1 = self.m2_1 / (self.n1 - 1.0);
let se = (var0 / self.n0 + var1 / self.n1).sqrt();
if se == 0.0 {
return 0.0;
}
(self.mean0 - self.mean1) / se
}
}
pub struct Xorshift64 {
state: u64,
}
impl Xorshift64 {
pub fn new(seed: u64) -> Self {
Self { state: seed }
}
pub fn next(&mut self) -> u64 {
let mut x = self.state;
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
self.state = x;
x
}
pub fn next_bool(&mut self) -> bool {
self.next() & 1 == 1
}
pub fn fill_bytes(&mut self, buf: &mut [u8]) {
for chunk in buf.chunks_mut(8) {
let val = self.next();
for (i, b) in chunk.iter_mut().enumerate() {
*b = (val >> (i * 8)) as u8;
}
}
}
}
#[inline(never)]
pub fn measure_ns<F: FnMut()>(mut f: F) -> f64 {
let start = Instant::now();
f();
start.elapsed().as_nanos() as f64
}
pub fn report(name: &str, t: &TTest) {
let t_val = t.t_value();
let verdict = if t_val.abs() < T_THRESHOLD { "PASS" } else { "FAIL" };
println!(" {:<45} t={:>8.2} [{}]", name, t_val, verdict);
}