1use num_traits::ToPrimitive;
38use std::{
39 cell::RefCell,
40 collections::HashMap,
41 fmt::Display,
42 marker::PhantomData,
43 ops::{AddAssign, Deref},
44};
45
46use ordered_float::OrderedFloat;
47
48#[derive(Debug, Clone)]
49pub struct Value(f64);
50
51impl Deref for Value {
52 type Target = f64;
53
54 fn deref(&self) -> &Self::Target {
55 &self.0
56 }
57}
58
59impl Display for Value {
60 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61 write!(f, "{}", self.0)
62 }
63}
64
65macro_rules! impl_partial_eq {
66 ($($ty:ty), *) => {
67 $(
68 impl PartialEq<$ty> for Value {
69 fn eq(&self, other: &$ty) -> bool {
70 self.0 == *other as f64
71 }
72 }
73 )*
74 };
75 () => {
76
77 };
78}
79
80impl_partial_eq!(usize, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64);
81
82macro_rules! utilities {
83 ($($ty:ty),*) => {
84 $(
85 impl AddAssign<$ty> for Moving<$ty> {
86 fn add_assign(&mut self, other: $ty) {
87 let _ = self.add(other);
88 }
89 }
90
91 impl PartialEq<$ty> for Moving<$ty> {
92 fn eq(&self, other: &$ty) -> bool {
93 self.mean() == *other as f64
94 }
95 }
96
97 impl PartialOrd<$ty> for Moving<$ty> {
98 fn partial_cmp(&self, other: &$ty) -> Option<std::cmp::Ordering> {
99 self.mean().partial_cmp(&(*other as f64))
100 }
101 }
102
103 impl PartialEq<Moving<$ty>> for $ty {
104 fn eq(&self, other: &Moving<$ty>) -> bool {
105 *self as f64 == other.mean()
106 }
107 }
108
109 impl PartialOrd<Moving<$ty>> for $ty {
110 fn partial_cmp(&self, other: &Moving<$ty>) -> Option<std::cmp::Ordering> {
111 (*self as f64).partial_cmp(&other.mean())
112 }
113 }
114 )*
115 };
116}
117
118macro_rules! partial_non {
119 ($($ty:ty), *) => {
120 $(
121 impl PartialEq<f32> for Moving<$ty> {
122 fn eq(&self, other: &f32) -> bool {
123 self.mean() == *other as f64
124 }
125 }
126
127 impl PartialEq<f64> for Moving<$ty> {
128 fn eq(&self, other: &f64) -> bool {
129 self.mean() == *other
130 }
131 }
132 )*
133
134 };
135}
136
137macro_rules! signed {
138 ($($ty:ty), *) => {
139 $(
140 impl Sign for $ty {
141 fn signed() -> bool {
142 true
143 }
144 }
145 )*
146 };
147}
148macro_rules! unsigned {
149 ($($ty:ty), *) => {
150 $(
151 impl Sign for $ty {
152 fn signed() -> bool {
153 false
154 }
155 }
156 )*
157 };
158}
159
160utilities!(usize, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64);
161partial_non!(usize, i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
162signed!(i8, i16, i32, i64, i128, f32, f64);
163unsigned!(usize, u8, u16, u32, u64, u128);
164
165pub trait Sign {
166 fn signed() -> bool;
167}
168
169#[derive(Debug, PartialEq, Eq, Clone, Copy)]
170pub enum MovingError {
172 NegativeValueToUnsignedType,
174
175 Overflow,
178
179 Underflow,
181
182 CountOverflow,
184
185 ThresholdReached,
192}
193
194#[derive(Debug, Default)]
223pub struct Moving<T> {
224 count: RefCell<usize>,
225 mean: RefCell<f64>,
226 mode: RefCell<HashMap<OrderedFloat<f64>, usize>>,
227 threshold: f64,
228 phantom: std::marker::PhantomData<T>,
229}
230
231impl<T> Moving<T>
232where
233 T: Sign + ToPrimitive,
234{
235 pub fn new() -> Self {
242 Self {
243 count: RefCell::new(0),
244 mean: RefCell::new(0.0),
245 mode: RefCell::new(HashMap::new()),
246 threshold: f64::MAX,
247 phantom: PhantomData,
248 }
249 }
250
251 pub fn new_with_threshold(threshold: f64) -> Self {
266 Self {
267 count: RefCell::new(0),
268 mean: RefCell::new(0.0),
269 mode: RefCell::new(HashMap::new()),
270 threshold,
271 phantom: PhantomData,
272 }
273 }
274 pub fn add_with_result(&self, value: T) -> Result<f64, MovingError> {
288 let value_f64: f64 = value.to_f64().unwrap();
289 if !T::signed() && value_f64 < 0.0 {
290 return Err(MovingError::NegativeValueToUnsignedType);
291 }
292 let mut count = self.count.borrow_mut();
293 let mut mean = self.mean.borrow_mut();
294 let mut mode = self.mode.borrow_mut();
295 mode.entry(OrderedFloat(value_f64))
296 .and_modify(|e| *e += 1)
297 .or_insert(1);
298
299 *count += 1;
300 *mean += (value_f64 - *mean) / *count as f64;
301
302 if *mean >= self.threshold {
303 return Err(MovingError::ThresholdReached);
304 }
305
306 Ok(*mean)
307 }
308
309 pub fn add(&self, value: T) {
313 let _ = self.add_with_result(value);
314 }
315
316 pub fn mean(&self) -> f64 {
318 *self.mean.borrow()
319 }
320
321 pub fn mode(&self) -> f64 {
361 let mode_map = self.mode.borrow();
362 if mode_map.is_empty() {
363 return 0.0;
364 }
365 let max_count = match mode_map.values().max() {
367 Some(&max) if max > 1 => max,
368 _ => return self.mean(),
370 };
371 let modes: Vec<_> = mode_map
373 .iter()
374 .filter(|&(_, &count)| count == max_count)
375 .collect();
376 if modes.len() != 1 {
378 let mean = self.mean();
379 let closest = modes
380 .iter()
381 .min_by_key(|&&(value, _)| (value.0 - mean).abs() as i64)
382 .unwrap();
383 return closest.0.into_inner();
384 }
385 modes[0].0.into_inner()
387 }
388
389 pub fn count(&self) -> usize {
403 *self.count.borrow()
404 }
405}
406
407impl<T> std::fmt::Display for Moving<T> {
408 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409 write!(f, "{}", self.mean.borrow())
410 }
411}
412
413impl<T> PartialEq for Moving<T> {
414 fn eq(&self, other: &Self) -> bool {
415 *self.mean.borrow() == *other.mean.borrow()
416 }
417}
418
419impl<T> PartialOrd for Moving<T> {
420 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
421 self.mean.borrow().partial_cmp(&*other.mean.borrow())
422 }
423}
424
425impl std::fmt::Display for MovingError {
426 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427 write!(f, "{:?}", self)
428 }
429}
430
431#[cfg(test)]
432mod tests {
433 use crate::Moving;
434
435 #[test]
436 fn mode() {
437 let moving = Moving::new();
438 moving.add(10);
439 moving.add(20);
440 moving.add(10);
441 assert_eq!(moving.mode(), 10.0);
442 }
443
444 #[test]
445 fn big_mode() {
446 let moving = Moving::new();
447 for i in 0..10000 {
448 moving.add(i);
449 }
450 assert_eq!(moving.mode(), moving.mean());
451 moving.add(9999);
452 assert_eq!(moving.mode(), 9999.0);
453 }
454
455 #[test]
456 fn double_mode() {
457 let moving = Moving::new();
458 moving.add(10);
459 moving.add(20);
460 moving.add(10);
461 moving.add(20);
462 moving.add(1);
463 assert_eq!(moving.mode(), 10.0);
464 moving.add(3000);
465 assert_eq!(moving.mode(), 20.0);
466 }
467
468 #[test]
469 fn partial_order() {
470 let m1 = Moving::new();
471 let m2 = Moving::new();
472 m1.add(10);
473 m2.add(20);
474 assert!(m1 < m2);
475 }
476
477 #[test]
478 fn thresholds() {
479 let moving_threshold = Moving::new_with_threshold(10.0);
480 let result = moving_threshold.add_with_result(9);
481 assert_eq!(result.unwrap(), 9.0);
482 let result = moving_threshold.add_with_result(15);
483 assert!(result.is_err(), "{:?}", result);
484 assert_eq!(result.unwrap_err(), crate::MovingError::ThresholdReached);
485 }
486
487 #[test]
488 fn never_overflow() {
489 let moving_average: Moving<usize> = Moving::new();
490 let result = moving_average.add_with_result(usize::MAX);
491 assert!(result.is_ok());
492 assert_eq!(result.unwrap(), usize::MAX as f64);
493 let result = moving_average.add_with_result(usize::MAX);
494 assert!(result.is_ok());
495
496 assert_eq!(result.unwrap(), usize::MAX as f64);
497 }
498
499 #[test]
500 fn add_moving_average() {
501 let moving_average: Moving<usize> = Moving::new();
502 moving_average.add(10);
503 assert_eq!(moving_average, 10);
504 moving_average.add(20);
505 assert_eq!(moving_average, 15);
506 }
507
508 #[test]
509 fn float_moving_average() {
510 let moving_average: Moving<f32> = Moving::new();
511 moving_average.add(10.0);
512 moving_average.add(20.0);
513 assert_eq!(moving_average, 15.0);
514 }
515
516 #[test]
517 fn assign_add() {
518 let mut moving_average: Moving<usize> = Moving::new();
519 moving_average.add(10);
520 moving_average += 20;
521 assert_eq!(moving_average, 15);
522 }
523
524 #[test]
525 fn assign_add_float() {
526 let mut moving_average: Moving<f32> = Moving::new();
527 moving_average.add(10.0);
528 moving_average += 20.0;
529 assert_eq!(moving_average, 15.0);
530 }
531
532 #[test]
533 fn assign_add_i64() {
534 let mut moving_average: Moving<i64> = Moving::new();
535 moving_average.add(10);
536 moving_average += 20;
537 assert_eq!(moving_average, 15);
538 }
539 #[test]
540 fn default_works() {
541 let moving_average: Moving<usize> = Default::default();
542 assert_eq!(moving_average, 0);
543 let moving_average: Moving<f32> = Default::default();
544 assert_eq!(moving_average, 0.0);
545 }
546
547 #[test]
548 fn binary_operations() {
549 let moving_average: Moving<usize> = Moving::new();
550 moving_average.add(10);
551 moving_average.add(20);
552 assert!(moving_average < usize::MAX)
553 }
554
555 #[test]
556 fn binary_operations_float() {
557 let moving_average: Moving<f32> = Moving::new();
558 moving_average.add(10.0);
559 moving_average.add(20.0);
560 assert!(moving_average < f32::MAX)
561 }
562
563 #[test]
564 fn many_operations() {
565 let moving_average: Moving<_> = Moving::new();
566 for i in 0..1000 {
567 moving_average.add(i);
568 }
569 assert_eq!(moving_average, 999.0 / 2.0);
570 }
571}