#![allow(dead_code)]
pub fn mean(data: &[f32]) -> f32 {
if data.is_empty() {
return 0.0;
}
data.iter().sum::<f32>() / data.len() as f32
}
pub fn variance(data: &[f32]) -> f32 {
if data.len() < 2 {
return 0.0;
}
let m = mean(data);
data.iter().map(|&x| (x - m) * (x - m)).sum::<f32>() / data.len() as f32
}
pub fn std_dev(data: &[f32]) -> f32 {
variance(data).sqrt()
}
pub fn median(data: &[f32]) -> f32 {
if data.is_empty() {
return 0.0;
}
let mut sorted = data.to_vec();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let n = sorted.len();
if n.is_multiple_of(2) {
(sorted[n / 2 - 1] + sorted[n / 2]) / 2.0
} else {
sorted[n / 2]
}
}
pub fn min_val(data: &[f32]) -> f32 {
data.iter().cloned().fold(f32::MAX, f32::min)
}
pub fn max_val(data: &[f32]) -> f32 {
data.iter().cloned().fold(f32::MIN, f32::max)
}
pub fn pearson_r(x: &[f32], y: &[f32]) -> f32 {
let n = x.len().min(y.len());
if n == 0 {
return 0.0;
}
let mx = mean(&x[..n]);
let my = mean(&y[..n]);
let num: f32 = x[..n]
.iter()
.zip(y[..n].iter())
.map(|(&xi, &yi)| (xi - mx) * (yi - my))
.sum();
let dx: f32 = x[..n]
.iter()
.map(|&xi| (xi - mx) * (xi - mx))
.sum::<f32>()
.sqrt();
let dy: f32 = y[..n]
.iter()
.map(|&yi| (yi - my) * (yi - my))
.sum::<f32>()
.sqrt();
if dx < 1e-12 || dy < 1e-12 {
return 0.0;
}
num / (dx * dy)
}
pub fn percentile(data: &[f32], p: f32) -> f32 {
if data.is_empty() {
return 0.0;
}
let mut sorted = data.to_vec();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let idx = (p / 100.0 * (sorted.len() - 1) as f32).clamp(0.0, (sorted.len() - 1) as f32);
let lo = idx.floor() as usize;
let hi = idx.ceil() as usize;
let frac = idx - lo as f32;
sorted[lo] + frac * (sorted[hi] - sorted[lo])
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mean_basic() {
let d = [1.0f32, 2.0, 3.0, 4.0, 5.0];
assert!((mean(&d) - 3.0).abs() < 1e-5);
}
#[test]
fn test_mean_empty() {
assert!(mean(&[]).abs() < 1e-9);
}
#[test]
fn test_variance_constant() {
let d = [5.0f32; 10];
assert!(variance(&d).abs() < 1e-9);
}
#[test]
fn test_std_dev_known() {
let d = [2.0f32, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
assert!((std_dev(&d) - 2.0).abs() < 1e-4);
}
#[test]
fn test_median_odd() {
let d = [5.0f32, 1.0, 3.0];
assert!((median(&d) - 3.0).abs() < 1e-5);
}
#[test]
fn test_median_even() {
let d = [4.0f32, 2.0, 1.0, 3.0];
assert!((median(&d) - 2.5).abs() < 1e-5);
}
#[test]
fn test_min_max() {
let d = [3.0f32, 1.0, 4.0, 1.0, 5.0];
assert!((min_val(&d) - 1.0).abs() < 1e-6);
assert!((max_val(&d) - 5.0).abs() < 1e-6);
}
#[test]
fn test_pearson_r_perfect() {
let x: Vec<f32> = (0..10).map(|i| i as f32).collect();
let y: Vec<f32> = x.iter().map(|&v| v * 2.0 + 3.0).collect();
let r = pearson_r(&x, &y);
assert!((r - 1.0).abs() < 1e-4);
}
#[test]
fn test_percentile_50() {
let d: Vec<f32> = (1..=11).map(|i| i as f32).collect();
let p = percentile(&d, 50.0);
assert!((p - 6.0).abs() < 1e-4);
}
}