NormalDistribution.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.math3.distribution;

  18. import org.apache.commons.math3.exception.NotStrictlyPositiveException;
  19. import org.apache.commons.math3.exception.NumberIsTooLargeException;
  20. import org.apache.commons.math3.exception.OutOfRangeException;
  21. import org.apache.commons.math3.exception.util.LocalizedFormats;
  22. import org.apache.commons.math3.random.RandomGenerator;
  23. import org.apache.commons.math3.random.Well19937c;
  24. import org.apache.commons.math3.special.Erf;
  25. import org.apache.commons.math3.util.FastMath;

  26. /**
  27.  * Implementation of the normal (gaussian) distribution.
  28.  *
  29.  * @see <a href="http://en.wikipedia.org/wiki/Normal_distribution">Normal distribution (Wikipedia)</a>
  30.  * @see <a href="http://mathworld.wolfram.com/NormalDistribution.html">Normal distribution (MathWorld)</a>
  31.  */
  32. public class NormalDistribution extends AbstractRealDistribution {
  33.     /**
  34.      * Default inverse cumulative probability accuracy.
  35.      * @since 2.1
  36.      */
  37.     public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
  38.     /** Serializable version identifier. */
  39.     private static final long serialVersionUID = 8589540077390120676L;
  40.     /** &radic;(2) */
  41.     private static final double SQRT2 = FastMath.sqrt(2.0);
  42.     /** Mean of this distribution. */
  43.     private final double mean;
  44.     /** Standard deviation of this distribution. */
  45.     private final double standardDeviation;
  46.     /** The value of {@code log(sd) + 0.5*log(2*pi)} stored for faster computation. */
  47.     private final double logStandardDeviationPlusHalfLog2Pi;
  48.     /** Inverse cumulative probability accuracy. */
  49.     private final double solverAbsoluteAccuracy;

  50.     /**
  51.      * Create a normal distribution with mean equal to zero and standard
  52.      * deviation equal to one.
  53.      * <p>
  54.      * <b>Note:</b> this constructor will implicitly create an instance of
  55.      * {@link Well19937c} as random generator to be used for sampling only (see
  56.      * {@link #sample()} and {@link #sample(int)}). In case no sampling is
  57.      * needed for the created distribution, it is advised to pass {@code null}
  58.      * as random generator via the appropriate constructors to avoid the
  59.      * additional initialisation overhead.
  60.      */
  61.     public NormalDistribution() {
  62.         this(0, 1);
  63.     }

  64.     /**
  65.      * Create a normal distribution using the given mean and standard deviation.
  66.      * <p>
  67.      * <b>Note:</b> this constructor will implicitly create an instance of
  68.      * {@link Well19937c} as random generator to be used for sampling only (see
  69.      * {@link #sample()} and {@link #sample(int)}). In case no sampling is
  70.      * needed for the created distribution, it is advised to pass {@code null}
  71.      * as random generator via the appropriate constructors to avoid the
  72.      * additional initialisation overhead.
  73.      *
  74.      * @param mean Mean for this distribution.
  75.      * @param sd Standard deviation for this distribution.
  76.      * @throws NotStrictlyPositiveException if {@code sd <= 0}.
  77.      */
  78.     public NormalDistribution(double mean, double sd)
  79.         throws NotStrictlyPositiveException {
  80.         this(mean, sd, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
  81.     }

  82.     /**
  83.      * Create a normal distribution using the given mean, standard deviation and
  84.      * inverse cumulative distribution accuracy.
  85.      * <p>
  86.      * <b>Note:</b> this constructor will implicitly create an instance of
  87.      * {@link Well19937c} as random generator to be used for sampling only (see
  88.      * {@link #sample()} and {@link #sample(int)}). In case no sampling is
  89.      * needed for the created distribution, it is advised to pass {@code null}
  90.      * as random generator via the appropriate constructors to avoid the
  91.      * additional initialisation overhead.
  92.      *
  93.      * @param mean Mean for this distribution.
  94.      * @param sd Standard deviation for this distribution.
  95.      * @param inverseCumAccuracy Inverse cumulative probability accuracy.
  96.      * @throws NotStrictlyPositiveException if {@code sd <= 0}.
  97.      * @since 2.1
  98.      */
  99.     public NormalDistribution(double mean, double sd, double inverseCumAccuracy)
  100.         throws NotStrictlyPositiveException {
  101.         this(new Well19937c(), mean, sd, inverseCumAccuracy);
  102.     }

  103.     /**
  104.      * Creates a normal distribution.
  105.      *
  106.      * @param rng Random number generator.
  107.      * @param mean Mean for this distribution.
  108.      * @param sd Standard deviation for this distribution.
  109.      * @throws NotStrictlyPositiveException if {@code sd <= 0}.
  110.      * @since 3.3
  111.      */
  112.     public NormalDistribution(RandomGenerator rng, double mean, double sd)
  113.         throws NotStrictlyPositiveException {
  114.         this(rng, mean, sd, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
  115.     }

  116.     /**
  117.      * Creates a normal distribution.
  118.      *
  119.      * @param rng Random number generator.
  120.      * @param mean Mean for this distribution.
  121.      * @param sd Standard deviation for this distribution.
  122.      * @param inverseCumAccuracy Inverse cumulative probability accuracy.
  123.      * @throws NotStrictlyPositiveException if {@code sd <= 0}.
  124.      * @since 3.1
  125.      */
  126.     public NormalDistribution(RandomGenerator rng,
  127.                               double mean,
  128.                               double sd,
  129.                               double inverseCumAccuracy)
  130.         throws NotStrictlyPositiveException {
  131.         super(rng);

  132.         if (sd <= 0) {
  133.             throw new NotStrictlyPositiveException(LocalizedFormats.STANDARD_DEVIATION, sd);
  134.         }

  135.         this.mean = mean;
  136.         standardDeviation = sd;
  137.         logStandardDeviationPlusHalfLog2Pi = FastMath.log(sd) + 0.5 * FastMath.log(2 * FastMath.PI);
  138.         solverAbsoluteAccuracy = inverseCumAccuracy;
  139.     }

  140.     /**
  141.      * Access the mean.
  142.      *
  143.      * @return the mean for this distribution.
  144.      */
  145.     public double getMean() {
  146.         return mean;
  147.     }

  148.     /**
  149.      * Access the standard deviation.
  150.      *
  151.      * @return the standard deviation for this distribution.
  152.      */
  153.     public double getStandardDeviation() {
  154.         return standardDeviation;
  155.     }

  156.     /** {@inheritDoc} */
  157.     public double density(double x) {
  158.         return FastMath.exp(logDensity(x));
  159.     }

  160.     /** {@inheritDoc} */
  161.     @Override
  162.     public double logDensity(double x) {
  163.         final double x0 = x - mean;
  164.         final double x1 = x0 / standardDeviation;
  165.         return -0.5 * x1 * x1 - logStandardDeviationPlusHalfLog2Pi;
  166.     }

  167.     /**
  168.      * {@inheritDoc}
  169.      *
  170.      * If {@code x} is more than 40 standard deviations from the mean, 0 or 1
  171.      * is returned, as in these cases the actual value is within
  172.      * {@code Double.MIN_VALUE} of 0 or 1.
  173.      */
  174.     public double cumulativeProbability(double x)  {
  175.         final double dev = x - mean;
  176.         if (FastMath.abs(dev) > 40 * standardDeviation) {
  177.             return dev < 0 ? 0.0d : 1.0d;
  178.         }
  179.         return 0.5 * (1 + Erf.erf(dev / (standardDeviation * SQRT2)));
  180.     }

  181.     /** {@inheritDoc}
  182.      * @since 3.2
  183.      */
  184.     @Override
  185.     public double inverseCumulativeProbability(final double p) throws OutOfRangeException {
  186.         if (p < 0.0 || p > 1.0) {
  187.             throw new OutOfRangeException(p, 0, 1);
  188.         }
  189.         return mean + standardDeviation * SQRT2 * Erf.erfInv(2 * p - 1);
  190.     }

  191.     /**
  192.      * {@inheritDoc}
  193.      *
  194.      * @deprecated See {@link RealDistribution#cumulativeProbability(double,double)}
  195.      */
  196.     @Override@Deprecated
  197.     public double cumulativeProbability(double x0, double x1)
  198.         throws NumberIsTooLargeException {
  199.         return probability(x0, x1);
  200.     }

  201.     /** {@inheritDoc} */
  202.     @Override
  203.     public double probability(double x0,
  204.                               double x1)
  205.         throws NumberIsTooLargeException {
  206.         if (x0 > x1) {
  207.             throw new NumberIsTooLargeException(LocalizedFormats.LOWER_ENDPOINT_ABOVE_UPPER_ENDPOINT,
  208.                                                 x0, x1, true);
  209.         }
  210.         final double denom = standardDeviation * SQRT2;
  211.         final double v0 = (x0 - mean) / denom;
  212.         final double v1 = (x1 - mean) / denom;
  213.         return 0.5 * Erf.erf(v0, v1);
  214.     }

  215.     /** {@inheritDoc} */
  216.     @Override
  217.     protected double getSolverAbsoluteAccuracy() {
  218.         return solverAbsoluteAccuracy;
  219.     }

  220.     /**
  221.      * {@inheritDoc}
  222.      *
  223.      * For mean parameter {@code mu}, the mean is {@code mu}.
  224.      */
  225.     public double getNumericalMean() {
  226.         return getMean();
  227.     }

  228.     /**
  229.      * {@inheritDoc}
  230.      *
  231.      * For standard deviation parameter {@code s}, the variance is {@code s^2}.
  232.      */
  233.     public double getNumericalVariance() {
  234.         final double s = getStandardDeviation();
  235.         return s * s;
  236.     }

  237.     /**
  238.      * {@inheritDoc}
  239.      *
  240.      * The lower bound of the support is always negative infinity
  241.      * no matter the parameters.
  242.      *
  243.      * @return lower bound of the support (always
  244.      * {@code Double.NEGATIVE_INFINITY})
  245.      */
  246.     public double getSupportLowerBound() {
  247.         return Double.NEGATIVE_INFINITY;
  248.     }

  249.     /**
  250.      * {@inheritDoc}
  251.      *
  252.      * The upper bound of the support is always positive infinity
  253.      * no matter the parameters.
  254.      *
  255.      * @return upper bound of the support (always
  256.      * {@code Double.POSITIVE_INFINITY})
  257.      */
  258.     public double getSupportUpperBound() {
  259.         return Double.POSITIVE_INFINITY;
  260.     }

  261.     /** {@inheritDoc} */
  262.     public boolean isSupportLowerBoundInclusive() {
  263.         return false;
  264.     }

  265.     /** {@inheritDoc} */
  266.     public boolean isSupportUpperBoundInclusive() {
  267.         return false;
  268.     }

  269.     /**
  270.      * {@inheritDoc}
  271.      *
  272.      * The support of this distribution is connected.
  273.      *
  274.      * @return {@code true}
  275.      */
  276.     public boolean isSupportConnected() {
  277.         return true;
  278.     }

  279.     /** {@inheritDoc} */
  280.     @Override
  281.     public double sample()  {
  282.         return standardDeviation * random.nextGaussian() + mean;
  283.     }
  284. }