radiate_core/stats/
statistics.rs

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