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.  *      https://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. /*
  18.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */

  21. package org.hipparchus.distribution.continuous;

  22. import org.hipparchus.exception.LocalizedCoreFormats;
  23. import org.hipparchus.exception.MathIllegalArgumentException;
  24. import org.hipparchus.special.Erf;
  25. import org.hipparchus.util.FastMath;
  26. import org.hipparchus.util.MathUtils;

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

  44.     /**
  45.      * Create a normal distribution with mean equal to zero and standard
  46.      * deviation equal to one.
  47.      */
  48.     public NormalDistribution() {
  49.         this(0, 1);
  50.     }

  51.     /**
  52.      * Create a normal distribution using the given mean, standard deviation.
  53.      *
  54.      * @param mean Mean for this distribution.
  55.      * @param sd Standard deviation for this distribution.
  56.      * @throws MathIllegalArgumentException if {@code sd <= 0}.
  57.      */
  58.     public NormalDistribution(double mean, double sd)
  59.         throws MathIllegalArgumentException {
  60.         if (sd <= 0) {
  61.             throw new MathIllegalArgumentException(LocalizedCoreFormats.STANDARD_DEVIATION, sd);
  62.         }

  63.         this.mean = mean;
  64.         this.standardDeviation = sd;
  65.         this.logStandardDeviationPlusHalfLog2Pi =
  66.                 FastMath.log(sd) + 0.5 * FastMath.log(2 * FastMath.PI);
  67.     }

  68.     /**
  69.      * Access the mean.
  70.      *
  71.      * @return the mean for this distribution.
  72.      */
  73.     public double getMean() {
  74.         return mean;
  75.     }

  76.     /**
  77.      * Access the standard deviation.
  78.      *
  79.      * @return the standard deviation for this distribution.
  80.      */
  81.     public double getStandardDeviation() {
  82.         return standardDeviation;
  83.     }

  84.     /** {@inheritDoc} */
  85.     @Override
  86.     public double density(double x) {
  87.         return FastMath.exp(logDensity(x));
  88.     }

  89.     /** {@inheritDoc} */
  90.     @Override
  91.     public double logDensity(double x) {
  92.         final double x0 = x - mean;
  93.         final double x1 = x0 / standardDeviation;
  94.         return -0.5 * x1 * x1 - logStandardDeviationPlusHalfLog2Pi;
  95.     }

  96.     /**
  97.      * {@inheritDoc}
  98.      *
  99.      * If {@code x} is more than 40 standard deviations from the mean, 0 or 1
  100.      * is returned, as in these cases the actual value is within
  101.      * {@code Double.MIN_VALUE} of 0 or 1.
  102.      */
  103.     @Override
  104.     public double cumulativeProbability(double x)  {
  105.         final double dev = x - mean;
  106.         if (FastMath.abs(dev) > 40 * standardDeviation) {
  107.             return dev < 0 ? 0.0d : 1.0d;
  108.         }
  109.         return 0.5 * Erf.erfc(-dev / (standardDeviation * SQRT2));
  110.     }

  111.     /** {@inheritDoc} */
  112.     @Override
  113.     public double inverseCumulativeProbability(final double p) throws MathIllegalArgumentException {
  114.         MathUtils.checkRangeInclusive(p, 0, 1);
  115.         return mean + standardDeviation * SQRT2 * Erf.erfInv(2 * p - 1);
  116.     }

  117.     /** {@inheritDoc} */
  118.     @Override
  119.     public double probability(double x0,
  120.                               double x1)
  121.         throws MathIllegalArgumentException {
  122.         if (x0 > x1) {
  123.             throw new MathIllegalArgumentException(LocalizedCoreFormats.LOWER_ENDPOINT_ABOVE_UPPER_ENDPOINT,
  124.                                                 x0, x1, true);
  125.         }
  126.         final double denom = standardDeviation * SQRT2;
  127.         final double v0 = (x0 - mean) / denom;
  128.         final double v1 = (x1 - mean) / denom;
  129.         return 0.5 * Erf.erf(v0, v1);
  130.     }

  131.     /**
  132.      * {@inheritDoc}
  133.      *
  134.      * For mean parameter {@code mu}, the mean is {@code mu}.
  135.      */
  136.     @Override
  137.     public double getNumericalMean() {
  138.         return getMean();
  139.     }

  140.     /**
  141.      * {@inheritDoc}
  142.      *
  143.      * For standard deviation parameter {@code s}, the variance is {@code s^2}.
  144.      */
  145.     @Override
  146.     public double getNumericalVariance() {
  147.         final double s = getStandardDeviation();
  148.         return s * s;
  149.     }

  150.     /**
  151.      * {@inheritDoc}
  152.      *
  153.      * The lower bound of the support is always negative infinity
  154.      * no matter the parameters.
  155.      *
  156.      * @return lower bound of the support (always
  157.      * {@code Double.NEGATIVE_INFINITY})
  158.      */
  159.     @Override
  160.     public double getSupportLowerBound() {
  161.         return Double.NEGATIVE_INFINITY;
  162.     }

  163.     /**
  164.      * {@inheritDoc}
  165.      *
  166.      * The upper bound of the support is always positive infinity
  167.      * no matter the parameters.
  168.      *
  169.      * @return upper bound of the support (always
  170.      * {@code Double.POSITIVE_INFINITY})
  171.      */
  172.     @Override
  173.     public double getSupportUpperBound() {
  174.         return Double.POSITIVE_INFINITY;
  175.     }

  176.     /**
  177.      * {@inheritDoc}
  178.      *
  179.      * The support of this distribution is connected.
  180.      *
  181.      * @return {@code true}
  182.      */
  183.     @Override
  184.     public boolean isSupportConnected() {
  185.         return true;
  186.     }
  187. }