001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.math3.distribution;
019
020import org.apache.commons.math3.exception.NotStrictlyPositiveException;
021import org.apache.commons.math3.exception.NumberIsTooLargeException;
022import org.apache.commons.math3.exception.OutOfRangeException;
023import org.apache.commons.math3.exception.util.LocalizedFormats;
024import org.apache.commons.math3.random.RandomGenerator;
025import org.apache.commons.math3.random.Well19937c;
026import org.apache.commons.math3.special.Erf;
027import org.apache.commons.math3.util.FastMath;
028
029/**
030 * Implementation of the normal (gaussian) distribution.
031 *
032 * @see <a href="http://en.wikipedia.org/wiki/Normal_distribution">Normal distribution (Wikipedia)</a>
033 * @see <a href="http://mathworld.wolfram.com/NormalDistribution.html">Normal distribution (MathWorld)</a>
034 */
035public class NormalDistribution extends AbstractRealDistribution {
036    /**
037     * Default inverse cumulative probability accuracy.
038     * @since 2.1
039     */
040    public static final double DEFAULT_INVERSE_ABSOLUTE_ACCURACY = 1e-9;
041    /** Serializable version identifier. */
042    private static final long serialVersionUID = 8589540077390120676L;
043    /** &radic;(2) */
044    private static final double SQRT2 = FastMath.sqrt(2.0);
045    /** Mean of this distribution. */
046    private final double mean;
047    /** Standard deviation of this distribution. */
048    private final double standardDeviation;
049    /** The value of {@code log(sd) + 0.5*log(2*pi)} stored for faster computation. */
050    private final double logStandardDeviationPlusHalfLog2Pi;
051    /** Inverse cumulative probability accuracy. */
052    private final double solverAbsoluteAccuracy;
053
054    /**
055     * Create a normal distribution with mean equal to zero and standard
056     * deviation equal to one.
057     * <p>
058     * <b>Note:</b> this constructor will implicitly create an instance of
059     * {@link Well19937c} as random generator to be used for sampling only (see
060     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
061     * needed for the created distribution, it is advised to pass {@code null}
062     * as random generator via the appropriate constructors to avoid the
063     * additional initialisation overhead.
064     */
065    public NormalDistribution() {
066        this(0, 1);
067    }
068
069    /**
070     * Create a normal distribution using the given mean and standard deviation.
071     * <p>
072     * <b>Note:</b> this constructor will implicitly create an instance of
073     * {@link Well19937c} as random generator to be used for sampling only (see
074     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
075     * needed for the created distribution, it is advised to pass {@code null}
076     * as random generator via the appropriate constructors to avoid the
077     * additional initialisation overhead.
078     *
079     * @param mean Mean for this distribution.
080     * @param sd Standard deviation for this distribution.
081     * @throws NotStrictlyPositiveException if {@code sd <= 0}.
082     */
083    public NormalDistribution(double mean, double sd)
084        throws NotStrictlyPositiveException {
085        this(mean, sd, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
086    }
087
088    /**
089     * Create a normal distribution using the given mean, standard deviation and
090     * inverse cumulative distribution accuracy.
091     * <p>
092     * <b>Note:</b> this constructor will implicitly create an instance of
093     * {@link Well19937c} as random generator to be used for sampling only (see
094     * {@link #sample()} and {@link #sample(int)}). In case no sampling is
095     * needed for the created distribution, it is advised to pass {@code null}
096     * as random generator via the appropriate constructors to avoid the
097     * additional initialisation overhead.
098     *
099     * @param mean Mean for this distribution.
100     * @param sd Standard deviation for this distribution.
101     * @param inverseCumAccuracy Inverse cumulative probability accuracy.
102     * @throws NotStrictlyPositiveException if {@code sd <= 0}.
103     * @since 2.1
104     */
105    public NormalDistribution(double mean, double sd, double inverseCumAccuracy)
106        throws NotStrictlyPositiveException {
107        this(new Well19937c(), mean, sd, inverseCumAccuracy);
108    }
109
110    /**
111     * Creates a normal distribution.
112     *
113     * @param rng Random number generator.
114     * @param mean Mean for this distribution.
115     * @param sd Standard deviation for this distribution.
116     * @throws NotStrictlyPositiveException if {@code sd <= 0}.
117     * @since 3.3
118     */
119    public NormalDistribution(RandomGenerator rng, double mean, double sd)
120        throws NotStrictlyPositiveException {
121        this(rng, mean, sd, DEFAULT_INVERSE_ABSOLUTE_ACCURACY);
122    }
123
124    /**
125     * Creates a normal distribution.
126     *
127     * @param rng Random number generator.
128     * @param mean Mean for this distribution.
129     * @param sd Standard deviation for this distribution.
130     * @param inverseCumAccuracy Inverse cumulative probability accuracy.
131     * @throws NotStrictlyPositiveException if {@code sd <= 0}.
132     * @since 3.1
133     */
134    public NormalDistribution(RandomGenerator rng,
135                              double mean,
136                              double sd,
137                              double inverseCumAccuracy)
138        throws NotStrictlyPositiveException {
139        super(rng);
140
141        if (sd <= 0) {
142            throw new NotStrictlyPositiveException(LocalizedFormats.STANDARD_DEVIATION, sd);
143        }
144
145        this.mean = mean;
146        standardDeviation = sd;
147        logStandardDeviationPlusHalfLog2Pi = FastMath.log(sd) + 0.5 * FastMath.log(2 * FastMath.PI);
148        solverAbsoluteAccuracy = inverseCumAccuracy;
149    }
150
151    /**
152     * Access the mean.
153     *
154     * @return the mean for this distribution.
155     */
156    public double getMean() {
157        return mean;
158    }
159
160    /**
161     * Access the standard deviation.
162     *
163     * @return the standard deviation for this distribution.
164     */
165    public double getStandardDeviation() {
166        return standardDeviation;
167    }
168
169    /** {@inheritDoc} */
170    public double density(double x) {
171        return FastMath.exp(logDensity(x));
172    }
173
174    /** {@inheritDoc} */
175    @Override
176    public double logDensity(double x) {
177        final double x0 = x - mean;
178        final double x1 = x0 / standardDeviation;
179        return -0.5 * x1 * x1 - logStandardDeviationPlusHalfLog2Pi;
180    }
181
182    /**
183     * {@inheritDoc}
184     *
185     * If {@code x} is more than 40 standard deviations from the mean, 0 or 1
186     * is returned, as in these cases the actual value is within
187     * {@code Double.MIN_VALUE} of 0 or 1.
188     */
189    public double cumulativeProbability(double x)  {
190        final double dev = x - mean;
191        if (FastMath.abs(dev) > 40 * standardDeviation) {
192            return dev < 0 ? 0.0d : 1.0d;
193        }
194        return 0.5 * Erf.erfc(-dev / (standardDeviation * SQRT2));
195    }
196
197    /** {@inheritDoc}
198     * @since 3.2
199     */
200    @Override
201    public double inverseCumulativeProbability(final double p) throws OutOfRangeException {
202        if (p < 0.0 || p > 1.0) {
203            throw new OutOfRangeException(p, 0, 1);
204        }
205        return mean + standardDeviation * SQRT2 * Erf.erfInv(2 * p - 1);
206    }
207
208    /**
209     * {@inheritDoc}
210     *
211     * @deprecated See {@link RealDistribution#cumulativeProbability(double,double)}
212     */
213    @Override@Deprecated
214    public double cumulativeProbability(double x0, double x1)
215        throws NumberIsTooLargeException {
216        return probability(x0, x1);
217    }
218
219    /** {@inheritDoc} */
220    @Override
221    public double probability(double x0,
222                              double x1)
223        throws NumberIsTooLargeException {
224        if (x0 > x1) {
225            throw new NumberIsTooLargeException(LocalizedFormats.LOWER_ENDPOINT_ABOVE_UPPER_ENDPOINT,
226                                                x0, x1, true);
227        }
228        final double denom = standardDeviation * SQRT2;
229        final double v0 = (x0 - mean) / denom;
230        final double v1 = (x1 - mean) / denom;
231        return 0.5 * Erf.erf(v0, v1);
232    }
233
234    /** {@inheritDoc} */
235    @Override
236    protected double getSolverAbsoluteAccuracy() {
237        return solverAbsoluteAccuracy;
238    }
239
240    /**
241     * {@inheritDoc}
242     *
243     * For mean parameter {@code mu}, the mean is {@code mu}.
244     */
245    public double getNumericalMean() {
246        return getMean();
247    }
248
249    /**
250     * {@inheritDoc}
251     *
252     * For standard deviation parameter {@code s}, the variance is {@code s^2}.
253     */
254    public double getNumericalVariance() {
255        final double s = getStandardDeviation();
256        return s * s;
257    }
258
259    /**
260     * {@inheritDoc}
261     *
262     * The lower bound of the support is always negative infinity
263     * no matter the parameters.
264     *
265     * @return lower bound of the support (always
266     * {@code Double.NEGATIVE_INFINITY})
267     */
268    public double getSupportLowerBound() {
269        return Double.NEGATIVE_INFINITY;
270    }
271
272    /**
273     * {@inheritDoc}
274     *
275     * The upper bound of the support is always positive infinity
276     * no matter the parameters.
277     *
278     * @return upper bound of the support (always
279     * {@code Double.POSITIVE_INFINITY})
280     */
281    public double getSupportUpperBound() {
282        return Double.POSITIVE_INFINITY;
283    }
284
285    /** {@inheritDoc} */
286    public boolean isSupportLowerBoundInclusive() {
287        return false;
288    }
289
290    /** {@inheritDoc} */
291    public boolean isSupportUpperBoundInclusive() {
292        return false;
293    }
294
295    /**
296     * {@inheritDoc}
297     *
298     * The support of this distribution is connected.
299     *
300     * @return {@code true}
301     */
302    public boolean isSupportConnected() {
303        return true;
304    }
305
306    /** {@inheritDoc} */
307    @Override
308    public double sample()  {
309        return standardDeviation * random.nextGaussian() + mean;
310    }
311}