use dashu_float::{FBig, round::mode::HalfEven};
use crate::layouts::{Backend, HostDataRef, VecZnx, VecZnxBig};
pub struct Stats {
max: f64,
std: f64,
}
impl Stats {
pub fn max(&self) -> f64 {
self.max
}
pub fn std(&self) -> f64 {
self.std
}
}
impl<D: HostDataRef> VecZnx<D> {
pub fn stats(&self, base2k: usize, col: usize) -> Stats {
let mut data: Vec<FBig<HalfEven>> = (0..self.n()).map(|_| FBig::ZERO).collect();
self.decode_vec_float(base2k, col, &mut data);
let mut avg: FBig<HalfEven> = FBig::ZERO;
let mut max: FBig<HalfEven> = FBig::ZERO;
data.iter().for_each(|x| {
avg = avg.clone() + x.clone();
let abs_x = if x < &FBig::<HalfEven>::ZERO { -x.clone() } else { x.clone() };
if abs_x > max {
max = abs_x;
}
});
avg /= FBig::from(data.len() as i64);
data.iter_mut().for_each(|x| {
*x = x.clone() - avg.clone();
});
let mut variance: FBig<HalfEven> = FBig::ZERO;
data.iter().for_each(|x| {
variance = variance.clone() + x.clone() * x.clone();
});
variance /= FBig::from(data.len() as i64);
Stats {
std: variance.to_f64().value().sqrt(),
max: max.to_f64().value(),
}
}
}
impl<D: HostDataRef, B: Backend + Backend<ScalarBig = i64>> VecZnxBig<D, B> {
pub fn stats(&self, base2k: usize, col: usize) -> Stats {
let shape = self.shape();
let znx: VecZnx<&[u8]> =
VecZnx::from_data_with_max_size(self.data.as_ref(), shape.n(), shape.cols(), shape.size(), shape.max_size());
znx.stats(base2k, col)
}
}