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