math/
mean.rs

1//! Functions for calculating mean
2use std::f64::NAN;
3
4/// Calculates arithmetic mean (AM) of data set `slice`.
5///
6/// # Arguments
7///
8/// * `slice` - collection of values
9///
10/// # Example
11///
12/// ```
13/// use math::mean;
14///
15/// let slice = [8., 16.];
16/// assert_eq!(mean::arithmetic(&slice), 12.);
17/// ```
18pub fn arithmetic(slice: &[f64]) -> f64 {
19	slice.iter().fold(0., |a, b| a + b) / slice.len() as f64
20}
21
22/// Calculate geometric mean (GM) of data set `slice`.
23///
24/// If the result would be imaginary, function returns `NAN`.
25///
26/// # Arguments
27///
28/// * `slice` - collection of values
29///
30/// # Example
31///
32/// ```
33/// use math::mean;
34///
35/// let slice = [9., 16.];
36/// assert_eq!(mean::geometric(&slice), 12.);
37/// ```
38pub fn geometric(slice: &[f64]) -> f64 {
39	let product = slice.iter().fold(1., |a, b| a * b);
40	match product < 0. {
41		true => NAN,
42		false => product.powf(1. / slice.len() as f64),
43	}
44}
45
46/// Calculate harmonic mean (HM) of data set `slice`.
47///
48/// # Arguments
49///
50/// * `slice` - collection of values
51///
52/// # Example
53///
54/// ```
55/// use math::mean;
56///
57/// let slice = [1., 7.];
58/// assert_eq!(mean::harmonic(&slice), 1.75);
59/// ```
60pub fn harmonic(slice: &[f64]) -> f64 {
61	slice.len() as f64 / slice.iter().fold(0., |a, b| a + 1. / b)
62}
63
64#[cfg(test)]
65mod tests {
66	use std::f64::{ NAN, INFINITY, NEG_INFINITY };
67	use round;
68
69	macro_rules! test_mean {
70		($func:path [ $($name:ident: $params:expr,)* ]) => {
71		$(
72			#[test]
73			fn $name() {
74				let (slice, expected): (&[f64], f64) = $params;
75				let result = $func(slice);
76				match result.is_nan() {
77					true => assert_eq!(expected.is_nan(), true),
78					false => assert_eq!(round::half_up(result, 6), expected),
79				}
80			}
81		)*
82		}
83	}
84
85	test_mean! { super::arithmetic [
86		arithmetic_1: (&[-7., -4., 1., 3., 8.], 0.2),
87		arithmetic_2: (&[-4., 1., 3., 8., 12.], 4.),
88		arithmetic_3: (&[0., 0., 0., 0., 0.], 0.),
89		arithmetic_4: (&[0., 4., 7., 9., 17.], 7.4),
90		arithmetic_5: (&[1., 2., 6., 4., 13.], 5.2),
91		arithmetic_6: (&[1., 5., 10., 20., 25.], 12.2),
92		arithmetic_7: (&[2., 3., 5., 7., 11.], 5.6),
93		arithmetic_8: (&[NEG_INFINITY, 1., 2., 3., 4.], NEG_INFINITY),
94		arithmetic_9: (&[1., 2., 3., 4., INFINITY], INFINITY),
95	]}
96
97	test_mean! { super::geometric [
98		geometric_1: (&[-7., -4., 1., 3., 8.], 3.676833),
99		geometric_2: (&[-4., 1., 3., 8., 12.], NAN),
100		geometric_3: (&[0., 0., 0., 0., 0.], 0.),
101		geometric_4: (&[0., 4., 7., 9., 17.], 0.),
102		geometric_5: (&[1., 2., 6., 4., 13.], 3.622738),
103		geometric_6: (&[1., 5., 10., 20., 25.], 7.578583),
104		geometric_7: (&[2., 3., 5., 7., 11.], 4.706764),
105		geometric_8: (&[NEG_INFINITY, 1., 2., 3., 4.], NAN),
106		geometric_9: (&[1., 2., 3., 4., INFINITY], INFINITY),
107	]}
108
109	test_mean! { super::harmonic [
110		harmonic_1: (&[-7., -4., 1., 3., 8.], 4.692737),
111		harmonic_2: (&[-4., 1., 3., 8., 12.], 3.870968),
112		harmonic_3: (&[0., 0., 0., 0., 0.], 0.),
113		harmonic_4: (&[0., 4., 7., 9., 17.], 0.),
114		harmonic_5: (&[1., 2., 6., 4., 13.], 2.508039),
115		harmonic_6: (&[1., 5., 10., 20., 25.], 3.597122),
116		harmonic_7: (&[2., 3., 5., 7., 11.], 3.94602),
117		harmonic_8: (&[NEG_INFINITY, 1., 2., 3., 4.], 2.4),
118		harmonic_9: (&[1., 2., 3., 4., INFINITY], 2.4),
119	]}
120}