]> git.lizzy.rs Git - rust.git/blob - src/libtest/stats.rs
librustc: Remove the fallback to `int` from typechecking.
[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::collections::hashmap;
14 use std::fmt::Show;
15 use std::hash::Hash;
16 use std::io;
17 use std::mem;
18 use std::num::Zero;
19 use std::num;
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>{
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_doc)]
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
148     /// Construct a new summary of a sample set.
149     pub fn new(samples: &[T]) -> Summary<T> {
150         Summary {
151             sum: samples.sum(),
152             min: samples.min(),
153             max: samples.max(),
154             mean: samples.mean(),
155             median: samples.median(),
156             var: samples.var(),
157             std_dev: samples.std_dev(),
158             std_dev_pct: samples.std_dev_pct(),
159             median_abs_dev: samples.median_abs_dev(),
160             median_abs_dev_pct: samples.median_abs_dev_pct(),
161             quartiles: samples.quartiles(),
162             iqr: samples.iqr()
163         }
164     }
165 }
166
167 impl<'a,T: FloatMath + FromPrimitive> Stats<T> for &'a [T] {
168
169     // FIXME #11059 handle NaN, inf and overflow
170     fn sum(self) -> T {
171         let mut partials = vec![];
172
173         for &mut x in self.iter() {
174             let mut j = 0;
175             // This inner loop applies `hi`/`lo` summation to each
176             // partial so that the list of partial sums remains exact.
177             for i in range(0, partials.len()) {
178                 let mut y = *partials.get(i);
179                 if num::abs(x) < num::abs(y) {
180                     mem::swap(&mut x, &mut y);
181                 }
182                 // Rounded `x+y` is stored in `hi` with round-off stored in
183                 // `lo`. Together `hi+lo` are exactly equal to `x+y`.
184                 let hi = x + y;
185                 let lo = y - (hi - x);
186                 if !lo.is_zero() {
187                     *partials.get_mut(j) = lo;
188                     j += 1;
189                 }
190                 x = hi;
191             }
192             if j >= partials.len() {
193                 partials.push(x);
194             } else {
195                 *partials.get_mut(j) = x;
196                 partials.truncate(j+1);
197             }
198         }
199         let zero: T = Zero::zero();
200         partials.iter().fold(zero, |p, q| p + *q)
201     }
202
203     fn min(self) -> T {
204         assert!(self.len() != 0);
205         self.iter().fold(self[0], |p, q| p.min(*q))
206     }
207
208     fn max(self) -> T {
209         assert!(self.len() != 0);
210         self.iter().fold(self[0], |p, q| p.max(*q))
211     }
212
213     fn mean(self) -> T {
214         assert!(self.len() != 0);
215         self.sum() / FromPrimitive::from_uint(self.len()).unwrap()
216     }
217
218     fn median(self) -> T {
219         self.percentile(FromPrimitive::from_uint(50).unwrap())
220     }
221
222     fn var(self) -> T {
223         if self.len() < 2 {
224             Zero::zero()
225         } else {
226             let mean = self.mean();
227             let mut v: T = Zero::zero();
228             for s in self.iter() {
229                 let x = *s - mean;
230                 v = v + x*x;
231             }
232             // NB: this is _supposed to be_ len-1, not len. If you
233             // change it back to len, you will be calculating a
234             // population variance, not a sample variance.
235             let denom = FromPrimitive::from_uint(self.len()-1).unwrap();
236             v/denom
237         }
238     }
239
240     fn std_dev(self) -> T {
241         self.var().sqrt()
242     }
243
244     fn std_dev_pct(self) -> T {
245         let hundred = FromPrimitive::from_uint(100).unwrap();
246         (self.std_dev() / self.mean()) * hundred
247     }
248
249     fn median_abs_dev(self) -> T {
250         let med = self.median();
251         let abs_devs: Vec<T> = self.iter().map(|&v| num::abs(med - v)).collect();
252         // This constant is derived by smarter statistics brains than me, but it is
253         // consistent with how R and other packages treat the MAD.
254         let number = FromPrimitive::from_f64(1.4826).unwrap();
255         abs_devs.as_slice().median() * number
256     }
257
258     fn median_abs_dev_pct(self) -> T {
259         let hundred = FromPrimitive::from_uint(100).unwrap();
260         (self.median_abs_dev() / self.median()) * hundred
261     }
262
263     fn percentile(self, pct: T) -> T {
264         let mut tmp = Vec::from_slice(self);
265         local_sort(tmp.as_mut_slice());
266         percentile_of_sorted(tmp.as_slice(), pct)
267     }
268
269     fn quartiles(self) -> (T,T,T) {
270         let mut tmp = Vec::from_slice(self);
271         local_sort(tmp.as_mut_slice());
272         let first = FromPrimitive::from_uint(25).unwrap();
273         let a = percentile_of_sorted(tmp.as_slice(), first);
274         let secound = FromPrimitive::from_uint(50).unwrap();
275         let b = percentile_of_sorted(tmp.as_slice(), secound);
276         let third = FromPrimitive::from_uint(75).unwrap();
277         let c = percentile_of_sorted(tmp.as_slice(), third);
278         (a,b,c)
279     }
280
281     fn iqr(self) -> T {
282         let (a,_,c) = self.quartiles();
283         c - a
284     }
285 }
286
287
288 // Helper function: extract a value representing the `pct` percentile of a sorted sample-set, using
289 // linear interpolation. If samples are not sorted, return nonsensical value.
290 fn percentile_of_sorted<T: Float + FromPrimitive>(sorted_samples: &[T],
291                                                              pct: T) -> T {
292     assert!(sorted_samples.len() != 0);
293     if sorted_samples.len() == 1 {
294         return sorted_samples[0];
295     }
296     let zero: T = Zero::zero();
297     assert!(zero <= pct);
298     let hundred = FromPrimitive::from_uint(100).unwrap();
299     assert!(pct <= hundred);
300     if pct == hundred {
301         return sorted_samples[sorted_samples.len() - 1];
302     }
303     let length = FromPrimitive::from_uint(sorted_samples.len() - 1).unwrap();
304     let rank = (pct / hundred) * length;
305     let lrank = rank.floor();
306     let d = rank - lrank;
307     let n = lrank.to_uint().unwrap();
308     let lo = sorted_samples[n];
309     let hi = sorted_samples[n+1];
310     lo + (hi - lo) * d
311 }
312
313
314 /// Winsorize a set of samples, replacing values above the `100-pct` percentile and below the `pct`
315 /// percentile with those percentiles themselves. This is a way of minimizing the effect of
316 /// outliers, at the cost of biasing the sample. It differs from trimming in that it does not
317 /// change the number of samples, just changes the values of those that are outliers.
318 ///
319 /// See: http://en.wikipedia.org/wiki/Winsorising
320 pub fn winsorize<T: Float + FromPrimitive>(samples: &mut [T], pct: T) {
321     let mut tmp = Vec::from_slice(samples);
322     local_sort(tmp.as_mut_slice());
323     let lo = percentile_of_sorted(tmp.as_slice(), pct);
324     let hundred: T = FromPrimitive::from_uint(100).unwrap();
325     let hi = percentile_of_sorted(tmp.as_slice(), hundred-pct);
326     for samp in samples.mut_iter() {
327         if *samp > hi {
328             *samp = hi
329         } else if *samp < lo {
330             *samp = lo
331         }
332     }
333 }
334
335 /// Render writes the min, max and quartiles of the provided `Summary` to the provided `Writer`.
336 pub fn write_5_number_summary<T: Float + Show>(w: &mut io::Writer,
337                                                s: &Summary<T>) -> io::IoResult<()> {
338     let (q1,q2,q3) = s.quartiles;
339     write!(w, "(min={}, q1={}, med={}, q3={}, max={})",
340                      s.min,
341                      q1,
342                      q2,
343                      q3,
344                      s.max)
345 }
346
347 /// Render a boxplot to the provided writer. The boxplot shows the min, max and quartiles of the
348 /// provided `Summary` (thus includes the mean) and is scaled to display within the range of the
349 /// nearest multiple-of-a-power-of-ten above and below the min and max of possible values, and
350 /// target `width_hint` characters of display (though it will be wider if necessary).
351 ///
352 /// As an example, the summary with 5-number-summary `(min=15, q1=17, med=20, q3=24, max=31)` might
353 /// display as:
354 ///
355 /// ~~~~ignore
356 ///   10 |        [--****#******----------]          | 40
357 /// ~~~~
358
359 pub fn write_boxplot<T: Float + Show + FromPrimitive>(
360                      w: &mut io::Writer,
361                      s: &Summary<T>,
362                      width_hint: uint)
363                       -> io::IoResult<()> {
364
365     let (q1,q2,q3) = s.quartiles;
366
367     // the .abs() handles the case where numbers are negative
368     let ten: T = FromPrimitive::from_uint(10).unwrap();
369     let lomag = ten.powf(s.min.abs().log10().floor());
370     let himag = ten.powf(s.max.abs().log10().floor());
371
372     // need to consider when the limit is zero
373     let zero: T = Zero::zero();
374     let lo = if lomag.is_zero() {
375         zero
376     } else {
377         (s.min / lomag).floor() * lomag
378     };
379
380     let hi = if himag.is_zero() {
381         zero
382     } else {
383         (s.max / himag).ceil() * himag
384     };
385
386     let range = hi - lo;
387
388     let lostr = lo.to_str();
389     let histr = hi.to_str();
390
391     let overhead_width = lostr.len() + histr.len() + 4;
392     let range_width = width_hint - overhead_width;
393     let range_float = FromPrimitive::from_uint(range_width).unwrap();
394     let char_step = range / range_float;
395
396     try!(write!(w, "{} |", lostr));
397
398     let mut c = 0;
399     let mut v = lo;
400
401     while c < range_width && v < s.min {
402         try!(write!(w, " "));
403         v = v + char_step;
404         c += 1;
405     }
406     try!(write!(w, "["));
407     c += 1;
408     while c < range_width && v < q1 {
409         try!(write!(w, "-"));
410         v = v + char_step;
411         c += 1;
412     }
413     while c < range_width && v < q2 {
414         try!(write!(w, "*"));
415         v = v + char_step;
416         c += 1;
417     }
418     try!(write!(w, "#"));
419     c += 1;
420     while c < range_width && v < q3 {
421         try!(write!(w, "*"));
422         v = v + char_step;
423         c += 1;
424     }
425     while c < range_width && v < s.max {
426         try!(write!(w, "-"));
427         v = v + char_step;
428         c += 1;
429     }
430     try!(write!(w, "]"));
431     while c < range_width {
432         try!(write!(w, " "));
433         v = v + char_step;
434         c += 1;
435     }
436
437     try!(write!(w, "| {}", histr));
438     Ok(())
439 }
440
441 /// Returns a HashMap with the number of occurrences of every element in the
442 /// sequence that the iterator exposes.
443 pub fn freq_count<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
444     let mut map: hashmap::HashMap<U,uint> = hashmap::HashMap::new();
445     for elem in iter {
446         map.insert_or_update_with(elem, 1, |_, count| *count += 1);
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::str;
461     use std::f64;
462
463     macro_rules! assert_approx_eq(
464         ($a:expr, $b:expr) => ({
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 as &mut io::Writer;
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             use std::io::MemWriter;
1031             let mut m = MemWriter::new();
1032             write_boxplot(&mut m as &mut io::Writer, s, 30).unwrap();
1033             let out = str::from_utf8(m.unwrap().as_slice()).unwrap().to_string();
1034             assert_eq!(out, expected);
1035         }
1036
1037         t(&Summary::new([-2.0f64, -1.0f64]),
1038                         "-2 |[------******#*****---]| -1".to_string());
1039         t(&Summary::new([0.0f64, 2.0f64]),
1040                         "0 |[-------*****#*******---]| 2".to_string());
1041         t(&Summary::new([-2.0f64, 0.0f64]),
1042                         "-2 |[------******#******---]| 0".to_string());
1043
1044     }
1045     #[test]
1046     fn test_sum_f64s() {
1047         assert_eq!([0.5f64, 3.2321f64, 1.5678f64].sum(), 5.2999);
1048     }
1049     #[test]
1050     fn test_sum_f64_between_ints_that_sum_to_0() {
1051         assert_eq!([1e30f64, 1.2f64, -1e30f64].sum(), 1.2);
1052     }
1053 }
1054
1055 #[cfg(test)]
1056 mod bench {
1057     use Bencher;
1058     use stats::Stats;
1059
1060     #[bench]
1061     pub fn sum_three_items(b: &mut Bencher) {
1062         b.iter(|| {
1063             [1e20f64, 1.5f64, -1e20f64].sum();
1064         })
1065     }
1066     #[bench]
1067     pub fn sum_many_f64(b: &mut Bencher) {
1068         let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60];
1069         let v = Vec::from_fn(500, |i| nums[i%5]);
1070
1071         b.iter(|| {
1072             v.as_slice().sum();
1073         })
1074     }
1075 }