numeric_statistics/f32/
variance.rs

1use super::average;
2
3/// Calculate statistical variance for values.
4///
5/// Return NaN if the values are empty.
6///
7/// Filter NaN values in the stream.
8///
9pub fn variance<T: AsRef<[f32]>>(values: T) -> f32 {
10    let values = values.as_ref();
11    if values.is_empty() { return f32::NAN; }
12    let average = average(values);
13    variance_with_average(values, average)
14}
15
16/// Calculate statistical variance for values, 
17/// given a pre-calculated average value.
18///
19/// Return NaN if the values are empty.
20///
21/// Filter NaN values in the stream.
22/// 
23pub fn variance_with_average<T: AsRef<[f32]>>(values: T, average: f32) -> f32 {
24    let values = values.as_ref();
25    if values.is_empty() { return f32::NAN; }
26    let mut delta_square_sum: f32 = 0.0;
27    let mut len: usize = 0;
28    values.iter().for_each(|x|
29        if !x.is_nan() {
30            let delta = x - average;
31            delta_square_sum += delta * delta;
32            len += 1;
33        }
34    );
35    match len {
36        0 => return f32::NAN,
37        1 => return 0.0,
38        x => delta_square_sum / ((x - 1) as f32)
39    }
40}
41
42#[cfg(test)]
43mod test {
44    use super::*;
45
46    #[test]
47    fn test_empty() {
48        let x: &[f32] = &[];
49        assert!(variance(x).is_nan());
50    }
51
52    #[test]
53    fn test_nan() {
54        let x: &[f32] = &[f32::NAN];
55        assert!(variance(x).is_nan());
56    }
57
58    #[test]
59    fn test_value() {
60        let x: &[f32] = &[1.0];
61        assert_eq_float!(variance(x), 0.0);
62    }
63
64    #[test]
65    fn test_values_ascending() {
66        let x = &[1.0, 2.0, 4.0];
67        assert_eq_float!(variance(x), 2.3333333333333333 as f32);
68    }
69
70    #[test]
71    fn test_values_ascending_and_nans() {
72        let x = &[1.0, f32::NAN, 2.0, f32::NAN, 4.0];
73        assert_eq_float!(variance(x), 2.3333333333333333 as f32);
74    }
75
76}