radiate_core/stats/
statistics.rs

1use core::f32;
2
3#[derive(PartialEq, Clone)]
4pub struct Adder {
5    compensation: f32,
6    simple_sum: f32,
7    sum: f32,
8}
9
10impl Adder {
11    pub fn value(&self) -> f32 {
12        let result = self.sum + self.compensation;
13        if result.is_nan() {
14            self.simple_sum
15        } else {
16            result
17        }
18    }
19
20    pub fn add(&mut self, value: f32) {
21        let y = value - self.compensation;
22        let t = self.sum + y;
23
24        self.compensation = (t - self.sum) - y;
25        self.sum = t;
26        self.simple_sum += value;
27    }
28}
29
30impl Default for Adder {
31    fn default() -> Self {
32        Adder {
33            compensation: 0_f32,
34            simple_sum: 0_f32,
35            sum: 0_f32,
36        }
37    }
38}
39
40#[derive(PartialEq, Clone)]
41pub struct Statistic {
42    m1: Adder,
43    m2: Adder,
44    m3: Adder,
45    m4: Adder,
46    sum: Adder,
47    count: i32,
48    last_value: f32,
49    max: f32,
50    min: f32,
51}
52
53impl Statistic {
54    pub fn new(initial_val: f32) -> Self {
55        let mut result = Statistic::default();
56        result.add(initial_val);
57        result
58    }
59
60    pub fn last_value(&self) -> f32 {
61        self.last_value
62    }
63
64    pub fn count(&self) -> i32 {
65        self.count
66    }
67
68    pub fn min(&self) -> f32 {
69        self.min
70    }
71
72    pub fn max(&self) -> f32 {
73        self.max
74    }
75
76    pub fn mean(&self) -> f32 {
77        if self.count == 0 {
78            0_f32
79        } else {
80            self.m1.value()
81        }
82    }
83
84    pub fn sum(&self) -> f32 {
85        self.sum.value()
86    }
87
88    pub fn variance(&self) -> f32 {
89        let mut value = f32::NAN;
90        if self.count == 1 {
91            value = self.m2.value();
92        } else if self.count > 1 {
93            value = self.m2.value() / (self.count - 1) as f32;
94        }
95
96        value
97    }
98
99    pub fn std_dev(&self) -> f32 {
100        self.variance().sqrt()
101    }
102
103    pub fn skewness(&self) -> f32 {
104        let mut value = f32::NAN;
105        if self.count >= 3 {
106            let temp = self.m2.value() / self.count as f32 - 1_f32;
107            if temp < 10e-10_f32 {
108                value = 0_f32;
109            } else {
110                value = self.count as f32 * self.m3.value()
111                    / ((self.count as f32 - 1_f32)
112                        * (self.count as f32 - 2_f32)
113                        * temp.sqrt()
114                        * temp)
115            }
116        }
117
118        value
119    }
120
121    pub fn kurtosis(&self) -> f32 {
122        let mut value = f32::NAN;
123        if self.count >= 4 {
124            let temp = self.m2.value() / self.count as f32 - 1_f32;
125            if temp < 10e-10_f32 {
126                value = 0_f32;
127            } else {
128                value = self.count as f32 * (self.count as f32 + 1_f32) * self.m4.value()
129                    / ((self.count as f32 - 1_f32)
130                        * (self.count as f32 - 2_f32)
131                        * (self.count as f32 - 3_f32)
132                        * temp
133                        * temp)
134            }
135        }
136
137        value
138    }
139
140    pub fn add(&mut self, value: f32) {
141        self.count += 1;
142
143        let n = self.count as f32;
144        let d = value - self.m1.value();
145        let dn = d / n;
146        let dn2 = dn * dn;
147        let t1 = d * dn * (n - 1_f32);
148
149        self.m1.add(dn);
150
151        self.m4.add(t1 * dn2 * (n * n - 3_f32 * n + 3_f32));
152        self.m4
153            .add(6_f32 * dn2 * self.m2.value() - 4_f32 * dn * self.m3.value());
154
155        self.m3
156            .add(t1 * dn * (n - 2_f32) - 3_f32 * dn * self.m2.value());
157        self.m2.add(t1);
158
159        self.last_value = value;
160        self.max = if value > self.max { value } else { self.max };
161        self.min = if value < self.min { value } else { self.min };
162        self.sum.add(value);
163    }
164
165    pub fn clear(&mut self) {
166        self.m1 = Adder::default();
167        self.m2 = Adder::default();
168        self.m3 = Adder::default();
169        self.m4 = Adder::default();
170        self.sum = Adder::default();
171        self.count = 0;
172        self.last_value = 0_f32;
173        self.max = f32::MIN;
174        self.min = f32::MAX;
175    }
176}
177
178impl Default for Statistic {
179    fn default() -> Self {
180        Statistic {
181            m1: Adder::default(),
182            m2: Adder::default(),
183            m3: Adder::default(),
184            m4: Adder::default(),
185            sum: Adder::default(),
186            count: 0,
187            last_value: 0_f32,
188            max: f32::MIN,
189            min: f32::MAX,
190        }
191    }
192}
193
194impl From<f32> for Statistic {
195    fn from(value: f32) -> Self {
196        Statistic::new(value)
197    }
198}
199
200impl From<i32> for Statistic {
201    fn from(value: i32) -> Self {
202        Statistic::new(value as f32)
203    }
204}
205
206impl From<usize> for Statistic {
207    fn from(value: usize) -> Self {
208        Statistic::new(value as f32)
209    }
210}
211
212#[cfg(test)]
213mod tests {
214    use super::*;
215
216    #[test]
217    fn test_adder() {
218        let mut adder = Adder::default();
219        adder.add(1_f32);
220        adder.add(2_f32);
221        adder.add(3_f32);
222        adder.add(4_f32);
223        adder.add(5_f32);
224
225        assert_eq!(adder.value(), 15_f32);
226    }
227
228    #[test]
229    fn test_statistic() {
230        let mut statistic = Statistic::default();
231        statistic.add(1_f32);
232        statistic.add(2_f32);
233        statistic.add(3_f32);
234        statistic.add(4_f32);
235        statistic.add(5_f32);
236
237        assert_eq!(statistic.mean(), 3_f32);
238        assert_eq!(statistic.variance(), 2.5_f32);
239        assert_eq!(statistic.std_dev(), 1.5811388_f32);
240        assert_eq!(statistic.skewness(), 0_f32);
241    }
242}