SSJ API Documentation
Stochastic Simulation in Java
Loading...
Searching...
No Matches
NormalDist.java
1/*
2 * Class: NormalDist
3 * Description: normal or Gaussian distribution
4 * Environment: Java
5 * Software: SSJ
6 * Copyright (C) 2001 Pierre L'Ecuyer and Universite de Montreal
7 * Organization: DIRO, Universite de Montreal
8 * @author Richard Simard
9 * @since
10 *
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 * http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *
24 */
25package umontreal.ssj.probdist;
26
27import umontreal.ssj.util.Num;
28
49public class NormalDist extends ContinuousDistribution {
50 protected double mu;
51 protected double sigma;
52 protected static final double RAC2PI = 2.50662827463100050; // Sqrt(2*Pi)
53
54 private static final double[] AbarF = { 6.10143081923200418E-1, -4.34841272712577472E-1, 1.76351193643605501E-1,
55 -6.07107956092494149E-2, 1.77120689956941145E-2, -4.32111938556729382E-3, 8.54216676887098679E-4,
56 -1.27155090609162743E-4, 1.12481672436711895E-5, 3.13063885421820973E-7, -2.70988068537762022E-7,
57 3.07376227014076884E-8, 2.51562038481762294E-9, -1.02892992132031913E-9, 2.99440521199499394E-11,
58 2.60517896872669363E-11, -2.63483992417196939E-12, -6.43404509890636443E-13, 1.12457401801663447E-13,
59 1.7281533389986098E-14, -4.2641016949424E-15, -5.4537197788E-16, 1.5869760776E-16, 2.08998378E-17,
60 -0.5900E-17 };
61
66 public NormalDist() {
67 setParams(0.0, 1.0);
68 }
69
74 public NormalDist(double mu, double sigma) {
75 setParams(mu, sigma);
76 }
77
78 public double density(double x) {
79 double z = (x - mu) / sigma;
80 return Math.exp(-0.5 * z * z) / (RAC2PI * sigma);
81 }
82
83 public double cdf(double x) {
84 return cdf01((x - mu) / sigma);
85 }
86
87 public double barF(double x) {
88 return barF01((x - mu) / sigma);
89 }
90
91 public double inverseF(double u) {
92 return mu + sigma * inverseF01(u);
93 }
94
95 public double getMean() {
96 return NormalDist.getMean(mu, sigma);
97 }
98
99 public double getVariance() {
100 return NormalDist.getVariance(mu, sigma);
101 }
102
103 public double getStandardDeviation() {
104 return NormalDist.getStandardDeviation(mu, sigma);
105 }
106
110 public static double density01(double x) {
111 return Math.exp(-0.5 * x * x) / RAC2PI;
112 }
113
118 public static double density(double mu, double sigma, double x) {
119 if (sigma <= 0)
120 throw new IllegalArgumentException("sigma <= 0");
121 double z = (x - mu) / sigma;
122 return Math.exp(-0.5 * z * z) / (RAC2PI * sigma);
123 }
124
125 /*
126 * The precision of double is 16 decimals; we shall thus use coeffmax = 24
127 * coefficients. But the approximation is good to 30 decimals of precision with
128 * 44 coefficients.
129 */
130 private static final int COEFFMAX = 24;
131
132 private static final double NORMAL2_A[] = { 6.10143081923200417926465815756e-1, -4.34841272712577471828182820888e-1,
133 1.76351193643605501125840298123e-1, -6.0710795609249414860051215825e-2, 1.7712068995694114486147141191e-2,
134 -4.321119385567293818599864968e-3, 8.54216676887098678819832055e-4, -1.27155090609162742628893940e-4,
135 1.1248167243671189468847072e-5, 3.13063885421820972630152e-7, -2.70988068537762022009086e-7,
136 3.0737622701407688440959e-8, 2.515620384817622937314e-9, -1.028929921320319127590e-9,
137 2.9944052119949939363e-11, 2.6051789687266936290e-11, -2.634839924171969386e-12, -6.43404509890636443e-13,
138 1.12457401801663447e-13, 1.7281533389986098e-14, -4.264101694942375e-15, -5.45371977880191e-16,
139 1.58697607761671e-16, 2.0899837844334e-17, -5.900526869409e-18, -9.41893387554e-19
140 /*
141 * , 2.14977356470e-19, 4.6660985008e-20, -7.243011862e-21, -2.387966824e-21,
142 * 1.91177535e-22, 1.20482568e-22, -6.72377e-25, -5.747997e-24, -4.28493e-25,
143 * 2.44856e-25, 4.3793e-26, -8.151e-27, -3.089e-27, 9.3e-29, 1.74e-28, 1.6e-29,
144 * -8.0e-30, -2.0e-30
145 */
146 };
147
151 public static double cdf01(double x) {
152 /*
153 * Returns P[X < x] for the normal distribution. As in J. L. Schonfelder, Math.
154 * of Computation, Vol. 32, pp 1232--1240, (1978).
155 */
156
157 double t, r;
158
159 if (x <= -XBIG)
160 return 0.0;
161 if (x >= XBIG)
162 return 1.0;
163
164 x = -x / Num.RAC2;
165 if (x < 0) {
166 x = -x;
167 t = (x - 3.75) / (x + 3.75);
168 r = 1.0 - 0.5 * Math.exp(-x * x) * Num.evalCheby(NORMAL2_A, COEFFMAX, t);
169 } else {
170 t = (x - 3.75) / (x + 3.75);
171 r = 0.5 * Math.exp(-x * x) * Num.evalCheby(NORMAL2_A, COEFFMAX, t);
172 }
173 return r;
174 }
175
181 public static double cdf(double mu, double sigma, double x) {
182 if (sigma <= 0)
183 throw new IllegalArgumentException("sigma <= 0");
184 return cdf01((x - mu) / sigma);
185 }
186
190 public static double barF01(double x) {
191 /*
192 * Returns P[X >= x] = 1 - F (x) where F is the normal distribution by computing
193 * the complementary distribution directly; it is thus more precise in the tail.
194 */
195
196 final double KK = 5.30330085889910643300; // 3.75 Sqrt (2)
197 double y, t;
198 int neg;
199
200 if (x >= XBIG)
201 return 0.0;
202 if (x <= -XBIG)
203 return 1.0;
204
205 if (x >= 0.0)
206 neg = 0;
207 else {
208 neg = 1;
209 x = -x;
210 }
211
212 t = (x - KK) / (x + KK);
213 y = Num.evalCheby(AbarF, 24, t);
214 y = y * Math.exp(-x * x / 2.0) / 2.0;
215
216 if (neg == 1)
217 return 1.0 - y;
218 else
219 return y;
220 }
221
229 public static double barF(double mu, double sigma, double x) {
230 if (sigma <= 0)
231 throw new IllegalArgumentException("sigma <= 0");
232 return barF01((x - mu) / sigma);
233 }
234
235 private static final double[] InvP1 = { 0.160304955844066229311E2, -0.90784959262960326650E2,
236 0.18644914861620987391E3, -0.16900142734642382420E3, 0.6545466284794487048E2, -0.864213011587247794E1,
237 0.1760587821390590 };
238
239 private static final double[] InvQ1 = { 0.147806470715138316110E2, -0.91374167024260313396E2,
240 0.21015790486205317714E3, -0.22210254121855132366E3, 0.10760453916055123830E3, -0.206010730328265443E2,
241 0.1E1 };
242
243 private static final double[] InvP2 = { -0.152389263440726128E-1, 0.3444556924136125216, -0.29344398672542478687E1,
244 0.11763505705217827302E2, -0.22655292823101104193E2, 0.19121334396580330163E2, -0.5478927619598318769E1,
245 0.237516689024448000 };
246
247 private static final double[] InvQ2 = { -0.108465169602059954E-1, 0.2610628885843078511, -0.24068318104393757995E1,
248 0.10695129973387014469E2, -0.23716715521596581025E2, 0.24640158943917284883E2, -0.10014376349783070835E2,
249 0.1E1 };
250
251 private static final double[] InvP3 = { 0.56451977709864482298E-4, 0.53504147487893013765E-2, 0.12969550099727352403,
252 0.10426158549298266122E1, 0.28302677901754489974E1, 0.26255672879448072726E1, 0.20789742630174917228E1,
253 0.72718806231556811306, 0.66816807711804989575E-1, -0.17791004575111759979E-1, 0.22419563223346345828E-2 };
254
255 private static final double[] InvQ3 = { 0.56451699862760651514E-4, 0.53505587067930653953E-2, 0.12986615416911646934,
256 0.10542932232626491195E1, 0.30379331173522206237E1, 0.37631168536405028901E1, 0.38782858277042011263E1,
257 0.20372431817412177929E1, 0.1E1 };
258
262 public static double inverseF01(double u) {
263 /*
264 * Returns the inverse of the cdf of the normal distribution. Rational
265 * approximations giving 16 decimals of precision. J.M. Blair, C.A. Edwards,
266 * J.H. Johnson, "Rational Chebyshev approximations for the Inverse of the Error
267 * Function", in Mathematics of Computation, Vol. 30, 136, pp 827, (1976)
268 */
269
270 int i;
271 boolean negatif;
272 double y, z, v, w;
273 double x = u;
274
275 if (u < 0.0 || u > 1.0)
276 throw new IllegalArgumentException("u is not in [0, 1]");
277 if (u <= 0.0)
278 return Double.NEGATIVE_INFINITY;
279 if (u >= 1.0)
280 return Double.POSITIVE_INFINITY;
281
282 // Transform x as argument of InvErf
283 x = 2.0 * x - 1.0;
284 if (x < 0.0) {
285 x = -x;
286 negatif = true;
287 } else {
288 negatif = false;
289 }
290
291 if (x <= 0.75) {
292 y = x * x - 0.5625;
293 v = w = 0.0;
294 for (i = 6; i >= 0; i--) {
295 v = v * y + InvP1[i];
296 w = w * y + InvQ1[i];
297 }
298 z = (v / w) * x;
299
300 } else if (x <= 0.9375) {
301 y = x * x - 0.87890625;
302 v = w = 0.0;
303 for (i = 7; i >= 0; i--) {
304 v = v * y + InvP2[i];
305 w = w * y + InvQ2[i];
306 }
307 z = (v / w) * x;
308
309 } else {
310 if (u > 0.5)
311 y = 1.0 / Math.sqrt(-Math.log(1.0 - x));
312 else
313 y = 1.0 / Math.sqrt(-Math.log(2.0 * u));
314 v = 0.0;
315 for (i = 10; i >= 0; i--)
316 v = v * y + InvP3[i];
317 w = 0.0;
318 for (i = 8; i >= 0; i--)
319 w = w * y + InvQ3[i];
320 z = (v / w) / y;
321 }
322
323 if (negatif) {
324 if (u < 1.0e-105) {
325 final double RACPI = 1.77245385090551602729;
326 w = Math.exp(-z * z) / RACPI; // pdf
327 y = 2.0 * z * z;
328 v = 1.0;
329 double term = 1.0;
330 // Asymptotic series for erfc(z) (apart from exp factor)
331 for (i = 0; i < 6; ++i) {
332 term *= -(2 * i + 1) / y;
333 v += term;
334 }
335 // Apply 1 iteration of Newton solver to get last few decimals
336 z -= u / w - 0.5 * v / z;
337
338 }
339 return -(z * Num.RAC2);
340
341 } else
342 return z * Num.RAC2;
343 }
344
352 public static double inverseF(double mu, double sigma, double u) {
353 if (sigma <= 0)
354 throw new IllegalArgumentException("sigma <= 0");
355 return mu + sigma * inverseF01(u);
356 }
357
375 public static double[] getMLE(double[] x, int n) {
376 if (n <= 0)
377 throw new IllegalArgumentException("n <= 0");
378
379 double[] parameters = new double[2];
380 double sum = 0.0;
381 for (int i = 0; i < n; i++)
382 sum += x[i];
383 parameters[0] = sum / n;
384
385 sum = 0.0;
386 for (int i = 0; i < n; i++)
387 sum = sum + (x[i] - parameters[0]) * (x[i] - parameters[0]);
388 parameters[1] = Math.sqrt(sum / n);
389
390 return parameters;
391 }
392
402 public static NormalDist getInstanceFromMLE(double[] x, int n) {
403 double parameters[] = getMLE(x, n);
404 return new NormalDist(parameters[0], parameters[1]);
405 }
406
413 public static double getMean(double mu, double sigma) {
414 if (sigma <= 0.0)
415 throw new IllegalArgumentException("sigma <= 0");
416
417 return mu;
418 }
419
427 public static double getVariance(double mu, double sigma) {
428 if (sigma <= 0.0)
429 throw new IllegalArgumentException("sigma <= 0");
430
431 return (sigma * sigma);
432 }
433
440 public static double getStandardDeviation(double mu, double sigma) {
441 return sigma;
442 }
443
447 public double getMu() {
448 return mu;
449 }
450
454 public double getSigma() {
455 return sigma;
456 }
457
461 public void setParams(double mu, double sigma) {
462 if (sigma <= 0.0)
463 throw new IllegalArgumentException("sigma <= 0");
464 this.mu = mu;
465 this.sigma = sigma;
466 }
467
472 public double[] getParams() {
473 double[] retour = { mu, sigma };
474 return retour;
475 }
476
480 public String toString() {
481 return getClass().getSimpleName() + " : mu = " + mu + ", sigma = " + sigma;
482 }
483
484}
Classes implementing continuous distributions should inherit from this base class.
static double inverseF(double mu, double sigma, double u)
Computes the inverse normal distribution function with mean.
double getMu()
Returns the parameter .
static NormalDist getInstanceFromMLE(double[] x, int n)
Creates a new instance of a normal distribution with parameters.
double getMean()
Returns the mean.
double[] getParams()
Return a table containing the parameters of the current distribution.
static double barF(double mu, double sigma, double x)
Computes the complementary normal distribution function.
String toString()
Returns a String containing information about the current distribution.
NormalDist(double mu, double sigma)
Constructs a NormalDist object with mean = mu and standard deviation = sigma.
double getStandardDeviation()
Returns the standard deviation.
double density(double x)
Returns , the density evaluated at .
double getVariance()
Returns the variance.
static double inverseF01(double u)
Same as inverseF(0, 1, u).
static double cdf01(double x)
Same as cdf(0, 1, x).
static double density01(double x)
Same as density(0, 1, x).
double cdf(double x)
Returns the distribution function .
static double density(double mu, double sigma, double x)
Computes the normal density function ( fnormal ).
static double[] getMLE(double[] x, int n)
Estimates the parameters of the normal distribution using the maximum likelihood method,...
static double getVariance(double mu, double sigma)
Computes and returns the variance of the normal distribution with parameters and.
static double getStandardDeviation(double mu, double sigma)
Computes and returns the standard deviation of the normal distribution with parameters and .
static double getMean(double mu, double sigma)
Computes and returns the mean of the normal distribution with parameters and .
static double barF01(double x)
Same as barF(0, 1, x).
NormalDist()
Constructs a NormalDist object with default parameters and .
double inverseF(double u)
Returns the inverse distribution function .
double barF(double x)
Returns the complementary distribution function.
void setParams(double mu, double sigma)
Sets the parameters and of this object.
double getSigma()
Returns the parameter .
static double cdf(double mu, double sigma, double x)
Computes the normal distribution function with mean and variance .
This class provides various constants and methods to compute numerical quantities such as factorials,...
Definition Num.java:35
static final double RAC2
The value of .
Definition Num.java:138
static double evalCheby(double a[], int n, double x)
Evaluates a series of Chebyshev polynomials at over the basic interval , using the method of Clensh...
Definition Num.java:812