]> git.lizzy.rs Git - rust.git/blob - src/libtest/stats.rs
debuginfo: Make debuginfo source location assignment more stable (Pt. 1)
[rust.git] / src / libtest / stats.rs
1 // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(missing_docs)]
12
13 use std::cmp::Ordering::{self, Less, Greater, Equal};
14 use std::collections::hash_map::Entry::{Occupied, Vacant};
15 use std::collections::hash_map::{self, Hasher};
16 use std::fmt;
17 use std::hash::Hash;
18 use std::io;
19 use std::mem;
20 use std::num::{Float, FromPrimitive};
21
22 fn local_cmp<T:Float>(x: T, y: T) -> 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 local_sort<T: Float>(v: &mut [T]) {
38     v.sort_by(|x: &T, y: &T| local_cmp(*x, *y));
39 }
40
41 /// Trait that provides simple descriptive statistics on a univariate set of numeric samples.
42 pub trait Stats <T: Float + FromPrimitive> {
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) -> T;
52
53     /// Minimum value of the samples.
54     fn min(&self) -> T;
55
56     /// Maximum value of the samples.
57     fn max(&self) -> T;
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) -> T;
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) -> T;
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) -> T;
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) -> T;
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) -> T;
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) -> T;
101
102     /// Median absolute deviation as a percent of the median. See `median_abs_dev` and `median`.
103     fn median_abs_dev_pct(&self) -> T;
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: T) -> T;
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) -> (T,T,T);
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) -> T;
127 }
128
129 /// Extracted collection of all the summary statistics of a sample set.
130 #[derive(Clone, PartialEq)]
131 #[allow(missing_docs)]
132 pub struct Summary<T> {
133     pub sum: T,
134     pub min: T,
135     pub max: T,
136     pub mean: T,
137     pub median: T,
138     pub var: T,
139     pub std_dev: T,
140     pub std_dev_pct: T,
141     pub median_abs_dev: T,
142     pub median_abs_dev_pct: T,
143     pub quartiles: (T,T,T),
144     pub iqr: T,
145 }
146
147 impl<T: Float + FromPrimitive> Summary<T> {
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<T: Float + FromPrimitive> Stats<T> for [T] {
168     // FIXME #11059 handle NaN, inf and overflow
169     fn sum(&self) -> T {
170         let mut partials = vec![];
171
172         for &x in self.iter() {
173             let mut x = x;
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: T = partials[i];
179                 if x.abs() < y.abs() {
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 != Float::zero() {
187                     partials[j] = lo;
188                     j += 1;
189                 }
190                 x = hi;
191             }
192             if j >= partials.len() {
193                 partials.push(x);
194             } else {
195                 partials[j] = x;
196                 partials.truncate(j+1);
197             }
198         }
199         let zero: T = Float::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             Float::zero()
225         } else {
226             let mean = self.mean();
227             let mut v: T = Float::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| (med - v).abs()).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.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 = self.to_vec();
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 = self.to_vec();
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 = Float::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 = samples.to_vec();
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.iter_mut() {
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<W: Writer, T: Float + fmt::String + fmt::Show>(w: &mut W,
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 pub fn write_boxplot<W: Writer, T: Float + fmt::String + fmt::Show + FromPrimitive>(
359                      w: &mut W,
360                      s: &Summary<T>,
361                      width_hint: uint)
362                       -> io::IoResult<()> {
363
364     let (q1,q2,q3) = s.quartiles;
365
366     // the .abs() handles the case where numbers are negative
367     let ten: T = FromPrimitive::from_uint(10).unwrap();
368     let lomag = ten.powf(s.min.abs().log10().floor());
369     let himag = ten.powf(s.max.abs().log10().floor());
370
371     // need to consider when the limit is zero
372     let zero: T = Float::zero();
373     let lo = if lomag == Float::zero() {
374         zero
375     } else {
376         (s.min / lomag).floor() * lomag
377     };
378
379     let hi = if himag == Float::zero() {
380         zero
381     } else {
382         (s.max / himag).ceil() * himag
383     };
384
385     let range = hi - lo;
386
387     let lostr = lo.to_string();
388     let histr = hi.to_string();
389
390     let overhead_width = lostr.len() + histr.len() + 4;
391     let range_width = width_hint - overhead_width;
392     let range_float = FromPrimitive::from_uint(range_width).unwrap();
393     let char_step = range / range_float;
394
395     try!(write!(w, "{} |", lostr));
396
397     let mut c = 0;
398     let mut v = lo;
399
400     while c < range_width && v < s.min {
401         try!(write!(w, " "));
402         v = v + char_step;
403         c += 1;
404     }
405     try!(write!(w, "["));
406     c += 1;
407     while c < range_width && v < q1 {
408         try!(write!(w, "-"));
409         v = v + char_step;
410         c += 1;
411     }
412     while c < range_width && v < q2 {
413         try!(write!(w, "*"));
414         v = v + char_step;
415         c += 1;
416     }
417     try!(write!(w, "#"));
418     c += 1;
419     while c < range_width && v < q3 {
420         try!(write!(w, "*"));
421         v = v + char_step;
422         c += 1;
423     }
424     while c < range_width && v < s.max {
425         try!(write!(w, "-"));
426         v = v + char_step;
427         c += 1;
428     }
429     try!(write!(w, "]"));
430     while c < range_width {
431         try!(write!(w, " "));
432         v = v + char_step;
433         c += 1;
434     }
435
436     try!(write!(w, "| {}", histr));
437     Ok(())
438 }
439
440 /// Returns a HashMap with the number of occurrences of every element in the
441 /// sequence that the iterator exposes.
442 pub fn freq_count<T, U>(mut iter: T) -> hash_map::HashMap<U, uint>
443   where T: Iterator<Item=U>, U: Eq + Clone + Hash<Hasher>
444 {
445     let mut map: hash_map::HashMap<U,uint> = hash_map::HashMap::new();
446     for elem in iter {
447         match map.entry(elem) {
448             Occupied(mut entry) => { *entry.get_mut() += 1; },
449             Vacant(entry) => { entry.insert(1); },
450         }
451     }
452     map
453 }
454
455 // Test vectors generated from R, using the script src/etc/stat-test-vectors.r.
456
457 #[cfg(test)]
458 mod tests {
459     use stats::Stats;
460     use stats::Summary;
461     use stats::write_5_number_summary;
462     use stats::write_boxplot;
463     use std::io;
464     use std::f64;
465
466     macro_rules! assert_approx_eq {
467         ($a:expr, $b:expr) => ({
468             use std::num::Float;
469             let (a, b) = (&$a, &$b);
470             assert!((*a - *b).abs() < 1.0e-6,
471                     "{} is not approximately equal to {}", *a, *b);
472         })
473     }
474
475     fn check(samples: &[f64], summ: &Summary<f64>) {
476
477         let summ2 = Summary::new(samples);
478
479         let mut w = io::stdout();
480         let w = &mut w;
481         (write!(w, "\n")).unwrap();
482         write_5_number_summary(w, &summ2).unwrap();
483         (write!(w, "\n")).unwrap();
484         write_boxplot(w, &summ2, 50).unwrap();
485         (write!(w, "\n")).unwrap();
486
487         assert_eq!(summ.sum, summ2.sum);
488         assert_eq!(summ.min, summ2.min);
489         assert_eq!(summ.max, summ2.max);
490         assert_eq!(summ.mean, summ2.mean);
491         assert_eq!(summ.median, summ2.median);
492
493         // We needed a few more digits to get exact equality on these
494         // but they're within float epsilon, which is 1.0e-6.
495         assert_approx_eq!(summ.var, summ2.var);
496         assert_approx_eq!(summ.std_dev, summ2.std_dev);
497         assert_approx_eq!(summ.std_dev_pct, summ2.std_dev_pct);
498         assert_approx_eq!(summ.median_abs_dev, summ2.median_abs_dev);
499         assert_approx_eq!(summ.median_abs_dev_pct, summ2.median_abs_dev_pct);
500
501         assert_eq!(summ.quartiles, summ2.quartiles);
502         assert_eq!(summ.iqr, summ2.iqr);
503     }
504
505     #[test]
506     fn test_min_max_nan() {
507         let xs = &[1.0, 2.0, f64::NAN, 3.0, 4.0];
508         let summary = Summary::new(xs);
509         assert_eq!(summary.min, 1.0);
510         assert_eq!(summary.max, 4.0);
511     }
512
513     #[test]
514     fn test_norm2() {
515         let val = &[
516             958.0000000000,
517             924.0000000000,
518         ];
519         let summ = &Summary {
520             sum: 1882.0000000000,
521             min: 924.0000000000,
522             max: 958.0000000000,
523             mean: 941.0000000000,
524             median: 941.0000000000,
525             var: 578.0000000000,
526             std_dev: 24.0416305603,
527             std_dev_pct: 2.5549022912,
528             median_abs_dev: 25.2042000000,
529             median_abs_dev_pct: 2.6784484591,
530             quartiles: (932.5000000000,941.0000000000,949.5000000000),
531             iqr: 17.0000000000,
532         };
533         check(val, summ);
534     }
535     #[test]
536     fn test_norm10narrow() {
537         let val = &[
538             966.0000000000,
539             985.0000000000,
540             1110.0000000000,
541             848.0000000000,
542             821.0000000000,
543             975.0000000000,
544             962.0000000000,
545             1157.0000000000,
546             1217.0000000000,
547             955.0000000000,
548         ];
549         let summ = &Summary {
550             sum: 9996.0000000000,
551             min: 821.0000000000,
552             max: 1217.0000000000,
553             mean: 999.6000000000,
554             median: 970.5000000000,
555             var: 16050.7111111111,
556             std_dev: 126.6914010938,
557             std_dev_pct: 12.6742097933,
558             median_abs_dev: 102.2994000000,
559             median_abs_dev_pct: 10.5408964451,
560             quartiles: (956.7500000000,970.5000000000,1078.7500000000),
561             iqr: 122.0000000000,
562         };
563         check(val, summ);
564     }
565     #[test]
566     fn test_norm10medium() {
567         let val = &[
568             954.0000000000,
569             1064.0000000000,
570             855.0000000000,
571             1000.0000000000,
572             743.0000000000,
573             1084.0000000000,
574             704.0000000000,
575             1023.0000000000,
576             357.0000000000,
577             869.0000000000,
578         ];
579         let summ = &Summary {
580             sum: 8653.0000000000,
581             min: 357.0000000000,
582             max: 1084.0000000000,
583             mean: 865.3000000000,
584             median: 911.5000000000,
585             var: 48628.4555555556,
586             std_dev: 220.5186059170,
587             std_dev_pct: 25.4846418487,
588             median_abs_dev: 195.7032000000,
589             median_abs_dev_pct: 21.4704552935,
590             quartiles: (771.0000000000,911.5000000000,1017.2500000000),
591             iqr: 246.2500000000,
592         };
593         check(val, summ);
594     }
595     #[test]
596     fn test_norm10wide() {
597         let val = &[
598             505.0000000000,
599             497.0000000000,
600             1591.0000000000,
601             887.0000000000,
602             1026.0000000000,
603             136.0000000000,
604             1580.0000000000,
605             940.0000000000,
606             754.0000000000,
607             1433.0000000000,
608         ];
609         let summ = &Summary {
610             sum: 9349.0000000000,
611             min: 136.0000000000,
612             max: 1591.0000000000,
613             mean: 934.9000000000,
614             median: 913.5000000000,
615             var: 239208.9888888889,
616             std_dev: 489.0899599142,
617             std_dev_pct: 52.3146817750,
618             median_abs_dev: 611.5725000000,
619             median_abs_dev_pct: 66.9482758621,
620             quartiles: (567.2500000000,913.5000000000,1331.2500000000),
621             iqr: 764.0000000000,
622         };
623         check(val, summ);
624     }
625     #[test]
626     fn test_norm25verynarrow() {
627         let val = &[
628             991.0000000000,
629             1018.0000000000,
630             998.0000000000,
631             1013.0000000000,
632             974.0000000000,
633             1007.0000000000,
634             1014.0000000000,
635             999.0000000000,
636             1011.0000000000,
637             978.0000000000,
638             985.0000000000,
639             999.0000000000,
640             983.0000000000,
641             982.0000000000,
642             1015.0000000000,
643             1002.0000000000,
644             977.0000000000,
645             948.0000000000,
646             1040.0000000000,
647             974.0000000000,
648             996.0000000000,
649             989.0000000000,
650             1015.0000000000,
651             994.0000000000,
652             1024.0000000000,
653         ];
654         let summ = &Summary {
655             sum: 24926.0000000000,
656             min: 948.0000000000,
657             max: 1040.0000000000,
658             mean: 997.0400000000,
659             median: 998.0000000000,
660             var: 393.2066666667,
661             std_dev: 19.8294393937,
662             std_dev_pct: 1.9888308788,
663             median_abs_dev: 22.2390000000,
664             median_abs_dev_pct: 2.2283567134,
665             quartiles: (983.0000000000,998.0000000000,1013.0000000000),
666             iqr: 30.0000000000,
667         };
668         check(val, summ);
669     }
670     #[test]
671     fn test_exp10a() {
672         let val = &[
673             23.0000000000,
674             11.0000000000,
675             2.0000000000,
676             57.0000000000,
677             4.0000000000,
678             12.0000000000,
679             5.0000000000,
680             29.0000000000,
681             3.0000000000,
682             21.0000000000,
683         ];
684         let summ = &Summary {
685             sum: 167.0000000000,
686             min: 2.0000000000,
687             max: 57.0000000000,
688             mean: 16.7000000000,
689             median: 11.5000000000,
690             var: 287.7888888889,
691             std_dev: 16.9643416875,
692             std_dev_pct: 101.5828843560,
693             median_abs_dev: 13.3434000000,
694             median_abs_dev_pct: 116.0295652174,
695             quartiles: (4.2500000000,11.5000000000,22.5000000000),
696             iqr: 18.2500000000,
697         };
698         check(val, summ);
699     }
700     #[test]
701     fn test_exp10b() {
702         let val = &[
703             24.0000000000,
704             17.0000000000,
705             6.0000000000,
706             38.0000000000,
707             25.0000000000,
708             7.0000000000,
709             51.0000000000,
710             2.0000000000,
711             61.0000000000,
712             32.0000000000,
713         ];
714         let summ = &Summary {
715             sum: 263.0000000000,
716             min: 2.0000000000,
717             max: 61.0000000000,
718             mean: 26.3000000000,
719             median: 24.5000000000,
720             var: 383.5666666667,
721             std_dev: 19.5848580967,
722             std_dev_pct: 74.4671410520,
723             median_abs_dev: 22.9803000000,
724             median_abs_dev_pct: 93.7971428571,
725             quartiles: (9.5000000000,24.5000000000,36.5000000000),
726             iqr: 27.0000000000,
727         };
728         check(val, summ);
729     }
730     #[test]
731     fn test_exp10c() {
732         let val = &[
733             71.0000000000,
734             2.0000000000,
735             32.0000000000,
736             1.0000000000,
737             6.0000000000,
738             28.0000000000,
739             13.0000000000,
740             37.0000000000,
741             16.0000000000,
742             36.0000000000,
743         ];
744         let summ = &Summary {
745             sum: 242.0000000000,
746             min: 1.0000000000,
747             max: 71.0000000000,
748             mean: 24.2000000000,
749             median: 22.0000000000,
750             var: 458.1777777778,
751             std_dev: 21.4050876611,
752             std_dev_pct: 88.4507754589,
753             median_abs_dev: 21.4977000000,
754             median_abs_dev_pct: 97.7168181818,
755             quartiles: (7.7500000000,22.0000000000,35.0000000000),
756             iqr: 27.2500000000,
757         };
758         check(val, summ);
759     }
760     #[test]
761     fn test_exp25() {
762         let val = &[
763             3.0000000000,
764             24.0000000000,
765             1.0000000000,
766             19.0000000000,
767             7.0000000000,
768             5.0000000000,
769             30.0000000000,
770             39.0000000000,
771             31.0000000000,
772             13.0000000000,
773             25.0000000000,
774             48.0000000000,
775             1.0000000000,
776             6.0000000000,
777             42.0000000000,
778             63.0000000000,
779             2.0000000000,
780             12.0000000000,
781             108.0000000000,
782             26.0000000000,
783             1.0000000000,
784             7.0000000000,
785             44.0000000000,
786             25.0000000000,
787             11.0000000000,
788         ];
789         let summ = &Summary {
790             sum: 593.0000000000,
791             min: 1.0000000000,
792             max: 108.0000000000,
793             mean: 23.7200000000,
794             median: 19.0000000000,
795             var: 601.0433333333,
796             std_dev: 24.5161851301,
797             std_dev_pct: 103.3565983562,
798             median_abs_dev: 19.2738000000,
799             median_abs_dev_pct: 101.4410526316,
800             quartiles: (6.0000000000,19.0000000000,31.0000000000),
801             iqr: 25.0000000000,
802         };
803         check(val, summ);
804     }
805     #[test]
806     fn test_binom25() {
807         let val = &[
808             18.0000000000,
809             17.0000000000,
810             27.0000000000,
811             15.0000000000,
812             21.0000000000,
813             25.0000000000,
814             17.0000000000,
815             24.0000000000,
816             25.0000000000,
817             24.0000000000,
818             26.0000000000,
819             26.0000000000,
820             23.0000000000,
821             15.0000000000,
822             23.0000000000,
823             17.0000000000,
824             18.0000000000,
825             18.0000000000,
826             21.0000000000,
827             16.0000000000,
828             15.0000000000,
829             31.0000000000,
830             20.0000000000,
831             17.0000000000,
832             15.0000000000,
833         ];
834         let summ = &Summary {
835             sum: 514.0000000000,
836             min: 15.0000000000,
837             max: 31.0000000000,
838             mean: 20.5600000000,
839             median: 20.0000000000,
840             var: 20.8400000000,
841             std_dev: 4.5650848842,
842             std_dev_pct: 22.2037202539,
843             median_abs_dev: 5.9304000000,
844             median_abs_dev_pct: 29.6520000000,
845             quartiles: (17.0000000000,20.0000000000,24.0000000000),
846             iqr: 7.0000000000,
847         };
848         check(val, summ);
849     }
850     #[test]
851     fn test_pois25lambda30() {
852         let val = &[
853             27.0000000000,
854             33.0000000000,
855             34.0000000000,
856             34.0000000000,
857             24.0000000000,
858             39.0000000000,
859             28.0000000000,
860             27.0000000000,
861             31.0000000000,
862             28.0000000000,
863             38.0000000000,
864             21.0000000000,
865             33.0000000000,
866             36.0000000000,
867             29.0000000000,
868             37.0000000000,
869             32.0000000000,
870             34.0000000000,
871             31.0000000000,
872             39.0000000000,
873             25.0000000000,
874             31.0000000000,
875             32.0000000000,
876             40.0000000000,
877             24.0000000000,
878         ];
879         let summ = &Summary {
880             sum: 787.0000000000,
881             min: 21.0000000000,
882             max: 40.0000000000,
883             mean: 31.4800000000,
884             median: 32.0000000000,
885             var: 26.5933333333,
886             std_dev: 5.1568724372,
887             std_dev_pct: 16.3814245145,
888             median_abs_dev: 5.9304000000,
889             median_abs_dev_pct: 18.5325000000,
890             quartiles: (28.0000000000,32.0000000000,34.0000000000),
891             iqr: 6.0000000000,
892         };
893         check(val, summ);
894     }
895     #[test]
896     fn test_pois25lambda40() {
897         let val = &[
898             42.0000000000,
899             50.0000000000,
900             42.0000000000,
901             46.0000000000,
902             34.0000000000,
903             45.0000000000,
904             34.0000000000,
905             49.0000000000,
906             39.0000000000,
907             28.0000000000,
908             40.0000000000,
909             35.0000000000,
910             37.0000000000,
911             39.0000000000,
912             46.0000000000,
913             44.0000000000,
914             32.0000000000,
915             45.0000000000,
916             42.0000000000,
917             37.0000000000,
918             48.0000000000,
919             42.0000000000,
920             33.0000000000,
921             42.0000000000,
922             48.0000000000,
923         ];
924         let summ = &Summary {
925             sum: 1019.0000000000,
926             min: 28.0000000000,
927             max: 50.0000000000,
928             mean: 40.7600000000,
929             median: 42.0000000000,
930             var: 34.4400000000,
931             std_dev: 5.8685603004,
932             std_dev_pct: 14.3978417577,
933             median_abs_dev: 5.9304000000,
934             median_abs_dev_pct: 14.1200000000,
935             quartiles: (37.0000000000,42.0000000000,45.0000000000),
936             iqr: 8.0000000000,
937         };
938         check(val, summ);
939     }
940     #[test]
941     fn test_pois25lambda50() {
942         let val = &[
943             45.0000000000,
944             43.0000000000,
945             44.0000000000,
946             61.0000000000,
947             51.0000000000,
948             53.0000000000,
949             59.0000000000,
950             52.0000000000,
951             49.0000000000,
952             51.0000000000,
953             51.0000000000,
954             50.0000000000,
955             49.0000000000,
956             56.0000000000,
957             42.0000000000,
958             52.0000000000,
959             51.0000000000,
960             43.0000000000,
961             48.0000000000,
962             48.0000000000,
963             50.0000000000,
964             42.0000000000,
965             43.0000000000,
966             42.0000000000,
967             60.0000000000,
968         ];
969         let summ = &Summary {
970             sum: 1235.0000000000,
971             min: 42.0000000000,
972             max: 61.0000000000,
973             mean: 49.4000000000,
974             median: 50.0000000000,
975             var: 31.6666666667,
976             std_dev: 5.6273143387,
977             std_dev_pct: 11.3913245723,
978             median_abs_dev: 4.4478000000,
979             median_abs_dev_pct: 8.8956000000,
980             quartiles: (44.0000000000,50.0000000000,52.0000000000),
981             iqr: 8.0000000000,
982         };
983         check(val, summ);
984     }
985     #[test]
986     fn test_unif25() {
987         let val = &[
988             99.0000000000,
989             55.0000000000,
990             92.0000000000,
991             79.0000000000,
992             14.0000000000,
993             2.0000000000,
994             33.0000000000,
995             49.0000000000,
996             3.0000000000,
997             32.0000000000,
998             84.0000000000,
999             59.0000000000,
1000             22.0000000000,
1001             86.0000000000,
1002             76.0000000000,
1003             31.0000000000,
1004             29.0000000000,
1005             11.0000000000,
1006             41.0000000000,
1007             53.0000000000,
1008             45.0000000000,
1009             44.0000000000,
1010             98.0000000000,
1011             98.0000000000,
1012             7.0000000000,
1013         ];
1014         let summ = &Summary {
1015             sum: 1242.0000000000,
1016             min: 2.0000000000,
1017             max: 99.0000000000,
1018             mean: 49.6800000000,
1019             median: 45.0000000000,
1020             var: 1015.6433333333,
1021             std_dev: 31.8691595957,
1022             std_dev_pct: 64.1488719719,
1023             median_abs_dev: 45.9606000000,
1024             median_abs_dev_pct: 102.1346666667,
1025             quartiles: (29.0000000000,45.0000000000,79.0000000000),
1026             iqr: 50.0000000000,
1027         };
1028         check(val, summ);
1029     }
1030
1031     #[test]
1032     fn test_boxplot_nonpositive() {
1033         fn t(s: &Summary<f64>, expected: String) {
1034             let mut m = Vec::new();
1035             write_boxplot(&mut m, s, 30).unwrap();
1036             let out = String::from_utf8(m).unwrap();
1037             assert_eq!(out, expected);
1038         }
1039
1040         t(&Summary::new(&[-2.0f64, -1.0f64]),
1041                         "-2 |[------******#*****---]| -1".to_string());
1042         t(&Summary::new(&[0.0f64, 2.0f64]),
1043                         "0 |[-------*****#*******---]| 2".to_string());
1044         t(&Summary::new(&[-2.0f64, 0.0f64]),
1045                         "-2 |[------******#******---]| 0".to_string());
1046
1047     }
1048     #[test]
1049     fn test_sum_f64s() {
1050         assert_eq!([0.5f64, 3.2321f64, 1.5678f64].sum(), 5.2999);
1051     }
1052     #[test]
1053     fn test_sum_f64_between_ints_that_sum_to_0() {
1054         assert_eq!([1e30f64, 1.2f64, -1e30f64].sum(), 1.2);
1055     }
1056 }
1057
1058 #[cfg(test)]
1059 mod bench {
1060     use Bencher;
1061     use stats::Stats;
1062
1063     #[bench]
1064     pub fn sum_three_items(b: &mut Bencher) {
1065         b.iter(|| {
1066             [1e20f64, 1.5f64, -1e20f64].sum();
1067         })
1068     }
1069     #[bench]
1070     pub fn sum_many_f64(b: &mut Bencher) {
1071         let nums = [-1e30f64, 1e60, 1e30, 1.0, -1e60];
1072         let v = range(0, 500).map(|i| nums[i%5]).collect::<Vec<_>>();
1073
1074         b.iter(|| {
1075             v.as_slice().sum();
1076         })
1077     }
1078 }