pub(super) fn count_to_f64(n: usize) -> f64 {
let wide = u64::try_from(n).unwrap_or(u64::MAX);
let hi = u32::try_from(wide >> 32).unwrap_or(0);
let lo = u32::try_from(wide & 0xFFFF_FFFF).unwrap_or(0);
f64::from(hi).mul_add(4_294_967_296.0, f64::from(lo))
}
pub(super) fn sample_variance(values: &[f64]) -> f64 {
let n = count_to_f64(values.len());
if n < 2.0 {
return 0.0;
}
let mean = values.iter().sum::<f64>() / n;
let ss: f64 = values
.iter()
.map(|&v| {
let d = v - mean;
d * d
})
.sum();
ss / (n - 1.0)
}
#[cfg(kani)]
mod verification {
use super::sample_variance;
const MAX_ABS: f64 = 1e6;
#[kani::proof]
fn density_sample_variance_non_negative() {
let v0: f64 = kani::any();
let v1: f64 = kani::any();
let v2: f64 = kani::any();
for v in [v0, v1, v2] {
kani::assume(v.is_finite());
kani::assume(v.abs() <= MAX_ABS);
}
let var = sample_variance(&[v0, v1, v2]);
assert!(
var.is_finite(),
"sample_variance produced a non-finite value"
);
assert!(var >= 0.0, "sample_variance produced a negative value");
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn count_widens_exactly() {
assert!((count_to_f64(2048) - 2048.0).abs() < 1e-12, "widening");
}
#[test]
fn variance_matches_hand_value() {
let v = sample_variance(&[2.0, 4.0, 6.0]);
assert!((v - 4.0).abs() < 1e-12, "variance was {v}");
}
#[test]
fn variance_of_singleton_is_zero() {
assert!(sample_variance(&[3.0]).abs() < 1e-12, "singleton variance");
}
}