use dashu_float::{FBig, round::mode::HalfEven};
use crate::layouts::{Backend, DataRef, VecZnx, VecZnxBig, VecZnxBigToRef, ZnxInfos};
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: DataRef> 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: DataRef, B: Backend + Backend<ScalarBig = i64>> VecZnxBig<D, B> {
pub fn stats(&self, base2k: usize, col: usize) -> Stats {
let self_ref: VecZnxBig<&[u8], B> = self.to_ref();
let znx: VecZnx<&[u8]> = VecZnx {
data: self_ref.data,
n: self_ref.n,
cols: self_ref.cols,
size: self_ref.size,
max_size: self_ref.max_size,
};
znx.stats(base2k, col)
}
}