Fixes to Histogram
1. Now histograms with more than 31 bins are supported (before there were issues with missing implementations on arrays.) 2. The items defined by `define_histogram!` are in their own module, to avoid issues with Rust's lack of macro hygiene for items.
This commit is contained in:
parent
b010d0cae6
commit
56344750a7
@ -1,13 +1,20 @@
|
|||||||
/// Define a histogram with a number of bins known at compile time.
|
/// Define a histogram with a number of bins known at compile time.
|
||||||
///
|
///
|
||||||
|
/// Because macros are not hygenic for items, everything is defined in a private
|
||||||
|
/// module with the given name. This includes the `Histogram` struct, the number
|
||||||
|
/// of bins `LEN` and the histogram iterator `HistogramIter`.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # extern crate core;
|
/// # extern crate core;
|
||||||
/// # #[macro_use] extern crate average;
|
/// # #[macro_use] extern crate average;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// use average::Histogram;
|
/// use average::Histogram;
|
||||||
///
|
///
|
||||||
/// define_histogram!(Histogram10, 10);
|
/// define_histogram!(hist, 10);
|
||||||
/// let mut h = Histogram10::with_const_width(0., 100.);
|
/// let mut h = hist::Histogram::with_const_width(0., 100.);
|
||||||
/// for i in 0..100 {
|
/// for i in 0..100 {
|
||||||
/// h.add(i as f64).unwrap();
|
/// h.add(i as f64).unwrap();
|
||||||
/// }
|
/// }
|
||||||
@ -17,19 +24,33 @@
|
|||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! define_histogram {
|
macro_rules! define_histogram {
|
||||||
($name:ident, $LEN:expr) => (
|
($name:ident, $LEN:expr) => (
|
||||||
|
mod $name {
|
||||||
|
use $crate::Histogram as Trait;
|
||||||
|
|
||||||
/// The number of bins of the histogram.
|
/// The number of bins of the histogram.
|
||||||
const LEN: usize = $LEN;
|
const LEN: usize = $LEN;
|
||||||
|
|
||||||
/// A histogram with a number of bins known at compile time.
|
/// A histogram with a number of bins known at compile time.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct $name {
|
pub struct Histogram {
|
||||||
/// The ranges defining the bins of the histogram.
|
/// The ranges defining the bins of the histogram.
|
||||||
range: [f64; LEN + 1],
|
range: [f64; LEN + 1],
|
||||||
/// The bins of the histogram.
|
/// The bins of the histogram.
|
||||||
bin: [u64; LEN],
|
bin: [u64; LEN],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $name {
|
impl ::core::fmt::Debug for Histogram {
|
||||||
|
fn fmt(&self, formatter: &mut ::core::fmt::Formatter)
|
||||||
|
-> ::core::fmt::Result {
|
||||||
|
write!(formatter, "Histogram {{ range: ")?;
|
||||||
|
self.range[..].fmt(formatter)?;
|
||||||
|
write!(formatter, ", bins: ")?;
|
||||||
|
self.bin[..].fmt(formatter)?;
|
||||||
|
write!(formatter, " }}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Histogram {
|
||||||
/// Construct a histogram with constant bin width.
|
/// Construct a histogram with constant bin width.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn with_const_width(start: f64, end: f64) -> Self {
|
pub fn with_const_width(start: f64, end: f64) -> Self {
|
||||||
@ -170,7 +191,7 @@ macro_rules! define_histogram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::core::iter::IntoIterator for &'a $name {
|
impl<'a> ::core::iter::IntoIterator for &'a Histogram {
|
||||||
type Item = ((f64, f64), u64);
|
type Item = ((f64, f64), u64);
|
||||||
type IntoIter = IterHistogram<'a>;
|
type IntoIter = IterHistogram<'a>;
|
||||||
fn into_iter(self) -> IterHistogram<'a> {
|
fn into_iter(self) -> IterHistogram<'a> {
|
||||||
@ -181,24 +202,26 @@ macro_rules! define_histogram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::Histogram for $name {
|
impl $crate::Histogram for Histogram {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bins(&self) -> &[u64] {
|
fn bins(&self) -> &[u64] {
|
||||||
&self.bin as &[u64]
|
&self.bin as &[u64]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ::core::ops::AddAssign<&'a Self> for $name {
|
impl<'a> ::core::ops::AddAssign<&'a Self> for Histogram {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_assign(&mut self, other: &Self) {
|
fn add_assign(&mut self, other: &Self) {
|
||||||
assert_eq!(self.range, other.range);
|
for (a, b) in self.range.iter().zip(other.range.iter()) {
|
||||||
|
assert_eq!(a, b, "Both histograms must have the same ranges");
|
||||||
|
}
|
||||||
for (x, y) in self.bin.iter_mut().zip(other.bin.iter()) {
|
for (x, y) in self.bin.iter_mut().zip(other.bin.iter()) {
|
||||||
*x += y;
|
*x += y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::core::ops::MulAssign<u64> for $name {
|
impl ::core::ops::MulAssign<u64> for Histogram {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul_assign(&mut self, other: u64) {
|
fn mul_assign(&mut self, other: u64) {
|
||||||
for x in self.bin.iter_mut() {
|
for x in self.bin.iter_mut() {
|
||||||
@ -207,7 +230,7 @@ macro_rules! define_histogram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl $crate::Merge for $name {
|
impl $crate::Merge for Histogram {
|
||||||
fn merge(&mut self, other: &Self) {
|
fn merge(&mut self, other: &Self) {
|
||||||
assert_eq!(self.bin.len(), other.bin.len());
|
assert_eq!(self.bin.len(), other.bin.len());
|
||||||
for (a, b) in self.range.iter().zip(other.range.iter()) {
|
for (a, b) in self.range.iter().zip(other.range.iter()) {
|
||||||
@ -218,5 +241,6 @@ macro_rules! define_histogram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
//!
|
//!
|
||||||
//! The [`define_histogram`] macro can be used to define a histogram struct that
|
//! The [`define_histogram`] macro can be used to define a histogram struct that
|
||||||
//! uses constant memory. See [`Histogram10`] (defined using
|
//! uses constant memory. See [`Histogram10`] (defined using
|
||||||
//! `define_histogram!(Histogram10, 10)`) and the extension trait [`Histogram`]
|
//! `define_histogram!(..., 10)`) and the extension trait [`Histogram`]
|
||||||
//! for the methods available to the generated struct.
|
//! for the methods available to the generated struct.
|
||||||
//!
|
//!
|
||||||
//!
|
//!
|
||||||
@ -110,5 +110,6 @@ pub use minmax::{Min, Max};
|
|||||||
pub use quantile::Quantile;
|
pub use quantile::Quantile;
|
||||||
pub use traits::{Estimate, Merge, Histogram};
|
pub use traits::{Estimate, Merge, Histogram};
|
||||||
|
|
||||||
define_histogram!(Histogram10, 10);
|
define_histogram!(hist, 10);
|
||||||
|
pub use hist::Histogram as Histogram10;
|
||||||
define_moments!(Moments4, 4);
|
define_moments!(Moments4, 4);
|
||||||
|
@ -9,7 +9,10 @@ use rand::FromEntropy;
|
|||||||
|
|
||||||
use average::{Histogram, Merge};
|
use average::{Histogram, Merge};
|
||||||
|
|
||||||
define_histogram!(Histogram10, 10);
|
define_histogram!(hist10, 10);
|
||||||
|
define_histogram!(hist100, 100);
|
||||||
|
|
||||||
|
use hist10::Histogram as Histogram10;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn with_const_width() {
|
fn with_const_width() {
|
||||||
|
Loading…
Reference in New Issue
Block a user