pub fn r_mean_narm(values: &[f64]) -> f64 {
let mut sum = 0.0f64;
let mut n = 0usize;
for &v in values {
if !v.is_nan() {
sum += v;
n += 1;
}
}
if n == 0 {
return f64::NAN;
}
let nf = n as f64;
let mut s = sum / nf;
if s.is_finite() {
let mut t = 0.0f64;
for &v in values {
if !v.is_nan() {
t += v - s;
}
}
s += t / nf;
}
s
}
pub fn r_median_narm(values: &[f64]) -> f64 {
let mut v: Vec<f64> = values.iter().copied().filter(|x| !x.is_nan()).collect();
let n = v.len();
if n == 0 {
return f64::NAN;
}
v.sort_by(f64::total_cmp);
let mid = n / 2;
if n % 2 == 1 {
v[mid]
} else {
r_mean_narm(&[v[mid - 1], v[mid]])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mean_basic() {
assert_eq!(r_mean_narm(&[1.0, 2.0, 3.0, 4.0]), 2.5);
assert_eq!(r_mean_narm(&[5.0]), 5.0);
}
#[test]
fn mean_narm() {
let got = r_mean_narm(&[1.0, 2.0, f64::NAN, 4.0]);
assert!((got - 7.0 / 3.0).abs() < 1e-15);
}
#[test]
fn mean_empty_is_nan() {
assert!(r_mean_narm(&[]).is_nan());
assert!(r_mean_narm(&[f64::NAN, f64::NAN]).is_nan());
}
#[test]
fn median_odd_even_na() {
assert_eq!(r_median_narm(&[3.0, 1.0, 2.0]), 2.0);
assert_eq!(r_median_narm(&[1.0, 2.0, 3.0, 4.0]), 2.5);
assert_eq!(r_median_narm(&[1.0, f64::NAN, 3.0]), 2.0);
assert!(r_median_narm(&[]).is_nan());
}
}