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 /** √(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}