]>
Commit | Line | Data |
---|---|---|
1a4d82fc | 1 | #![allow(missing_docs)] |
c34b1796 | 2 | #![allow(deprecated)] // Float |
1a4d82fc | 3 | |
3157f602 | 4 | use std::cmp::Ordering::{self, Equal, Greater, Less}; |
1a4d82fc | 5 | use std::mem; |
1a4d82fc | 6 | |
9346a6ac | 7 | fn local_cmp(x: f64, y: f64) -> Ordering { |
1a4d82fc JJ |
8 | // arbitrarily decide that NaNs are larger than everything. |
9 | if y.is_nan() { | |
10 | Less | |
11 | } else if x.is_nan() { | |
12 | Greater | |
13 | } else if x < y { | |
14 | Less | |
15 | } else if x == y { | |
16 | Equal | |
17 | } else { | |
18 | Greater | |
19 | } | |
20 | } | |
21 | ||
9346a6ac AL |
22 | fn local_sort(v: &mut [f64]) { |
23 | v.sort_by(|x: &f64, y: &f64| local_cmp(*x, *y)); | |
1a4d82fc JJ |
24 | } |
25 | ||
26 | /// Trait that provides simple descriptive statistics on a univariate set of numeric samples. | |
9346a6ac | 27 | pub trait Stats { |
1a4d82fc JJ |
28 | /// Sum of the samples. |
29 | /// | |
30 | /// Note: this method sacrifices performance at the altar of accuracy | |
31 | /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at: | |
cc61c64b XL |
32 | /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric |
33 | /// Predicates"][paper] | |
34 | /// | |
35 | /// [paper]: http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps | |
9346a6ac | 36 | fn sum(&self) -> f64; |
1a4d82fc JJ |
37 | |
38 | /// Minimum value of the samples. | |
9346a6ac | 39 | fn min(&self) -> f64; |
1a4d82fc JJ |
40 | |
41 | /// Maximum value of the samples. | |
9346a6ac | 42 | fn max(&self) -> f64; |
1a4d82fc JJ |
43 | |
44 | /// Arithmetic mean (average) of the samples: sum divided by sample-count. | |
45 | /// | |
ff7c6d11 | 46 | /// See: <https://en.wikipedia.org/wiki/Arithmetic_mean> |
9346a6ac | 47 | fn mean(&self) -> f64; |
1a4d82fc JJ |
48 | |
49 | /// Median of the samples: value separating the lower half of the samples from the higher half. | |
50 | /// Equal to `self.percentile(50.0)`. | |
51 | /// | |
ff7c6d11 | 52 | /// See: <https://en.wikipedia.org/wiki/Median> |
9346a6ac | 53 | fn median(&self) -> f64; |
1a4d82fc JJ |
54 | |
55 | /// Variance of the samples: bias-corrected mean of the squares of the differences of each | |
56 | /// sample from the sample mean. Note that this calculates the _sample variance_ rather than the | |
57 | /// population variance, which is assumed to be unknown. It therefore corrects the `(n-1)/n` | |
58 | /// bias that would appear if we calculated a population variance, by dividing by `(n-1)` rather | |
59 | /// than `n`. | |
60 | /// | |
ff7c6d11 | 61 | /// See: <https://en.wikipedia.org/wiki/Variance> |
9346a6ac | 62 | fn var(&self) -> f64; |
1a4d82fc JJ |
63 | |
64 | /// Standard deviation: the square root of the sample variance. | |
65 | /// | |
66 | /// Note: this is not a robust statistic for non-normal distributions. Prefer the | |
67 | /// `median_abs_dev` for unknown distributions. | |
68 | /// | |
ff7c6d11 | 69 | /// See: <https://en.wikipedia.org/wiki/Standard_deviation> |
9346a6ac | 70 | fn std_dev(&self) -> f64; |
1a4d82fc JJ |
71 | |
72 | /// Standard deviation as a percent of the mean value. See `std_dev` and `mean`. | |
73 | /// | |
74 | /// Note: this is not a robust statistic for non-normal distributions. Prefer the | |
75 | /// `median_abs_dev_pct` for unknown distributions. | |
9346a6ac | 76 | fn std_dev_pct(&self) -> f64; |
1a4d82fc JJ |
77 | |
78 | /// Scaled median of the absolute deviations of each sample from the sample median. This is a | |
79 | /// robust (distribution-agnostic) estimator of sample variability. Use this in preference to | |
80 | /// `std_dev` if you cannot assume your sample is normally distributed. Note that this is scaled | |
81 | /// by the constant `1.4826` to allow its use as a consistent estimator for the standard | |
82 | /// deviation. | |
83 | /// | |
ff7c6d11 | 84 | /// See: <http://en.wikipedia.org/wiki/Median_absolute_deviation> |
9346a6ac | 85 | fn median_abs_dev(&self) -> f64; |
1a4d82fc JJ |
86 | |
87 | /// Median absolute deviation as a percent of the median. See `median_abs_dev` and `median`. | |
9346a6ac | 88 | fn median_abs_dev_pct(&self) -> f64; |
1a4d82fc JJ |
89 | |
90 | /// Percentile: the value below which `pct` percent of the values in `self` fall. For example, | |
91 | /// percentile(95.0) will return the value `v` such that 95% of the samples `s` in `self` | |
92 | /// satisfy `s <= v`. | |
93 | /// | |
94 | /// Calculated by linear interpolation between closest ranks. | |
95 | /// | |
ff7c6d11 | 96 | /// See: <http://en.wikipedia.org/wiki/Percentile> |
9346a6ac | 97 | fn percentile(&self, pct: f64) -> f64; |
1a4d82fc JJ |
98 | |
99 | /// Quartiles of the sample: three values that divide the sample into four equal groups, each | |
100 | /// with 1/4 of the data. The middle value is the median. See `median` and `percentile`. This | |
101 | /// function may calculate the 3 quartiles more efficiently than 3 calls to `percentile`, but | |
102 | /// is otherwise equivalent. | |
103 | /// | |
ff7c6d11 | 104 | /// See also: <https://en.wikipedia.org/wiki/Quartile> |
9cc50fc6 | 105 | fn quartiles(&self) -> (f64, f64, f64); |
1a4d82fc JJ |
106 | |
107 | /// Inter-quartile range: the difference between the 25th percentile (1st quartile) and the 75th | |
108 | /// percentile (3rd quartile). See `quartiles`. | |
109 | /// | |
ff7c6d11 | 110 | /// See also: <https://en.wikipedia.org/wiki/Interquartile_range> |
9346a6ac | 111 | fn iqr(&self) -> f64; |
1a4d82fc JJ |
112 | } |
113 | ||
114 | /// Extracted collection of all the summary statistics of a sample set. | |
32a655c1 | 115 | #[derive(Clone, PartialEq, Copy)] |
1a4d82fc | 116 | #[allow(missing_docs)] |
9346a6ac AL |
117 | pub struct Summary { |
118 | pub sum: f64, | |
119 | pub min: f64, | |
120 | pub max: f64, | |
121 | pub mean: f64, | |
122 | pub median: f64, | |
123 | pub var: f64, | |
124 | pub std_dev: f64, | |
125 | pub std_dev_pct: f64, | |
126 | pub median_abs_dev: f64, | |
127 | pub median_abs_dev_pct: f64, | |
9cc50fc6 | 128 | pub quartiles: (f64, f64, f64), |
9346a6ac | 129 | pub iqr: f64, |
1a4d82fc JJ |
130 | } |
131 | ||
9346a6ac | 132 | impl Summary { |
1a4d82fc | 133 | /// Construct a new summary of a sample set. |
9346a6ac | 134 | pub fn new(samples: &[f64]) -> Summary { |
1a4d82fc JJ |
135 | Summary { |
136 | sum: samples.sum(), | |
137 | min: samples.min(), | |
138 | max: samples.max(), | |
139 | mean: samples.mean(), | |
140 | median: samples.median(), | |
141 | var: samples.var(), | |
142 | std_dev: samples.std_dev(), | |
143 | std_dev_pct: samples.std_dev_pct(), | |
144 | median_abs_dev: samples.median_abs_dev(), | |
145 | median_abs_dev_pct: samples.median_abs_dev_pct(), | |
146 | quartiles: samples.quartiles(), | |
9cc50fc6 | 147 | iqr: samples.iqr(), |
1a4d82fc JJ |
148 | } |
149 | } | |
150 | } | |
151 | ||
9346a6ac | 152 | impl Stats for [f64] { |
1a4d82fc | 153 | // FIXME #11059 handle NaN, inf and overflow |
9346a6ac | 154 | fn sum(&self) -> f64 { |
1a4d82fc JJ |
155 | let mut partials = vec![]; |
156 | ||
85aaf69f | 157 | for &x in self { |
1a4d82fc JJ |
158 | let mut x = x; |
159 | let mut j = 0; | |
160 | // This inner loop applies `hi`/`lo` summation to each | |
161 | // partial so that the list of partial sums remains exact. | |
85aaf69f | 162 | for i in 0..partials.len() { |
9346a6ac | 163 | let mut y: f64 = partials[i]; |
1a4d82fc JJ |
164 | if x.abs() < y.abs() { |
165 | mem::swap(&mut x, &mut y); | |
166 | } | |
167 | // Rounded `x+y` is stored in `hi` with round-off stored in | |
168 | // `lo`. Together `hi+lo` are exactly equal to `x+y`. | |
169 | let hi = x + y; | |
170 | let lo = y - (hi - x); | |
9346a6ac | 171 | if lo != 0.0 { |
1a4d82fc JJ |
172 | partials[j] = lo; |
173 | j += 1; | |
174 | } | |
175 | x = hi; | |
176 | } | |
177 | if j >= partials.len() { | |
178 | partials.push(x); | |
179 | } else { | |
180 | partials[j] = x; | |
9cc50fc6 | 181 | partials.truncate(j + 1); |
1a4d82fc JJ |
182 | } |
183 | } | |
9346a6ac | 184 | let zero: f64 = 0.0; |
1a4d82fc JJ |
185 | partials.iter().fold(zero, |p, q| p + *q) |
186 | } | |
187 | ||
9346a6ac AL |
188 | fn min(&self) -> f64 { |
189 | assert!(!self.is_empty()); | |
1a4d82fc JJ |
190 | self.iter().fold(self[0], |p, q| p.min(*q)) |
191 | } | |
192 | ||
9346a6ac AL |
193 | fn max(&self) -> f64 { |
194 | assert!(!self.is_empty()); | |
1a4d82fc JJ |
195 | self.iter().fold(self[0], |p, q| p.max(*q)) |
196 | } | |
197 | ||
9346a6ac AL |
198 | fn mean(&self) -> f64 { |
199 | assert!(!self.is_empty()); | |
200 | self.sum() / (self.len() as f64) | |
1a4d82fc JJ |
201 | } |
202 | ||
9346a6ac AL |
203 | fn median(&self) -> f64 { |
204 | self.percentile(50 as f64) | |
1a4d82fc JJ |
205 | } |
206 | ||
9346a6ac | 207 | fn var(&self) -> f64 { |
1a4d82fc | 208 | if self.len() < 2 { |
9346a6ac | 209 | 0.0 |
1a4d82fc JJ |
210 | } else { |
211 | let mean = self.mean(); | |
9346a6ac | 212 | let mut v: f64 = 0.0; |
85aaf69f | 213 | for s in self { |
1a4d82fc | 214 | let x = *s - mean; |
9cc50fc6 | 215 | v = v + x * x; |
1a4d82fc | 216 | } |
0731742a | 217 | // N.B., this is _supposed to be_ len-1, not len. If you |
1a4d82fc JJ |
218 | // change it back to len, you will be calculating a |
219 | // population variance, not a sample variance. | |
9346a6ac | 220 | let denom = (self.len() - 1) as f64; |
9cc50fc6 | 221 | v / denom |
1a4d82fc JJ |
222 | } |
223 | } | |
224 | ||
9346a6ac | 225 | fn std_dev(&self) -> f64 { |
1a4d82fc JJ |
226 | self.var().sqrt() |
227 | } | |
228 | ||
9346a6ac AL |
229 | fn std_dev_pct(&self) -> f64 { |
230 | let hundred = 100 as f64; | |
1a4d82fc JJ |
231 | (self.std_dev() / self.mean()) * hundred |
232 | } | |
233 | ||
9346a6ac | 234 | fn median_abs_dev(&self) -> f64 { |
1a4d82fc | 235 | let med = self.median(); |
9346a6ac | 236 | let abs_devs: Vec<f64> = self.iter().map(|&v| (med - v).abs()).collect(); |
1a4d82fc JJ |
237 | // This constant is derived by smarter statistics brains than me, but it is |
238 | // consistent with how R and other packages treat the MAD. | |
9346a6ac | 239 | let number = 1.4826; |
1a4d82fc JJ |
240 | abs_devs.median() * number |
241 | } | |
242 | ||
9346a6ac AL |
243 | fn median_abs_dev_pct(&self) -> f64 { |
244 | let hundred = 100 as f64; | |
1a4d82fc JJ |
245 | (self.median_abs_dev() / self.median()) * hundred |
246 | } | |
247 | ||
9346a6ac | 248 | fn percentile(&self, pct: f64) -> f64 { |
1a4d82fc | 249 | let mut tmp = self.to_vec(); |
85aaf69f SL |
250 | local_sort(&mut tmp); |
251 | percentile_of_sorted(&tmp, pct) | |
1a4d82fc JJ |
252 | } |
253 | ||
9cc50fc6 | 254 | fn quartiles(&self) -> (f64, f64, f64) { |
1a4d82fc | 255 | let mut tmp = self.to_vec(); |
85aaf69f | 256 | local_sort(&mut tmp); |
9346a6ac | 257 | let first = 25f64; |
85aaf69f | 258 | let a = percentile_of_sorted(&tmp, first); |
8bb4bdeb XL |
259 | let second = 50f64; |
260 | let b = percentile_of_sorted(&tmp, second); | |
9346a6ac | 261 | let third = 75f64; |
85aaf69f | 262 | let c = percentile_of_sorted(&tmp, third); |
9cc50fc6 | 263 | (a, b, c) |
1a4d82fc JJ |
264 | } |
265 | ||
9346a6ac | 266 | fn iqr(&self) -> f64 { |
9cc50fc6 | 267 | let (a, _, c) = self.quartiles(); |
1a4d82fc JJ |
268 | c - a |
269 | } | |
270 | } | |
271 | ||
1a4d82fc JJ |
272 | // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using |
273 | // linear interpolation. If samples are not sorted, return nonsensical value. | |
9346a6ac AL |
274 | fn percentile_of_sorted(sorted_samples: &[f64], pct: f64) -> f64 { |
275 | assert!(!sorted_samples.is_empty()); | |
1a4d82fc JJ |
276 | if sorted_samples.len() == 1 { |
277 | return sorted_samples[0]; | |
278 | } | |
9346a6ac | 279 | let zero: f64 = 0.0; |
1a4d82fc | 280 | assert!(zero <= pct); |
9346a6ac | 281 | let hundred = 100f64; |
1a4d82fc JJ |
282 | assert!(pct <= hundred); |
283 | if pct == hundred { | |
284 | return sorted_samples[sorted_samples.len() - 1]; | |
285 | } | |
9346a6ac | 286 | let length = (sorted_samples.len() - 1) as f64; |
1a4d82fc JJ |
287 | let rank = (pct / hundred) * length; |
288 | let lrank = rank.floor(); | |
289 | let d = rank - lrank; | |
9346a6ac | 290 | let n = lrank as usize; |
1a4d82fc | 291 | let lo = sorted_samples[n]; |
9cc50fc6 | 292 | let hi = sorted_samples[n + 1]; |
1a4d82fc JJ |
293 | lo + (hi - lo) * d |
294 | } | |
295 | ||
9346a6ac AL |
296 | /// Winsorize a set of samples, replacing values above the `100-pct` percentile |
297 | /// and below the `pct` percentile with those percentiles themselves. This is a | |
298 | /// way of minimizing the effect of outliers, at the cost of biasing the sample. | |
299 | /// It differs from trimming in that it does not change the number of samples, | |
300 | /// just changes the values of those that are outliers. | |
1a4d82fc | 301 | /// |
ff7c6d11 | 302 | /// See: <http://en.wikipedia.org/wiki/Winsorising> |
9346a6ac | 303 | pub fn winsorize(samples: &mut [f64], pct: f64) { |
1a4d82fc | 304 | let mut tmp = samples.to_vec(); |
85aaf69f SL |
305 | local_sort(&mut tmp); |
306 | let lo = percentile_of_sorted(&tmp, pct); | |
9346a6ac | 307 | let hundred = 100 as f64; |
9cc50fc6 | 308 | let hi = percentile_of_sorted(&tmp, hundred - pct); |
85aaf69f | 309 | for samp in samples { |
1a4d82fc JJ |
310 | if *samp > hi { |
311 | *samp = hi | |
312 | } else if *samp < lo { | |
313 | *samp = lo | |
314 | } | |
315 | } | |
316 | } | |
317 | ||
1a4d82fc JJ |
318 | // Test vectors generated from R, using the script src/etc/stat-test-vectors.r. |
319 | ||
320 | #[cfg(test)] | |
321 | mod tests { | |
322 | use stats::Stats; | |
323 | use stats::Summary; | |
1a4d82fc | 324 | use std::f64; |
9346a6ac AL |
325 | use std::io::prelude::*; |
326 | use std::io; | |
1a4d82fc JJ |
327 | |
328 | macro_rules! assert_approx_eq { | |
0531ce1d | 329 | ($a: expr, $b: expr) => {{ |
1a4d82fc | 330 | let (a, b) = (&$a, &$b); |
0531ce1d XL |
331 | assert!( |
332 | (*a - *b).abs() < 1.0e-6, | |
333 | "{} is not approximately equal to {}", | |
334 | *a, | |
335 | *b | |
336 | ); | |
337 | }}; | |
1a4d82fc JJ |
338 | } |
339 | ||
9346a6ac | 340 | fn check(samples: &[f64], summ: &Summary) { |
1a4d82fc JJ |
341 | let summ2 = Summary::new(samples); |
342 | ||
9346a6ac | 343 | let mut w = io::sink(); |
1a4d82fc JJ |
344 | let w = &mut w; |
345 | (write!(w, "\n")).unwrap(); | |
1a4d82fc JJ |
346 | |
347 | assert_eq!(summ.sum, summ2.sum); | |
348 | assert_eq!(summ.min, summ2.min); | |
349 | assert_eq!(summ.max, summ2.max); | |
350 | assert_eq!(summ.mean, summ2.mean); | |
351 | assert_eq!(summ.median, summ2.median); | |
352 | ||
353 | // We needed a few more digits to get exact equality on these | |
354 | // but they're within float epsilon, which is 1.0e-6. | |
355 | assert_approx_eq!(summ.var, summ2.var); | |
356 | assert_approx_eq!(summ.std_dev, summ2.std_dev); | |
357 | assert_approx_eq!(summ.std_dev_pct, summ2.std_dev_pct); | |
358 | assert_approx_eq!(summ.median_abs_dev, summ2.median_abs_dev); | |
359 | assert_approx_eq!(summ.median_abs_dev_pct, summ2.median_abs_dev_pct); | |
360 | ||
361 | assert_eq!(summ.quartiles, summ2.quartiles); | |
362 | assert_eq!(summ.iqr, summ2.iqr); | |
363 | } | |
364 | ||
365 | #[test] | |
366 | fn test_min_max_nan() { | |
367 | let xs = &[1.0, 2.0, f64::NAN, 3.0, 4.0]; | |
368 | let summary = Summary::new(xs); | |
369 | assert_eq!(summary.min, 1.0); | |
370 | assert_eq!(summary.max, 4.0); | |
371 | } | |
372 | ||
373 | #[test] | |
374 | fn test_norm2() { | |
9cc50fc6 | 375 | let val = &[958.0000000000, 924.0000000000]; |
1a4d82fc JJ |
376 | let summ = &Summary { |
377 | sum: 1882.0000000000, | |
378 | min: 924.0000000000, | |
379 | max: 958.0000000000, | |
380 | mean: 941.0000000000, | |
381 | median: 941.0000000000, | |
382 | var: 578.0000000000, | |
383 | std_dev: 24.0416305603, | |
384 | std_dev_pct: 2.5549022912, | |
385 | median_abs_dev: 25.2042000000, | |
386 | median_abs_dev_pct: 2.6784484591, | |
9cc50fc6 | 387 | quartiles: (932.5000000000, 941.0000000000, 949.5000000000), |
1a4d82fc JJ |
388 | iqr: 17.0000000000, |
389 | }; | |
390 | check(val, summ); | |
391 | } | |
392 | #[test] | |
393 | fn test_norm10narrow() { | |
2c00a5a8 XL |
394 | let val = &[ |
395 | 966.0000000000, | |
396 | 985.0000000000, | |
397 | 1110.0000000000, | |
398 | 848.0000000000, | |
399 | 821.0000000000, | |
400 | 975.0000000000, | |
401 | 962.0000000000, | |
402 | 1157.0000000000, | |
403 | 1217.0000000000, | |
404 | 955.0000000000, | |
405 | ]; | |
1a4d82fc JJ |
406 | let summ = &Summary { |
407 | sum: 9996.0000000000, | |
408 | min: 821.0000000000, | |
409 | max: 1217.0000000000, | |
410 | mean: 999.6000000000, | |
411 | median: 970.5000000000, | |
412 | var: 16050.7111111111, | |
413 | std_dev: 126.6914010938, | |
414 | std_dev_pct: 12.6742097933, | |
415 | median_abs_dev: 102.2994000000, | |
416 | median_abs_dev_pct: 10.5408964451, | |
9cc50fc6 | 417 | quartiles: (956.7500000000, 970.5000000000, 1078.7500000000), |
1a4d82fc JJ |
418 | iqr: 122.0000000000, |
419 | }; | |
420 | check(val, summ); | |
421 | } | |
422 | #[test] | |
423 | fn test_norm10medium() { | |
2c00a5a8 XL |
424 | let val = &[ |
425 | 954.0000000000, | |
426 | 1064.0000000000, | |
427 | 855.0000000000, | |
428 | 1000.0000000000, | |
429 | 743.0000000000, | |
430 | 1084.0000000000, | |
431 | 704.0000000000, | |
432 | 1023.0000000000, | |
433 | 357.0000000000, | |
434 | 869.0000000000, | |
435 | ]; | |
1a4d82fc JJ |
436 | let summ = &Summary { |
437 | sum: 8653.0000000000, | |
438 | min: 357.0000000000, | |
439 | max: 1084.0000000000, | |
440 | mean: 865.3000000000, | |
441 | median: 911.5000000000, | |
442 | var: 48628.4555555556, | |
443 | std_dev: 220.5186059170, | |
444 | std_dev_pct: 25.4846418487, | |
445 | median_abs_dev: 195.7032000000, | |
446 | median_abs_dev_pct: 21.4704552935, | |
9cc50fc6 | 447 | quartiles: (771.0000000000, 911.5000000000, 1017.2500000000), |
1a4d82fc JJ |
448 | iqr: 246.2500000000, |
449 | }; | |
450 | check(val, summ); | |
451 | } | |
452 | #[test] | |
453 | fn test_norm10wide() { | |
2c00a5a8 XL |
454 | let val = &[ |
455 | 505.0000000000, | |
456 | 497.0000000000, | |
457 | 1591.0000000000, | |
458 | 887.0000000000, | |
459 | 1026.0000000000, | |
460 | 136.0000000000, | |
461 | 1580.0000000000, | |
462 | 940.0000000000, | |
463 | 754.0000000000, | |
464 | 1433.0000000000, | |
465 | ]; | |
1a4d82fc JJ |
466 | let summ = &Summary { |
467 | sum: 9349.0000000000, | |
468 | min: 136.0000000000, | |
469 | max: 1591.0000000000, | |
470 | mean: 934.9000000000, | |
471 | median: 913.5000000000, | |
472 | var: 239208.9888888889, | |
473 | std_dev: 489.0899599142, | |
474 | std_dev_pct: 52.3146817750, | |
475 | median_abs_dev: 611.5725000000, | |
476 | median_abs_dev_pct: 66.9482758621, | |
9cc50fc6 | 477 | quartiles: (567.2500000000, 913.5000000000, 1331.2500000000), |
1a4d82fc JJ |
478 | iqr: 764.0000000000, |
479 | }; | |
480 | check(val, summ); | |
481 | } | |
482 | #[test] | |
483 | fn test_norm25verynarrow() { | |
2c00a5a8 XL |
484 | let val = &[ |
485 | 991.0000000000, | |
486 | 1018.0000000000, | |
487 | 998.0000000000, | |
488 | 1013.0000000000, | |
489 | 974.0000000000, | |
490 | 1007.0000000000, | |
491 | 1014.0000000000, | |
492 | 999.0000000000, | |
493 | 1011.0000000000, | |
494 | 978.0000000000, | |
495 | 985.0000000000, | |
496 | 999.0000000000, | |
497 | 983.0000000000, | |
498 | 982.0000000000, | |
499 | 1015.0000000000, | |
500 | 1002.0000000000, | |
501 | 977.0000000000, | |
502 | 948.0000000000, | |
503 | 1040.0000000000, | |
504 | 974.0000000000, | |
505 | 996.0000000000, | |
506 | 989.0000000000, | |
507 | 1015.0000000000, | |
508 | 994.0000000000, | |
509 | 1024.0000000000, | |
510 | ]; | |
1a4d82fc JJ |
511 | let summ = &Summary { |
512 | sum: 24926.0000000000, | |
513 | min: 948.0000000000, | |
514 | max: 1040.0000000000, | |
515 | mean: 997.0400000000, | |
516 | median: 998.0000000000, | |
517 | var: 393.2066666667, | |
518 | std_dev: 19.8294393937, | |
519 | std_dev_pct: 1.9888308788, | |
520 | median_abs_dev: 22.2390000000, | |
521 | median_abs_dev_pct: 2.2283567134, | |
9cc50fc6 | 522 | quartiles: (983.0000000000, 998.0000000000, 1013.0000000000), |
1a4d82fc JJ |
523 | iqr: 30.0000000000, |
524 | }; | |
525 | check(val, summ); | |
526 | } | |
527 | #[test] | |
528 | fn test_exp10a() { | |
2c00a5a8 XL |
529 | let val = &[ |
530 | 23.0000000000, | |
531 | 11.0000000000, | |
532 | 2.0000000000, | |
533 | 57.0000000000, | |
534 | 4.0000000000, | |
535 | 12.0000000000, | |
536 | 5.0000000000, | |
537 | 29.0000000000, | |
538 | 3.0000000000, | |
539 | 21.0000000000, | |
540 | ]; | |
1a4d82fc JJ |
541 | let summ = &Summary { |
542 | sum: 167.0000000000, | |
543 | min: 2.0000000000, | |
544 | max: 57.0000000000, | |
545 | mean: 16.7000000000, | |
546 | median: 11.5000000000, | |
547 | var: 287.7888888889, | |
548 | std_dev: 16.9643416875, | |
549 | std_dev_pct: 101.5828843560, | |
550 | median_abs_dev: 13.3434000000, | |
551 | median_abs_dev_pct: 116.0295652174, | |
9cc50fc6 | 552 | quartiles: (4.2500000000, 11.5000000000, 22.5000000000), |
1a4d82fc JJ |
553 | iqr: 18.2500000000, |
554 | }; | |
555 | check(val, summ); | |
556 | } | |
557 | #[test] | |
558 | fn test_exp10b() { | |
2c00a5a8 XL |
559 | let val = &[ |
560 | 24.0000000000, | |
561 | 17.0000000000, | |
562 | 6.0000000000, | |
563 | 38.0000000000, | |
564 | 25.0000000000, | |
565 | 7.0000000000, | |
566 | 51.0000000000, | |
567 | 2.0000000000, | |
568 | 61.0000000000, | |
569 | 32.0000000000, | |
570 | ]; | |
1a4d82fc JJ |
571 | let summ = &Summary { |
572 | sum: 263.0000000000, | |
573 | min: 2.0000000000, | |
574 | max: 61.0000000000, | |
575 | mean: 26.3000000000, | |
576 | median: 24.5000000000, | |
577 | var: 383.5666666667, | |
578 | std_dev: 19.5848580967, | |
579 | std_dev_pct: 74.4671410520, | |
580 | median_abs_dev: 22.9803000000, | |
581 | median_abs_dev_pct: 93.7971428571, | |
9cc50fc6 | 582 | quartiles: (9.5000000000, 24.5000000000, 36.5000000000), |
1a4d82fc JJ |
583 | iqr: 27.0000000000, |
584 | }; | |
585 | check(val, summ); | |
586 | } | |
587 | #[test] | |
588 | fn test_exp10c() { | |
2c00a5a8 XL |
589 | let val = &[ |
590 | 71.0000000000, | |
591 | 2.0000000000, | |
592 | 32.0000000000, | |
593 | 1.0000000000, | |
594 | 6.0000000000, | |
595 | 28.0000000000, | |
596 | 13.0000000000, | |
597 | 37.0000000000, | |
598 | 16.0000000000, | |
599 | 36.0000000000, | |
600 | ]; | |
1a4d82fc JJ |
601 | let summ = &Summary { |
602 | sum: 242.0000000000, | |
603 | min: 1.0000000000, | |
604 | max: 71.0000000000, | |
605 | mean: 24.2000000000, | |
606 | median: 22.0000000000, | |
607 | var: 458.1777777778, | |
608 | std_dev: 21.4050876611, | |
609 | std_dev_pct: 88.4507754589, | |
610 | median_abs_dev: 21.4977000000, | |
611 | median_abs_dev_pct: 97.7168181818, | |
9cc50fc6 | 612 | quartiles: (7.7500000000, 22.0000000000, 35.0000000000), |
1a4d82fc JJ |
613 | iqr: 27.2500000000, |
614 | }; | |
615 | check(val, summ); | |
616 | } | |
617 | #[test] | |
618 | fn test_exp25() { | |
2c00a5a8 XL |
619 | let val = &[ |
620 | 3.0000000000, | |
621 | 24.0000000000, | |
622 | 1.0000000000, | |
623 | 19.0000000000, | |
624 | 7.0000000000, | |
625 | 5.0000000000, | |
626 | 30.0000000000, | |
627 | 39.0000000000, | |
628 | 31.0000000000, | |
629 | 13.0000000000, | |
630 | 25.0000000000, | |
631 | 48.0000000000, | |
632 | 1.0000000000, | |
633 | 6.0000000000, | |
634 | 42.0000000000, | |
635 | 63.0000000000, | |
636 | 2.0000000000, | |
637 | 12.0000000000, | |
638 | 108.0000000000, | |
639 | 26.0000000000, | |
640 | 1.0000000000, | |
641 | 7.0000000000, | |
642 | 44.0000000000, | |
643 | 25.0000000000, | |
644 | 11.0000000000, | |
645 | ]; | |
1a4d82fc JJ |
646 | let summ = &Summary { |
647 | sum: 593.0000000000, | |
648 | min: 1.0000000000, | |
649 | max: 108.0000000000, | |
650 | mean: 23.7200000000, | |
651 | median: 19.0000000000, | |
652 | var: 601.0433333333, | |
653 | std_dev: 24.5161851301, | |
654 | std_dev_pct: 103.3565983562, | |
655 | median_abs_dev: 19.2738000000, | |
656 | median_abs_dev_pct: 101.4410526316, | |
9cc50fc6 | 657 | quartiles: (6.0000000000, 19.0000000000, 31.0000000000), |
1a4d82fc JJ |
658 | iqr: 25.0000000000, |
659 | }; | |
660 | check(val, summ); | |
661 | } | |
662 | #[test] | |
663 | fn test_binom25() { | |
2c00a5a8 XL |
664 | let val = &[ |
665 | 18.0000000000, | |
666 | 17.0000000000, | |
667 | 27.0000000000, | |
668 | 15.0000000000, | |
669 | 21.0000000000, | |
670 | 25.0000000000, | |
671 | 17.0000000000, | |
672 | 24.0000000000, | |
673 | 25.0000000000, | |
674 | 24.0000000000, | |
675 | 26.0000000000, | |
676 | 26.0000000000, | |
677 | 23.0000000000, | |
678 | 15.0000000000, | |
679 | 23.0000000000, | |
680 | 17.0000000000, | |
681 | 18.0000000000, | |
682 | 18.0000000000, | |
683 | 21.0000000000, | |
684 | 16.0000000000, | |
685 | 15.0000000000, | |
686 | 31.0000000000, | |
687 | 20.0000000000, | |
688 | 17.0000000000, | |
689 | 15.0000000000, | |
690 | ]; | |
1a4d82fc JJ |
691 | let summ = &Summary { |
692 | sum: 514.0000000000, | |
693 | min: 15.0000000000, | |
694 | max: 31.0000000000, | |
695 | mean: 20.5600000000, | |
696 | median: 20.0000000000, | |
697 | var: 20.8400000000, | |
698 | std_dev: 4.5650848842, | |
699 | std_dev_pct: 22.2037202539, | |
700 | median_abs_dev: 5.9304000000, | |
701 | median_abs_dev_pct: 29.6520000000, | |
9cc50fc6 | 702 | quartiles: (17.0000000000, 20.0000000000, 24.0000000000), |
1a4d82fc JJ |
703 | iqr: 7.0000000000, |
704 | }; | |
705 | check(val, summ); | |
706 | } | |
707 | #[test] | |
708 | fn test_pois25lambda30() { | |
2c00a5a8 XL |
709 | let val = &[ |
710 | 27.0000000000, | |
711 | 33.0000000000, | |
712 | 34.0000000000, | |
713 | 34.0000000000, | |
714 | 24.0000000000, | |
715 | 39.0000000000, | |
716 | 28.0000000000, | |
717 | 27.0000000000, | |
718 | 31.0000000000, | |
719 | 28.0000000000, | |
720 | 38.0000000000, | |
721 | 21.0000000000, | |
722 | 33.0000000000, | |
723 | 36.0000000000, | |
724 | 29.0000000000, | |
725 | 37.0000000000, | |
726 | 32.0000000000, | |
727 | 34.0000000000, | |
728 | 31.0000000000, | |
729 | 39.0000000000, | |
730 | 25.0000000000, | |
731 | 31.0000000000, | |
732 | 32.0000000000, | |
733 | 40.0000000000, | |
734 | 24.0000000000, | |
735 | ]; | |
1a4d82fc JJ |
736 | let summ = &Summary { |
737 | sum: 787.0000000000, | |
738 | min: 21.0000000000, | |
739 | max: 40.0000000000, | |
740 | mean: 31.4800000000, | |
741 | median: 32.0000000000, | |
742 | var: 26.5933333333, | |
743 | std_dev: 5.1568724372, | |
744 | std_dev_pct: 16.3814245145, | |
745 | median_abs_dev: 5.9304000000, | |
746 | median_abs_dev_pct: 18.5325000000, | |
9cc50fc6 | 747 | quartiles: (28.0000000000, 32.0000000000, 34.0000000000), |
1a4d82fc JJ |
748 | iqr: 6.0000000000, |
749 | }; | |
750 | check(val, summ); | |
751 | } | |
752 | #[test] | |
753 | fn test_pois25lambda40() { | |
2c00a5a8 XL |
754 | let val = &[ |
755 | 42.0000000000, | |
756 | 50.0000000000, | |
757 | 42.0000000000, | |
758 | 46.0000000000, | |
759 | 34.0000000000, | |
760 | 45.0000000000, | |
761 | 34.0000000000, | |
762 | 49.0000000000, | |
763 | 39.0000000000, | |
764 | 28.0000000000, | |
765 | 40.0000000000, | |
766 | 35.0000000000, | |
767 | 37.0000000000, | |
768 | 39.0000000000, | |
769 | 46.0000000000, | |
770 | 44.0000000000, | |
771 | 32.0000000000, | |
772 | 45.0000000000, | |
773 | 42.0000000000, | |
774 | 37.0000000000, | |
775 | 48.0000000000, | |
776 | 42.0000000000, | |
777 | 33.0000000000, | |
778 | 42.0000000000, | |
779 | 48.0000000000, | |
780 | ]; | |
1a4d82fc JJ |
781 | let summ = &Summary { |
782 | sum: 1019.0000000000, | |
783 | min: 28.0000000000, | |
784 | max: 50.0000000000, | |
785 | mean: 40.7600000000, | |
786 | median: 42.0000000000, | |
787 | var: 34.4400000000, | |
788 | std_dev: 5.8685603004, | |
789 | std_dev_pct: 14.3978417577, | |
790 | median_abs_dev: 5.9304000000, | |
791 | median_abs_dev_pct: 14.1200000000, | |
9cc50fc6 | 792 | quartiles: (37.0000000000, 42.0000000000, 45.0000000000), |
1a4d82fc JJ |
793 | iqr: 8.0000000000, |
794 | }; | |
795 | check(val, summ); | |
796 | } | |
797 | #[test] | |
798 | fn test_pois25lambda50() { | |
2c00a5a8 XL |
799 | let val = &[ |
800 | 45.0000000000, | |
801 | 43.0000000000, | |
802 | 44.0000000000, | |
803 | 61.0000000000, | |
804 | 51.0000000000, | |
805 | 53.0000000000, | |
806 | 59.0000000000, | |
807 | 52.0000000000, | |
808 | 49.0000000000, | |
809 | 51.0000000000, | |
810 | 51.0000000000, | |
811 | 50.0000000000, | |
812 | 49.0000000000, | |
813 | 56.0000000000, | |
814 | 42.0000000000, | |
815 | 52.0000000000, | |
816 | 51.0000000000, | |
817 | 43.0000000000, | |
818 | 48.0000000000, | |
819 | 48.0000000000, | |
820 | 50.0000000000, | |
821 | 42.0000000000, | |
822 | 43.0000000000, | |
823 | 42.0000000000, | |
824 | 60.0000000000, | |
825 | ]; | |
1a4d82fc JJ |
826 | let summ = &Summary { |
827 | sum: 1235.0000000000, | |
828 | min: 42.0000000000, | |
829 | max: 61.0000000000, | |
830 | mean: 49.4000000000, | |
831 | median: 50.0000000000, | |
832 | var: 31.6666666667, | |
833 | std_dev: 5.6273143387, | |
834 | std_dev_pct: 11.3913245723, | |
835 | median_abs_dev: 4.4478000000, | |
836 | median_abs_dev_pct: 8.8956000000, | |
9cc50fc6 | 837 | quartiles: (44.0000000000, 50.0000000000, 52.0000000000), |
1a4d82fc JJ |
838 | iqr: 8.0000000000, |
839 | }; | |
840 | check(val, summ); | |
841 | } | |
842 | #[test] | |
843 | fn test_unif25() { | |
2c00a5a8 XL |
844 | let val = &[ |
845 | 99.0000000000, | |
846 | 55.0000000000, | |
847 | 92.0000000000, | |
848 | 79.0000000000, | |
849 | 14.0000000000, | |
850 | 2.0000000000, | |
851 | 33.0000000000, | |
852 | 49.0000000000, | |
853 | 3.0000000000, | |
854 | 32.0000000000, | |
855 | 84.0000000000, | |
856 | 59.0000000000, | |
857 | 22.0000000000, | |
858 | 86.0000000000, | |
859 | 76.0000000000, | |
860 | 31.0000000000, | |
861 | 29.0000000000, | |
862 | 11.0000000000, | |
863 | 41.0000000000, | |
864 | 53.0000000000, | |
865 | 45.0000000000, | |
866 | 44.0000000000, | |
867 | 98.0000000000, | |
868 | 98.0000000000, | |
869 | 7.0000000000, | |
870 | ]; | |
1a4d82fc JJ |
871 | let summ = &Summary { |
872 | sum: 1242.0000000000, | |
873 | min: 2.0000000000, | |
874 | max: 99.0000000000, | |
875 | mean: 49.6800000000, | |
876 | median: 45.0000000000, | |
877 | var: 1015.6433333333, | |
878 | std_dev: 31.8691595957, | |
879 | std_dev_pct: 64.1488719719, | |
880 | median_abs_dev: 45.9606000000, | |
881 | median_abs_dev_pct: 102.1346666667, | |
9cc50fc6 | 882 | quartiles: (29.0000000000, 45.0000000000, 79.0000000000), |
1a4d82fc JJ |
883 | iqr: 50.0000000000, |
884 | }; | |
885 | check(val, summ); | |
886 | } | |
887 | ||
1a4d82fc JJ |
888 | #[test] |
889 | fn test_sum_f64s() { | |
890 | assert_eq!([0.5f64, 3.2321f64, 1.5678f64].sum(), 5.2999); | |
891 | } | |
892 | #[test] | |
893 | fn test_sum_f64_between_ints_that_sum_to_0() { | |
894 | assert_eq!([1e30f64, 1.2f64, -1e30f64].sum(), 1.2); | |
895 | } | |
896 | } | |
897 | ||
898 | #[cfg(test)] | |
899 | mod bench { | |
b7449926 XL |
900 | extern crate test; |
901 | use self::test::Bencher; | |
1a4d82fc JJ |
902 | use stats::Stats; |
903 | ||
904 | #[bench] | |
905 | pub fn sum_three_items(b: &mut Bencher) { | |
0531ce1d XL |
906 | b.iter(|| { |
907 | [1e20f64, 1.5f64, -1e20f64].sum(); | |
908 | }) | |
1a4d82fc JJ |
909 | } |
910 | #[bench] | |
911 | pub fn sum_many_f64(b: &mut Bencher) { | |
912 | let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60]; | |
9cc50fc6 | 913 | let v = (0..500).map(|i| nums[i % 5]).collect::<Vec<_>>(); |
1a4d82fc | 914 | |
0531ce1d XL |
915 | b.iter(|| { |
916 | v.sum(); | |
917 | }) | |
1a4d82fc | 918 | } |
32a655c1 SL |
919 | |
920 | #[bench] | |
921 | pub fn no_iter(_: &mut Bencher) {} | |
1a4d82fc | 922 | } |