1pub fn std_dev(v: &[f64]) -> f64 {
14 if v.len() < 2 {
15 return f64::NAN;
16 }
17 let mean = v.iter().sum::<f64>() / v.len() as f64;
18 let var = v.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / (v.len() - 1) as f64;
19 var.sqrt()
20}
21
22pub fn median(v: &mut [f64]) -> f64 {
27 if v.is_empty() {
28 return 0.0;
29 }
30 v.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
31 let n = v.len();
32 if n % 2 == 1 {
33 v[n / 2]
34 } else {
35 0.5 * (v[n / 2 - 1] + v[n / 2])
36 }
37}
38
39#[cfg(test)]
40mod tests {
41 use super::*;
42
43 #[test]
44 fn std_dev_nan_below_two() {
45 assert!(std_dev(&[]).is_nan());
46 assert!(std_dev(&[1.0]).is_nan());
47 }
48
49 #[test]
50 fn std_dev_sample_variance() {
51 let s = std_dev(&[2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0]);
53 assert!((s - (32.0f64 / 7.0).sqrt()).abs() < 1e-12);
54 }
55
56 #[test]
57 fn median_empty_is_zero() {
58 let mut v: Vec<f64> = vec![];
59 assert_eq!(median(&mut v), 0.0);
60 }
61
62 #[test]
63 fn median_odd_and_even() {
64 let mut odd = [3.0, 1.0, 2.0];
65 assert_eq!(median(&mut odd), 2.0);
66 let mut even = [4.0, 1.0, 3.0, 2.0];
67 assert_eq!(median(&mut even), 2.5);
68 }
69
70 #[test]
71 fn median_sorts_in_place() {
72 let mut v = [3.0, 1.0, 2.0];
73 median(&mut v);
74 assert_eq!(v, [1.0, 2.0, 3.0]);
75 }
76}