russell_stat 1.13.0

Statistics calculations and (engineering) probability distributions
Documentation
use crate::{ProbabilityDistribution, StrError};
use rand::Rng;
use rand_distr::{Distribution, Normal};
use russell_lab::math::{erf, SQRT_2, SQRT_PI};

/// Implements the Normal distribution
///
/// See: <https://en.wikipedia.org/wiki/Normal_distribution>
///
/// ![Normal](https://raw.githubusercontent.com/cpmech/russell/main/russell_stat/data/figures/plot_distribution_functions_normal.svg)
pub struct DistributionNormal {
    mu: f64,  // μ: mean
    sig: f64, // σ: standard deviation
    a: f64,   // 1 / (σ sqrt(2 π))
    b: f64,   // -1 / (2 σ²)

    sampler: Normal<f64>, // sampler
}

impl DistributionNormal {
    /// Allocates a new instance
    ///
    /// # Input
    ///
    /// * `mu` -- mean μ
    /// * `sig` -- standard deviation σ
    pub fn new(mu: f64, sig: f64) -> Result<Self, StrError> {
        Ok(DistributionNormal {
            mu,
            sig,
            a: 1.0 / (sig * SQRT_2 * SQRT_PI),
            b: -1.0 / (2.0 * sig * sig),
            sampler: Normal::new(mu, sig).map_err(|_| "invalid parameters")?,
        })
    }
}

impl ProbabilityDistribution for DistributionNormal {
    /// Evaluates the Probability Density Function (PDF)
    ///
    /// # Examples
    ///
    /// ```
    /// use russell_lab::approx_eq;
    /// use russell_stat::*;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     let dist = DistributionNormal::new(0.1, 0.9)?;
    ///     approx_eq(dist.pdf(1.0), 0.268856360576826, 1e-15);
    ///     Ok(())
    /// }
    /// ```
    fn pdf(&self, x: f64) -> f64 {
        self.a * f64::exp(self.b * f64::powf(x - self.mu, 2.0))
    }

    /// Evaluates the Cumulative Distribution Function (CDF)
    ///
    /// # Examples
    ///
    /// ```
    /// use russell_lab::approx_eq;
    /// use russell_stat::*;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     let dist = DistributionNormal::new(0.1, 0.9)?;
    ///     approx_eq(dist.cdf(1.0), 0.841344746068543, 1e-15);
    ///     Ok(())
    /// }
    /// ```
    fn cdf(&self, x: f64) -> f64 {
        (1.0 + erf((x - self.mu) / (self.sig * SQRT_2))) / 2.0
    }

    /// Returns the Mean
    ///
    /// # Examples
    ///
    /// ```
    /// use russell_stat::*;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     let dist = DistributionNormal::new(0.1, 0.9)?;
    ///     assert_eq!(dist.mean(), 0.1);
    ///     Ok(())
    /// }
    /// ```
    fn mean(&self) -> f64 {
        self.mu
    }

    /// Returns the Variance
    ///
    /// # Examples
    ///
    /// ```
    /// use russell_stat::*;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     let dist = DistributionNormal::new(0.1, 0.9)?;
    ///     assert_eq!(dist.variance(), 0.9 * 0.9);
    ///     Ok(())
    /// }
    /// ```
    fn variance(&self) -> f64 {
        self.sig * self.sig
    }

    /// Generates a pseudo-random number belonging to this probability distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use russell_stat::*;
    ///
    /// fn main() -> Result<(), StrError> {
    ///     let dist = DistributionNormal::new(0.1, 0.9)?;
    ///     let mut rng = get_rng();
    ///     println!("sample = {}", dist.sample(&mut rng));
    ///     Ok(())
    /// }
    /// ```
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
        self.sampler.sample(rng)
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use crate::{get_rng, DistributionNormal, ProbabilityDistribution};
    use russell_lab::approx_eq;

    // Data from the following R-code (run with Rscript normal.R):
    /*
    X <- seq(-4, 4, 0.5)
    M <- c(-0.5, 0, 1)
    S <- c(0.25, 0.5, 1)
    Y <- matrix(ncol=4)
    first <- TRUE
    for (mu in M) {
        for (sig in S) {
            pdf <- dnorm(X, mu, sig)
            cdf <- pnorm(X, mu, sig)
            for (i in 1:length(X)) {
                if (first) {
                    Y <- rbind(c(X[i], mu, sig, pdf[i], cdf[i]))
                    first <- FALSE
                } else {
                    Y <- rbind(Y, c(X[i], mu, sig, pdf[i], cdf[i]))
                }
            }
        }
    }
    write.table(format(Y, digits=15), "/tmp/normal.dat", row.names=FALSE, col.names=c("x","mu","sig","pdf","cdf"), quote=FALSE)
    print("file </tmp/normal.dat> written")
    */

    #[test]
    fn normal_handles_errors() {
        assert_eq!(
            DistributionNormal::new(2.0, f64::INFINITY).err(),
            Some("invalid parameters")
        );
    }

    #[test]
    fn normal_works() {
        #[rustfmt::skip]
        // x, mu, sig, pdf, cdf
        let data = [
            [-4.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 4.38642623755589e-43, 7.79353681919280e-45],
            [-3.50000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 8.58553494265224e-32, 1.77648211207768e-33],
            [-3.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 3.07783945068257e-22, 7.61985302416053e-24],
            [-2.50000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 2.02090843341476e-14, 6.22096057427178e-16],
            [-2.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 2.43035313992931e-08, 9.86587645037698e-10],
            [-1.50000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 5.35320903059541e-04, 3.16712418331199e-05],
            [-1.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 2.15963866052752e-01, 2.27501319481792e-02],
            [-5.00000000000000e-01, -5.00000000000000e-01, 2.50000000000000e-01, 1.59576912160573e+00, 5.00000000000000e-01],
            [ 0.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 2.15963866052752e-01, 9.77249868051821e-01],
            [ 5.00000000000000e-01, -5.00000000000000e-01, 2.50000000000000e-01, 5.35320903059541e-04, 9.99968328758167e-01],
            [ 1.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 2.43035313992931e-08, 9.99999999013412e-01],
            [ 1.50000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 2.02090843341476e-14, 9.99999999999999e-01],
            [ 2.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 3.07783945068257e-22, 1.00000000000000e+00],
            [ 2.50000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 8.58553494265224e-32, 1.00000000000000e+00],
            [ 3.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 4.38642623755589e-43, 1.00000000000000e+00],
            [ 3.50000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 4.10465229116761e-56, 1.00000000000000e+00],
            [ 4.00000000000000e+00, -5.00000000000000e-01, 2.50000000000000e-01, 7.03499817038042e-71, 1.00000000000000e+00],
            [-4.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 1.82694408167292e-11, 1.27981254388584e-12],
            [-3.50000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 1.21517656996466e-08, 9.86587645037698e-10],
            [-3.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 2.97343902946860e-06, 2.86651571879194e-07],
            [-2.50000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 2.67660451529771e-04, 3.16712418331199e-05],
            [-2.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 8.86369682387602e-03, 1.34989803163009e-03],
            [-1.50000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 1.07981933026376e-01, 2.27501319481792e-02],
            [-1.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 4.83941449038287e-01, 1.58655253931457e-01],
            [-5.00000000000000e-01, -5.00000000000000e-01, 5.00000000000000e-01, 7.97884560802865e-01, 5.00000000000000e-01],
            [ 0.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 4.83941449038287e-01, 8.41344746068543e-01],
            [ 5.00000000000000e-01, -5.00000000000000e-01, 5.00000000000000e-01, 1.07981933026376e-01, 9.77249868051821e-01],
            [ 1.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 8.86369682387602e-03, 9.98650101968370e-01],
            [ 1.50000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 2.67660451529771e-04, 9.99968328758167e-01],
            [ 2.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 2.97343902946860e-06, 9.99999713348428e-01],
            [ 2.50000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 1.21517656996466e-08, 9.99999999013412e-01],
            [ 3.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 1.82694408167292e-11, 9.99999999998720e-01],
            [ 3.50000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 1.01045421670738e-14, 9.99999999999999e-01],
            [ 4.00000000000000e+00, -5.00000000000000e-01, 5.00000000000000e-01, 2.05595471433378e-18, 1.00000000000000e+00],
            [-4.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 8.72682695045760e-04, 2.32629079035525e-04],
            [-3.50000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 4.43184841193801e-03, 1.34989803163009e-03],
            [-3.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 1.75283004935685e-02, 6.20966532577613e-03],
            [-2.50000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 5.39909665131881e-02, 2.27501319481792e-02],
            [-2.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 1.29517595665892e-01, 6.68072012688581e-02],
            [-1.50000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 2.41970724519143e-01, 1.58655253931457e-01],
            [-1.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 3.52065326764300e-01, 3.08537538725987e-01],
            [-5.00000000000000e-01, -5.00000000000000e-01, 1.00000000000000e+00, 3.98942280401433e-01, 5.00000000000000e-01],
            [ 0.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 3.52065326764300e-01, 6.91462461274013e-01],
            [ 5.00000000000000e-01, -5.00000000000000e-01, 1.00000000000000e+00, 2.41970724519143e-01, 8.41344746068543e-01],
            [ 1.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 1.29517595665892e-01, 9.33192798731142e-01],
            [ 1.50000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 5.39909665131881e-02, 9.77249868051821e-01],
            [ 2.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 1.75283004935685e-02, 9.93790334674224e-01],
            [ 2.50000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 4.43184841193801e-03, 9.98650101968370e-01],
            [ 3.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 8.72682695045760e-04, 9.99767370920964e-01],
            [ 3.50000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 1.33830225764885e-04, 9.99968328758167e-01],
            [ 4.00000000000000e+00, -5.00000000000000e-01, 1.00000000000000e+00, 1.59837411069055e-05, 9.99996602326875e-01],
            [-4.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 4.10465229116761e-56, 6.38875440053809e-58],
            [-3.50000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 4.38642623755589e-43, 7.79353681919280e-45],
            [-3.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 8.58553494265224e-32, 1.77648211207768e-33],
            [-2.50000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 3.07783945068257e-22, 7.61985302416053e-24],
            [-2.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 2.02090843341476e-14, 6.22096057427178e-16],
            [-1.50000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 2.43035313992931e-08, 9.86587645037698e-10],
            [-1.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 5.35320903059541e-04, 3.16712418331199e-05],
            [-5.00000000000000e-01,  0.00000000000000e+00, 2.50000000000000e-01, 2.15963866052752e-01, 2.27501319481792e-02],
            [ 0.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 1.59576912160573e+00, 5.00000000000000e-01],
            [ 5.00000000000000e-01,  0.00000000000000e+00, 2.50000000000000e-01, 2.15963866052752e-01, 9.77249868051821e-01],
            [ 1.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 5.35320903059541e-04, 9.99968328758167e-01],
            [ 1.50000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 2.43035313992931e-08, 9.99999999013412e-01],
            [ 2.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 2.02090843341476e-14, 9.99999999999999e-01],
            [ 2.50000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 3.07783945068257e-22, 1.00000000000000e+00],
            [ 3.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 8.58553494265224e-32, 1.00000000000000e+00],
            [ 3.50000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 4.38642623755589e-43, 1.00000000000000e+00],
            [ 4.00000000000000e+00,  0.00000000000000e+00, 2.50000000000000e-01, 4.10465229116761e-56, 1.00000000000000e+00],
            [-4.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.01045421670738e-14, 6.22096057427178e-16],
            [-3.50000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.82694408167292e-11, 1.27981254388584e-12],
            [-3.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.21517656996466e-08, 9.86587645037698e-10],
            [-2.50000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 2.97343902946860e-06, 2.86651571879194e-07],
            [-2.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 2.67660451529771e-04, 3.16712418331199e-05],
            [-1.50000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 8.86369682387602e-03, 1.34989803163009e-03],
            [-1.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.07981933026376e-01, 2.27501319481792e-02],
            [-5.00000000000000e-01,  0.00000000000000e+00, 5.00000000000000e-01, 4.83941449038287e-01, 1.58655253931457e-01],
            [ 0.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 7.97884560802865e-01, 5.00000000000000e-01],
            [ 5.00000000000000e-01,  0.00000000000000e+00, 5.00000000000000e-01, 4.83941449038287e-01, 8.41344746068543e-01],
            [ 1.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.07981933026376e-01, 9.77249868051821e-01],
            [ 1.50000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 8.86369682387602e-03, 9.98650101968370e-01],
            [ 2.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 2.67660451529771e-04, 9.99968328758167e-01],
            [ 2.50000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 2.97343902946860e-06, 9.99999713348428e-01],
            [ 3.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.21517656996466e-08, 9.99999999013412e-01],
            [ 3.50000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.82694408167292e-11, 9.99999999998720e-01],
            [ 4.00000000000000e+00,  0.00000000000000e+00, 5.00000000000000e-01, 1.01045421670738e-14, 9.99999999999999e-01],
            [-4.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 1.33830225764885e-04, 3.16712418331199e-05],
            [-3.50000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 8.72682695045760e-04, 2.32629079035525e-04],
            [-3.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 4.43184841193801e-03, 1.34989803163009e-03],
            [-2.50000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 1.75283004935685e-02, 6.20966532577613e-03],
            [-2.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 5.39909665131881e-02, 2.27501319481792e-02],
            [-1.50000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 1.29517595665892e-01, 6.68072012688581e-02],
            [-1.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 2.41970724519143e-01, 1.58655253931457e-01],
            [-5.00000000000000e-01,  0.00000000000000e+00, 1.00000000000000e+00, 3.52065326764300e-01, 3.08537538725987e-01],
            [ 0.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 3.98942280401433e-01, 5.00000000000000e-01],
            [ 5.00000000000000e-01,  0.00000000000000e+00, 1.00000000000000e+00, 3.52065326764300e-01, 6.91462461274013e-01],
            [ 1.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 2.41970724519143e-01, 8.41344746068543e-01],
            [ 1.50000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 1.29517595665892e-01, 9.33192798731142e-01],
            [ 2.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 5.39909665131881e-02, 9.77249868051821e-01],
            [ 2.50000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 1.75283004935685e-02, 9.93790334674224e-01],
            [ 3.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 4.43184841193801e-03, 9.98650101968370e-01],
            [ 3.50000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 8.72682695045760e-04, 9.99767370920964e-01],
            [ 4.00000000000000e+00,  0.00000000000000e+00, 1.00000000000000e+00, 1.33830225764885e-04, 9.99968328758167e-01],
            [-4.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 2.20837934486391e-87, 2.75362411860623e-89],
            [-3.50000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 7.03499817038042e-71, 9.74094891893715e-73],
            [-3.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 4.10465229116761e-56, 6.38875440053809e-58],
            [-2.50000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 4.38642623755589e-43, 7.79353681919280e-45],
            [-2.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 8.58553494265224e-32, 1.77648211207768e-33],
            [-1.50000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 3.07783945068257e-22, 7.61985302416053e-24],
            [-1.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 2.02090843341476e-14, 6.22096057427178e-16],
            [-5.00000000000000e-01,  1.00000000000000e+00, 2.50000000000000e-01, 2.43035313992931e-08, 9.86587645037698e-10],
            [ 0.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 5.35320903059541e-04, 3.16712418331199e-05],
            [ 5.00000000000000e-01,  1.00000000000000e+00, 2.50000000000000e-01, 2.15963866052752e-01, 2.27501319481792e-02],
            [ 1.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 1.59576912160573e+00, 5.00000000000000e-01],
            [ 1.50000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 2.15963866052752e-01, 9.77249868051821e-01],
            [ 2.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 5.35320903059541e-04, 9.99968328758167e-01],
            [ 2.50000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 2.43035313992931e-08, 9.99999999013412e-01],
            [ 3.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 2.02090843341476e-14, 9.99999999999999e-01],
            [ 3.50000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 3.07783945068257e-22, 1.00000000000000e+00],
            [ 4.00000000000000e+00,  1.00000000000000e+00, 2.50000000000000e-01, 8.58553494265224e-32, 1.00000000000000e+00],
            [-4.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 1.53891972534128e-22, 7.61985302416053e-24],
            [-3.50000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 2.05595471433378e-18, 1.12858840595384e-19],
            [-3.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 1.01045421670738e-14, 6.22096057427178e-16],
            [-2.50000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 1.82694408167292e-11, 1.27981254388584e-12],
            [-2.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 1.21517656996466e-08, 9.86587645037698e-10],
            [-1.50000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 2.97343902946860e-06, 2.86651571879194e-07],
            [-1.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 2.67660451529771e-04, 3.16712418331199e-05],
            [-5.00000000000000e-01,  1.00000000000000e+00, 5.00000000000000e-01, 8.86369682387602e-03, 1.34989803163009e-03],
            [ 0.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 1.07981933026376e-01, 2.27501319481792e-02],
            [ 5.00000000000000e-01,  1.00000000000000e+00, 5.00000000000000e-01, 4.83941449038287e-01, 1.58655253931457e-01],
            [ 1.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 7.97884560802865e-01, 5.00000000000000e-01],
            [ 1.50000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 4.83941449038287e-01, 8.41344746068543e-01],
            [ 2.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 1.07981933026376e-01, 9.77249868051821e-01],
            [ 2.50000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 8.86369682387602e-03, 9.98650101968370e-01],
            [ 3.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 2.67660451529771e-04, 9.99968328758167e-01],
            [ 3.50000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 2.97343902946860e-06, 9.99999713348428e-01],
            [ 4.00000000000000e+00,  1.00000000000000e+00, 5.00000000000000e-01, 1.21517656996466e-08, 9.99999999013412e-01],
            [-4.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 1.48671951473430e-06, 2.86651571879194e-07],
            [-3.50000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 1.59837411069055e-05, 3.39767312473006e-06],
            [-3.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 1.33830225764885e-04, 3.16712418331199e-05],
            [-2.50000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 8.72682695045760e-04, 2.32629079035525e-04],
            [-2.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 4.43184841193801e-03, 1.34989803163009e-03],
            [-1.50000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 1.75283004935685e-02, 6.20966532577613e-03],
            [-1.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 5.39909665131881e-02, 2.27501319481792e-02],
            [-5.00000000000000e-01,  1.00000000000000e+00, 1.00000000000000e+00, 1.29517595665892e-01, 6.68072012688581e-02],
            [ 0.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 2.41970724519143e-01, 1.58655253931457e-01],
            [ 5.00000000000000e-01,  1.00000000000000e+00, 1.00000000000000e+00, 3.52065326764300e-01, 3.08537538725987e-01],
            [ 1.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 3.98942280401433e-01, 5.00000000000000e-01],
            [ 1.50000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 3.52065326764300e-01, 6.91462461274013e-01],
            [ 2.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 2.41970724519143e-01, 8.41344746068543e-01],
            [ 2.50000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 1.29517595665892e-01, 9.33192798731142e-01],
            [ 3.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 5.39909665131881e-02, 9.77249868051821e-01],
            [ 3.50000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 1.75283004935685e-02, 9.93790334674224e-01],
            [ 4.00000000000000e+00,  1.00000000000000e+00, 1.00000000000000e+00, 4.43184841193801e-03, 9.98650101968370e-01],
        ];
        for row in data {
            let [x, mu, sig, pdf, cdf] = row;
            let d = DistributionNormal::new(mu, sig).unwrap();
            approx_eq(d.pdf(x), pdf, 1e-14);
            approx_eq(d.cdf(x), cdf, 1e-14);
        }
    }

    #[test]
    fn mean_and_variance_work() {
        let (mu, sig) = (1.0, 0.25);
        let d = DistributionNormal::new(mu, sig).unwrap();
        approx_eq(d.mean(), mu, 1e-14);
        approx_eq(d.variance(), sig * sig, 1e-14);
    }

    #[test]
    fn sample_works() {
        let d = DistributionNormal::new(1.0, 2.0).unwrap();
        let mut rng = get_rng();
        d.sample(&mut rng);
    }
}