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