reductor/reductors/
mean.rs1use super::state::NonEmptyState;
2use crate::Reductor;
3
4#[repr(transparent)]
23#[allow(clippy::derive_partial_eq_without_eq)] #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
25pub struct Mean<F>(pub F);
26
27macro_rules! impl_mean {
28 ($f:ty) => {
29 impl<T> Reductor<T> for Mean<$f>
30 where
31 T: Into<$f>,
32 {
33 type State = NonEmptyState<($f, usize)>;
34
35 #[inline]
36 fn new(item: T) -> Self::State {
37 NonEmptyState((item.into(), 1))
38 }
39
40 #[inline]
41 fn reduce(NonEmptyState((mean, count)): Self::State, item: T) -> Self::State {
42 NonEmptyState((
43 mean.mul_add(count as $f, item.into()) / (count + 1) as $f,
44 count + 1,
45 ))
46 }
47
48 #[inline]
49 fn into_result(NonEmptyState((mean, _)): Self::State) -> Self {
50 Self(mean)
51 }
52 }
53 };
54}
55
56impl_mean!(f32);
57impl_mean!(f64);
58
59#[cfg(test)]
60mod tests {
61 use crate::Reduce;
62
63 use super::*;
64
65 #[test]
66 fn test_mean() {
67 macro_rules! test {
68 ($f:ty) => {
69 let Mean::<$f>(mean) = [0.48, 3., 2.64]
70 .into_iter()
71 .reduce_with::<Option<_>>()
72 .unwrap();
73 assert!((mean - 2.04).abs() < <$f>::EPSILON);
74 };
75 }
76
77 test!(f32);
78 test!(f64);
79 }
80}