1use crate::Iterstats;
4
5pub trait StdDev<A = Self>: Sized {
7 type Output;
9
10 fn stddev<I>(iter: I) -> Self::Output
12 where
13 I: Iterator<Item = A>;
14}
15
16macro_rules! stddev_impl {
17 ($typ:ty) => {
18 impl StdDev for $typ {
19 type Output = $typ;
20
21 fn stddev<I>(iter: I) -> Self::Output
22 where
23 I: Iterator<Item = Self>,
24 {
25 let var = iter.variance();
26 var.sqrt()
27 }
28 }
29
30 impl StdDev for &$typ {
31 type Output = $typ;
32
33 fn stddev<I>(iter: I) -> Self::Output
34 where
35 I: Iterator<Item = Self>,
36 {
37 iter.map(|i| *i).stddev()
38 }
39 }
40 };
41}
42
43stddev_impl!(f64);
44stddev_impl!(f32);
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use paste::paste;
50
51 macro_rules! test_stddev {
52 ( $name:ident: $iterty:ty as $iter:expr ; into_iter => nan) => {
53 paste! {
54 #[test]
55 fn [<$name _into_iter >]() {
56 let stddev = <$iterty>::stddev($iter.into_iter());
57 assert!(stddev.is_nan());
58 }
59 }
60 };
61 ( $name:ident: $iterty:ty as $iter:expr ; iter => nan) => {
62 paste! {
63 #[test]
64 fn [<$name _iter >]() {
65 let stddev = <&$iterty>::stddev($iter.iter());
66 assert!(stddev.is_nan());
67 }
68 }
69 };
70 ( $name:ident: $iterty:ty as $iter:expr => nan) => {
71 test_stddev!($name: $iterty as $iter; into_iter => nan);
72 test_stddev!($name: $iterty as $iter; iter => nan);
73 };
74 ( $name:ident: $iterty:ty as $iter:expr ; into_iter => $expected:expr) => {
75 paste! {
76 #[test]
77 fn [<$name _into_iter >]() {
78 let stddev = <$iterty>::stddev($iter.into_iter());
79 assert_eq!(stddev, $expected);
80 }
81 }
82 };
83 ( $name:ident: $iterty:ty as $iter:expr ; iter => $expected:expr) => {
84 paste! {
85 #[test]
86 fn [<$name _iter >]() {
87 let stddev = <&$iterty>::stddev($iter.iter());
88 assert_eq!(stddev, $expected);
89 }
90 }
91 };
92 ( $name:ident: $iterty:ty as $iter:expr => $expected:expr) => {
93 test_stddev!($name: $iterty as $iter; into_iter => $expected);
94 test_stddev!($name: $iterty as $iter; iter => $expected);
95 };
96 }
97
98 test_stddev!(f64: f64 as [1.0, 2.0, 3.0, 4.0] => 1.25f64.sqrt());
99 test_stddev!(f64_max: f64 as [f64::MAX, f64::MAX] => 0.0);
100 test_stddev!(f64_min: f64 as [f64::MIN, f64::MIN] => 0.0);
101 test_stddev!(f64_minmax: f64 as [f64::MAX, f64::MIN] => nan);
102 test_stddev!(f64_nan: f64 as [1.0, 2.0, f64::NAN, 3.0, 4.0] => nan);
103 test_stddev!(f64_inf: f64 as [1.0, 2.0, f64::INFINITY, 3.0, 4.0] => nan);
104 test_stddev!(f64_neg_inf: f64 as [1.0, 2.0, f64::NEG_INFINITY, 3.0, 4.0] => nan);
105 test_stddev!(f32: f32 as [1.0, 2.0, 3.0, 4.0] => 1.25f32.sqrt());
106 test_stddev!(f32_max: f32 as [f32::MAX, f32::MAX] => 0.0);
107 test_stddev!(f32_min: f32 as [f32::MIN, f32::MIN] => 0.0);
108 test_stddev!(f32_minmax: f32 as [f32::MAX, f32::MIN] => nan);
109 test_stddev!(f32_nan: f32 as [1.0, 2.0, f32::NAN, 3.0, 4.0] => nan);
110 test_stddev!(f32_inf: f32 as [1.0, 2.0, f32::INFINITY, 3.0, 4.0] => nan);
111 test_stddev!(f32_neg_inf: f32 as [1.0, 2.0, f32::NEG_INFINITY, 3.0, 4.0] => nan);
112}