vec_utilities/maths/
stats.rs1pub trait Statistics<T> {
4 fn mean(self) -> Option<T>;
5 fn median(self) -> Option<T>;
6 fn variance(self) -> Option<T>;
7 fn std(self) -> Option<T>;
8
9 fn float_max(self) -> T;
11 fn float_min(self) -> T;
12
13 fn difference(self) -> T;
14 fn zero_crossings(self) -> usize;
15
16 fn peak_average_ratio(self) -> Option<T>;
17}
18
19macro_rules! impl_stats_iterator {
20 ($float:ty) => {
21 impl<'a, T: Iterator<Item = &'a $float>> Statistics<$float> for T {
22 fn mean(self) -> Option<$float> {
23 let (sum, count) =
24 self.fold((0.0, 0), |(sum, count), item| (sum + item, count + 1));
25
26 if count > 0 {
27 Some(sum / (count as $float))
28 } else {
29 None
30 }
31 }
32 fn variance(self) -> Option<$float> {
34 let mut m = 0.0 as $float;
35 let mut s = 0.0 as $float;
36 let mut k = 1.0 as $float;
37
38 for item in self {
39 let old_m = m;
40 m = m + (item - m) / k;
41 s = s + (item - m) * (item - old_m);
42 k = k + 1.0 as $float;
43 }
44
45 if k > 0.0 as $float {
46 return Some(s / (k - 1.0 as $float));
47 } else {
48 return None;
49 }
50 }
51
52 fn std(self) -> Option<$float> {
53 self.variance().map(|x| x.sqrt())
54 }
55
56 fn median(self) -> Option<$float> {
57 let elements: Vec<$float> = self.cloned().collect();
59 let len = elements.len();
60 if elements.len() == 0 {
61 return None;
62 }
63
64 let mut new = elements
65 .iter()
66 .map(|x| x.to_owned())
67 .collect::<Vec<$float>>();
68
69 new.sort_by(|a, b| a.total_cmp(b));
70
71 let mid = len / 2;
72
73 if len % 2 == 0 {
74 let low = match new.get(mid - 1) {
75 Some(x) => x,
76 None => return None,
77 };
78
79 let high = match new.get(mid) {
80 Some(x) => x,
81 None => return None,
82 };
83
84 return Some((low + high) / (2.0 as $float));
85 } else {
86 return match new.get(mid) {
87 Some(x) => Some(*x),
88 None => None,
89 };
90 }
91 }
92
93 fn float_max(self) -> $float {
94 self.fold(<$float>::NEG_INFINITY, |a, b| a.max(*b))
95 }
96
97 fn float_min(self) -> $float {
98 self.fold(<$float>::INFINITY, |a, b| a.min(*b))
99 }
100
101 fn difference(self) -> $float {
102 let mut min = <$float>::INFINITY;
106 let mut max = <$float>::NEG_INFINITY;
107
108 for n in self {
109 min = n.min(min);
110 max = n.max(max);
111 }
112
113 max - min
114 }
115
116 fn zero_crossings(self) -> usize {
117 let mut zero_crossings = 0;
118 let mut prev_item = None;
119
120 for item in self {
121 if let Some(prev) = prev_item {
122 if prev * item < 0.0 {
123 zero_crossings += 1;
124 }
125 }
126 prev_item = Some(item);
127 }
128
129 zero_crossings
130 }
131
132 fn peak_average_ratio(self) -> Option<$float> {
133 let (sum, count, max) = self.fold(
134 (0.0, 0, <$float>::NEG_INFINITY),
135 |(sum, count, max), item| (sum + item, count + 1, item.max(max)),
136 );
137
138 if count == 0 {
139 return None;
140 } else {
141 return Some(max / (sum / count as $float));
142 }
143 }
144 }
145 };
146}
147
148impl_stats_iterator!(f64);
149impl_stats_iterator!(f32);