/// Assert that two numbers are almost equal to each other. /// /// On panic, this macro will print the values of the expressions with their /// debug representations. #[macro_export] macro_rules! assert_almost_eq { ($a:expr, $b:expr, $prec:expr) => ( let diff = ($a - $b).abs(); if diff > $prec { panic!(format!( "assertion failed: `abs(left - right) = {:.1e} < {:e}`, \ (left: `{}`, right: `{}`)", diff, $prec, $a, $b)); } ); } /// Concatenate several iterative estimators into one. /// /// `$name` is the name of the new struct. `$statistic` is the name of a /// statistic and must exist as a method of the corresponding type `$estimator`. /// `$estimator` must have an `add` method for adding new observations to the /// sample (taking an `f64` as an argument). It must also implement `Default`. /// /// If the short syntax is used, the fields will be named `$statistic`. Use the /// long syntax and `$field` to give them explicit names. The long syntax also /// supports calculating several statistics from one estimator. /// /// For moments, only an estimator for the highest moment should be used and /// reused for the lower moments (see the example below). /// /// The following methods will be implemented: `new`, `add`, `$statistic`. /// /// The following traits will be implemented: `Default`, `FromIterator`. /// /// /// # Examples /// /// ``` /// use average::{Min, Max, Estimate, concatenate}; /// /// concatenate!(MinMax, [Min, min], [Max, max]); /// /// let s: MinMax = (1..6).map(f64::from).collect(); /// /// assert_eq!(s.min(), 1.0); /// assert_eq!(s.max(), 5.0); /// ``` /// /// The generated code looks roughly like this: /// /// ``` /// # use average::{Min, Max, Estimate}; /// # /// struct MinMax { /// min: Min, /// max: Max, /// } /// /// impl MinMax { /// pub fn new() -> MinMax { /// MinMax { min: Min::default(), max: Max::default() } /// } /// /// pub fn add(&mut self, x: f64) { /// self.min.add(x); /// self.max.add(x); /// } /// /// pub fn min(&self) -> f64 { /// self.min.min() /// } /// /// pub fn max(&self) -> f64 { /// self.max.max() /// } /// } /// ``` /// /// If you want to calculate the mean, variance and the median in one pass, you /// can do the following: /// /// ``` /// use average::{Variance1, Quantile, Estimate, concatenate}; /// /// concatenate!(Estimator, /// [Variance1, variance, mean, sample_variance], /// [Quantile, quantile, quantile]); /// ``` #[macro_export] macro_rules! concatenate { ( $name:ident, $([$estimator:ident, $statistic:ident]),+ ) => { concatenate!( $name, $([$estimator, $statistic, $statistic]),* ); }; ( $name:ident, $( [$estimator:ident, $field:ident, $($statistic:ident),+] ),+ ) => { struct $name { $( $field: $estimator, )* } impl $name { #[inline] pub fn new() -> $name { $name { $( $field: ::core::default::Default::default(), )* } } #[inline] pub fn add(&mut self, x: f64) { $( self.$field.add(x); )* } $( $( #[inline] pub fn $statistic(&self) -> f64 { self.$field.$statistic() } )* )* } impl Default for $name { fn default() -> $name { $name::new() } } $crate::impl_from_iterator!($name); }; } /// Implement `FromIterator` for an iterative estimator. #[macro_export] macro_rules! impl_from_iterator { ( $name:ident ) => { impl ::core::iter::FromIterator for $name { fn from_iter(iter: T) -> $name where T: IntoIterator { let mut e = $name::new(); for i in iter { e.add(i); } e } } impl<'a> ::core::iter::FromIterator<&'a f64> for $name { fn from_iter(iter: T) -> $name where T: IntoIterator { let mut e = $name::new(); for &i in iter { e.add(i); } e } } }; }