]> git.lizzy.rs Git - rust.git/blob - src/libtest/stats.rs
Fix errors
[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_string();
389     let histr = hi.to_string();
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::f64;
461
462     macro_rules! assert_approx_eq(
463         ($a:expr, $b:expr) => ({
464             let (a, b) = (&$a, &$b);
465             assert!((*a - *b).abs() < 1.0e-6,
466                     "{} is not approximately equal to {}", *a, *b);
467         })
468     )
469
470     fn check(samples: &[f64], summ: &Summary<f64>) {
471
472         let summ2 = Summary::new(samples);
473
474         let mut w = io::stdout();
475         let w = &mut w as &mut io::Writer;
476         (write!(w, "\n")).unwrap();
477         write_5_number_summary(w, &summ2).unwrap();
478         (write!(w, "\n")).unwrap();
479         write_boxplot(w, &summ2, 50).unwrap();
480         (write!(w, "\n")).unwrap();
481
482         assert_eq!(summ.sum, summ2.sum);
483         assert_eq!(summ.min, summ2.min);
484         assert_eq!(summ.max, summ2.max);
485         assert_eq!(summ.mean, summ2.mean);
486         assert_eq!(summ.median, summ2.median);
487
488         // We needed a few more digits to get exact equality on these
489         // but they're within float epsilon, which is 1.0e-6.
490         assert_approx_eq!(summ.var, summ2.var);
491         assert_approx_eq!(summ.std_dev, summ2.std_dev);
492         assert_approx_eq!(summ.std_dev_pct, summ2.std_dev_pct);
493         assert_approx_eq!(summ.median_abs_dev, summ2.median_abs_dev);
494         assert_approx_eq!(summ.median_abs_dev_pct, summ2.median_abs_dev_pct);
495
496         assert_eq!(summ.quartiles, summ2.quartiles);
497         assert_eq!(summ.iqr, summ2.iqr);
498     }
499
500     #[test]
501     fn test_min_max_nan() {
502         let xs = &[1.0, 2.0, f64::NAN, 3.0, 4.0];
503         let summary = Summary::new(xs);
504         assert_eq!(summary.min, 1.0);
505         assert_eq!(summary.max, 4.0);
506     }
507
508     #[test]
509     fn test_norm2() {
510         let val = &[
511             958.0000000000,
512             924.0000000000,
513         ];
514         let summ = &Summary {
515             sum: 1882.0000000000,
516             min: 924.0000000000,
517             max: 958.0000000000,
518             mean: 941.0000000000,
519             median: 941.0000000000,
520             var: 578.0000000000,
521             std_dev: 24.0416305603,
522             std_dev_pct: 2.5549022912,
523             median_abs_dev: 25.2042000000,
524             median_abs_dev_pct: 2.6784484591,
525             quartiles: (932.5000000000,941.0000000000,949.5000000000),
526             iqr: 17.0000000000,
527         };
528         check(val, summ);
529     }
530     #[test]
531     fn test_norm10narrow() {
532         let val = &[
533             966.0000000000,
534             985.0000000000,
535             1110.0000000000,
536             848.0000000000,
537             821.0000000000,
538             975.0000000000,
539             962.0000000000,
540             1157.0000000000,
541             1217.0000000000,
542             955.0000000000,
543         ];
544         let summ = &Summary {
545             sum: 9996.0000000000,
546             min: 821.0000000000,
547             max: 1217.0000000000,
548             mean: 999.6000000000,
549             median: 970.5000000000,
550             var: 16050.7111111111,
551             std_dev: 126.6914010938,
552             std_dev_pct: 12.6742097933,
553             median_abs_dev: 102.2994000000,
554             median_abs_dev_pct: 10.5408964451,
555             quartiles: (956.7500000000,970.5000000000,1078.7500000000),
556             iqr: 122.0000000000,
557         };
558         check(val, summ);
559     }
560     #[test]
561     fn test_norm10medium() {
562         let val = &[
563             954.0000000000,
564             1064.0000000000,
565             855.0000000000,
566             1000.0000000000,
567             743.0000000000,
568             1084.0000000000,
569             704.0000000000,
570             1023.0000000000,
571             357.0000000000,
572             869.0000000000,
573         ];
574         let summ = &Summary {
575             sum: 8653.0000000000,
576             min: 357.0000000000,
577             max: 1084.0000000000,
578             mean: 865.3000000000,
579             median: 911.5000000000,
580             var: 48628.4555555556,
581             std_dev: 220.5186059170,
582             std_dev_pct: 25.4846418487,
583             median_abs_dev: 195.7032000000,
584             median_abs_dev_pct: 21.4704552935,
585             quartiles: (771.0000000000,911.5000000000,1017.2500000000),
586             iqr: 246.2500000000,
587         };
588         check(val, summ);
589     }
590     #[test]
591     fn test_norm10wide() {
592         let val = &[
593             505.0000000000,
594             497.0000000000,
595             1591.0000000000,
596             887.0000000000,
597             1026.0000000000,
598             136.0000000000,
599             1580.0000000000,
600             940.0000000000,
601             754.0000000000,
602             1433.0000000000,
603         ];
604         let summ = &Summary {
605             sum: 9349.0000000000,
606             min: 136.0000000000,
607             max: 1591.0000000000,
608             mean: 934.9000000000,
609             median: 913.5000000000,
610             var: 239208.9888888889,
611             std_dev: 489.0899599142,
612             std_dev_pct: 52.3146817750,
613             median_abs_dev: 611.5725000000,
614             median_abs_dev_pct: 66.9482758621,
615             quartiles: (567.2500000000,913.5000000000,1331.2500000000),
616             iqr: 764.0000000000,
617         };
618         check(val, summ);
619     }
620     #[test]
621     fn test_norm25verynarrow() {
622         let val = &[
623             991.0000000000,
624             1018.0000000000,
625             998.0000000000,
626             1013.0000000000,
627             974.0000000000,
628             1007.0000000000,
629             1014.0000000000,
630             999.0000000000,
631             1011.0000000000,
632             978.0000000000,
633             985.0000000000,
634             999.0000000000,
635             983.0000000000,
636             982.0000000000,
637             1015.0000000000,
638             1002.0000000000,
639             977.0000000000,
640             948.0000000000,
641             1040.0000000000,
642             974.0000000000,
643             996.0000000000,
644             989.0000000000,
645             1015.0000000000,
646             994.0000000000,
647             1024.0000000000,
648         ];
649         let summ = &Summary {
650             sum: 24926.0000000000,
651             min: 948.0000000000,
652             max: 1040.0000000000,
653             mean: 997.0400000000,
654             median: 998.0000000000,
655             var: 393.2066666667,
656             std_dev: 19.8294393937,
657             std_dev_pct: 1.9888308788,
658             median_abs_dev: 22.2390000000,
659             median_abs_dev_pct: 2.2283567134,
660             quartiles: (983.0000000000,998.0000000000,1013.0000000000),
661             iqr: 30.0000000000,
662         };
663         check(val, summ);
664     }
665     #[test]
666     fn test_exp10a() {
667         let val = &[
668             23.0000000000,
669             11.0000000000,
670             2.0000000000,
671             57.0000000000,
672             4.0000000000,
673             12.0000000000,
674             5.0000000000,
675             29.0000000000,
676             3.0000000000,
677             21.0000000000,
678         ];
679         let summ = &Summary {
680             sum: 167.0000000000,
681             min: 2.0000000000,
682             max: 57.0000000000,
683             mean: 16.7000000000,
684             median: 11.5000000000,
685             var: 287.7888888889,
686             std_dev: 16.9643416875,
687             std_dev_pct: 101.5828843560,
688             median_abs_dev: 13.3434000000,
689             median_abs_dev_pct: 116.0295652174,
690             quartiles: (4.2500000000,11.5000000000,22.5000000000),
691             iqr: 18.2500000000,
692         };
693         check(val, summ);
694     }
695     #[test]
696     fn test_exp10b() {
697         let val = &[
698             24.0000000000,
699             17.0000000000,
700             6.0000000000,
701             38.0000000000,
702             25.0000000000,
703             7.0000000000,
704             51.0000000000,
705             2.0000000000,
706             61.0000000000,
707             32.0000000000,
708         ];
709         let summ = &Summary {
710             sum: 263.0000000000,
711             min: 2.0000000000,
712             max: 61.0000000000,
713             mean: 26.3000000000,
714             median: 24.5000000000,
715             var: 383.5666666667,
716             std_dev: 19.5848580967,
717             std_dev_pct: 74.4671410520,
718             median_abs_dev: 22.9803000000,
719             median_abs_dev_pct: 93.7971428571,
720             quartiles: (9.5000000000,24.5000000000,36.5000000000),
721             iqr: 27.0000000000,
722         };
723         check(val, summ);
724     }
725     #[test]
726     fn test_exp10c() {
727         let val = &[
728             71.0000000000,
729             2.0000000000,
730             32.0000000000,
731             1.0000000000,
732             6.0000000000,
733             28.0000000000,
734             13.0000000000,
735             37.0000000000,
736             16.0000000000,
737             36.0000000000,
738         ];
739         let summ = &Summary {
740             sum: 242.0000000000,
741             min: 1.0000000000,
742             max: 71.0000000000,
743             mean: 24.2000000000,
744             median: 22.0000000000,
745             var: 458.1777777778,
746             std_dev: 21.4050876611,
747             std_dev_pct: 88.4507754589,
748             median_abs_dev: 21.4977000000,
749             median_abs_dev_pct: 97.7168181818,
750             quartiles: (7.7500000000,22.0000000000,35.0000000000),
751             iqr: 27.2500000000,
752         };
753         check(val, summ);
754     }
755     #[test]
756     fn test_exp25() {
757         let val = &[
758             3.0000000000,
759             24.0000000000,
760             1.0000000000,
761             19.0000000000,
762             7.0000000000,
763             5.0000000000,
764             30.0000000000,
765             39.0000000000,
766             31.0000000000,
767             13.0000000000,
768             25.0000000000,
769             48.0000000000,
770             1.0000000000,
771             6.0000000000,
772             42.0000000000,
773             63.0000000000,
774             2.0000000000,
775             12.0000000000,
776             108.0000000000,
777             26.0000000000,
778             1.0000000000,
779             7.0000000000,
780             44.0000000000,
781             25.0000000000,
782             11.0000000000,
783         ];
784         let summ = &Summary {
785             sum: 593.0000000000,
786             min: 1.0000000000,
787             max: 108.0000000000,
788             mean: 23.7200000000,
789             median: 19.0000000000,
790             var: 601.0433333333,
791             std_dev: 24.5161851301,
792             std_dev_pct: 103.3565983562,
793             median_abs_dev: 19.2738000000,
794             median_abs_dev_pct: 101.4410526316,
795             quartiles: (6.0000000000,19.0000000000,31.0000000000),
796             iqr: 25.0000000000,
797         };
798         check(val, summ);
799     }
800     #[test]
801     fn test_binom25() {
802         let val = &[
803             18.0000000000,
804             17.0000000000,
805             27.0000000000,
806             15.0000000000,
807             21.0000000000,
808             25.0000000000,
809             17.0000000000,
810             24.0000000000,
811             25.0000000000,
812             24.0000000000,
813             26.0000000000,
814             26.0000000000,
815             23.0000000000,
816             15.0000000000,
817             23.0000000000,
818             17.0000000000,
819             18.0000000000,
820             18.0000000000,
821             21.0000000000,
822             16.0000000000,
823             15.0000000000,
824             31.0000000000,
825             20.0000000000,
826             17.0000000000,
827             15.0000000000,
828         ];
829         let summ = &Summary {
830             sum: 514.0000000000,
831             min: 15.0000000000,
832             max: 31.0000000000,
833             mean: 20.5600000000,
834             median: 20.0000000000,
835             var: 20.8400000000,
836             std_dev: 4.5650848842,
837             std_dev_pct: 22.2037202539,
838             median_abs_dev: 5.9304000000,
839             median_abs_dev_pct: 29.6520000000,
840             quartiles: (17.0000000000,20.0000000000,24.0000000000),
841             iqr: 7.0000000000,
842         };
843         check(val, summ);
844     }
845     #[test]
846     fn test_pois25lambda30() {
847         let val = &[
848             27.0000000000,
849             33.0000000000,
850             34.0000000000,
851             34.0000000000,
852             24.0000000000,
853             39.0000000000,
854             28.0000000000,
855             27.0000000000,
856             31.0000000000,
857             28.0000000000,
858             38.0000000000,
859             21.0000000000,
860             33.0000000000,
861             36.0000000000,
862             29.0000000000,
863             37.0000000000,
864             32.0000000000,
865             34.0000000000,
866             31.0000000000,
867             39.0000000000,
868             25.0000000000,
869             31.0000000000,
870             32.0000000000,
871             40.0000000000,
872             24.0000000000,
873         ];
874         let summ = &Summary {
875             sum: 787.0000000000,
876             min: 21.0000000000,
877             max: 40.0000000000,
878             mean: 31.4800000000,
879             median: 32.0000000000,
880             var: 26.5933333333,
881             std_dev: 5.1568724372,
882             std_dev_pct: 16.3814245145,
883             median_abs_dev: 5.9304000000,
884             median_abs_dev_pct: 18.5325000000,
885             quartiles: (28.0000000000,32.0000000000,34.0000000000),
886             iqr: 6.0000000000,
887         };
888         check(val, summ);
889     }
890     #[test]
891     fn test_pois25lambda40() {
892         let val = &[
893             42.0000000000,
894             50.0000000000,
895             42.0000000000,
896             46.0000000000,
897             34.0000000000,
898             45.0000000000,
899             34.0000000000,
900             49.0000000000,
901             39.0000000000,
902             28.0000000000,
903             40.0000000000,
904             35.0000000000,
905             37.0000000000,
906             39.0000000000,
907             46.0000000000,
908             44.0000000000,
909             32.0000000000,
910             45.0000000000,
911             42.0000000000,
912             37.0000000000,
913             48.0000000000,
914             42.0000000000,
915             33.0000000000,
916             42.0000000000,
917             48.0000000000,
918         ];
919         let summ = &Summary {
920             sum: 1019.0000000000,
921             min: 28.0000000000,
922             max: 50.0000000000,
923             mean: 40.7600000000,
924             median: 42.0000000000,
925             var: 34.4400000000,
926             std_dev: 5.8685603004,
927             std_dev_pct: 14.3978417577,
928             median_abs_dev: 5.9304000000,
929             median_abs_dev_pct: 14.1200000000,
930             quartiles: (37.0000000000,42.0000000000,45.0000000000),
931             iqr: 8.0000000000,
932         };
933         check(val, summ);
934     }
935     #[test]
936     fn test_pois25lambda50() {
937         let val = &[
938             45.0000000000,
939             43.0000000000,
940             44.0000000000,
941             61.0000000000,
942             51.0000000000,
943             53.0000000000,
944             59.0000000000,
945             52.0000000000,
946             49.0000000000,
947             51.0000000000,
948             51.0000000000,
949             50.0000000000,
950             49.0000000000,
951             56.0000000000,
952             42.0000000000,
953             52.0000000000,
954             51.0000000000,
955             43.0000000000,
956             48.0000000000,
957             48.0000000000,
958             50.0000000000,
959             42.0000000000,
960             43.0000000000,
961             42.0000000000,
962             60.0000000000,
963         ];
964         let summ = &Summary {
965             sum: 1235.0000000000,
966             min: 42.0000000000,
967             max: 61.0000000000,
968             mean: 49.4000000000,
969             median: 50.0000000000,
970             var: 31.6666666667,
971             std_dev: 5.6273143387,
972             std_dev_pct: 11.3913245723,
973             median_abs_dev: 4.4478000000,
974             median_abs_dev_pct: 8.8956000000,
975             quartiles: (44.0000000000,50.0000000000,52.0000000000),
976             iqr: 8.0000000000,
977         };
978         check(val, summ);
979     }
980     #[test]
981     fn test_unif25() {
982         let val = &[
983             99.0000000000,
984             55.0000000000,
985             92.0000000000,
986             79.0000000000,
987             14.0000000000,
988             2.0000000000,
989             33.0000000000,
990             49.0000000000,
991             3.0000000000,
992             32.0000000000,
993             84.0000000000,
994             59.0000000000,
995             22.0000000000,
996             86.0000000000,
997             76.0000000000,
998             31.0000000000,
999             29.0000000000,
1000             11.0000000000,
1001             41.0000000000,
1002             53.0000000000,
1003             45.0000000000,
1004             44.0000000000,
1005             98.0000000000,
1006             98.0000000000,
1007             7.0000000000,
1008         ];
1009         let summ = &Summary {
1010             sum: 1242.0000000000,
1011             min: 2.0000000000,
1012             max: 99.0000000000,
1013             mean: 49.6800000000,
1014             median: 45.0000000000,
1015             var: 1015.6433333333,
1016             std_dev: 31.8691595957,
1017             std_dev_pct: 64.1488719719,
1018             median_abs_dev: 45.9606000000,
1019             median_abs_dev_pct: 102.1346666667,
1020             quartiles: (29.0000000000,45.0000000000,79.0000000000),
1021             iqr: 50.0000000000,
1022         };
1023         check(val, summ);
1024     }
1025
1026     #[test]
1027     fn test_boxplot_nonpositive() {
1028         fn t(s: &Summary<f64>, expected: String) {
1029             use std::io::MemWriter;
1030             let mut m = MemWriter::new();
1031             write_boxplot(&mut m as &mut io::Writer, s, 30).unwrap();
1032             let out = String::from_utf8(m.unwrap()).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 }