1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.math.distribution;
18
19 import java.io.Serializable;
20
21 import org.apache.commons.math.MathException;
22 import org.apache.commons.math.special.Erf;
23
24 /**
25 * Default implementation of
26 * {@link org.apache.commons.math.distribution.NormalDistribution}.
27 *
28 * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
29 */
30 public class NormalDistributionImpl extends AbstractContinuousDistribution
31 implements NormalDistribution, Serializable {
32
33 /** Serializable version identifier */
34 private static final long serialVersionUID = 8589540077390120676L;
35
36 /** The mean of this distribution. */
37 private double mean = 0;
38
39 /** The standard deviation of this distribution. */
40 private double standardDeviation = 1;
41
42 /**
43 * Create a normal distribution using the given mean and standard deviation.
44 * @param mean mean for this distribution
45 * @param sd standard deviation for this distribution
46 */
47 public NormalDistributionImpl(double mean, double sd){
48 super();
49 setMean(mean);
50 setStandardDeviation(sd);
51 }
52
53 /**
54 * Creates normal distribution with the mean equal to zero and standard
55 * deviation equal to one.
56 */
57 public NormalDistributionImpl(){
58 this(0.0, 1.0);
59 }
60
61 /**
62 * Access the mean.
63 * @return mean for this distribution
64 */
65 public double getMean() {
66 return mean;
67 }
68
69 /**
70 * Modify the mean.
71 * @param mean for this distribution
72 */
73 public void setMean(double mean) {
74 this.mean = mean;
75 }
76
77 /**
78 * Access the standard deviation.
79 * @return standard deviation for this distribution
80 */
81 public double getStandardDeviation() {
82 return standardDeviation;
83 }
84
85 /**
86 * Modify the standard deviation.
87 * @param sd standard deviation for this distribution
88 * @throws IllegalArgumentException if <code>sd</code> is not positive.
89 */
90 public void setStandardDeviation(double sd) {
91 if (sd <= 0.0) {
92 throw new IllegalArgumentException(
93 "Standard deviation must be positive.");
94 }
95 standardDeviation = sd;
96 }
97
98 /**
99 * For this disbution, X, this method returns P(X < <code>x</code>).
100 * @param x the value at which the CDF is evaluated.
101 * @return CDF evaluted at <code>x</code>.
102 * @throws MathException if the algorithm fails to converge.
103 */
104 public double cumulativeProbability(double x) throws MathException {
105 return 0.5 * (1.0 + Erf.erf((x - mean) /
106 (standardDeviation * Math.sqrt(2.0))));
107 }
108
109 /**
110 * For this distribution, X, this method returns the critical point x, such
111 * that P(X < x) = <code>p</code>.
112 * <p>
113 * Returns <code>Double.NEGATIVE_INFINITY</code> for p=0 and
114 * <code>Double.POSITIVE_INFINITY</code> for p=1.
115 *
116 * @param p the desired probability
117 * @return x, such that P(X < x) = <code>p</code>
118 * @throws MathException if the inverse cumulative probability can not be
119 * computed due to convergence or other numerical errors.
120 * @throws IllegalArgumentException if <code>p</code> is not a valid
121 * probability.
122 */
123 public double inverseCumulativeProbability(final double p)
124 throws MathException {
125 if (p == 0) {
126 return Double.NEGATIVE_INFINITY;
127 }
128 if (p == 1) {
129 return Double.POSITIVE_INFINITY;
130 }
131 return super.inverseCumulativeProbability(p);
132 }
133
134 /**
135 * Access the domain value lower bound, based on <code>p</code>, used to
136 * bracket a CDF root. This method is used by
137 * {@link #inverseCumulativeProbability(double)} to find critical values.
138 *
139 * @param p the desired probability for the critical value
140 * @return domain value lower bound, i.e.
141 * P(X < <i>lower bound</i>) < <code>p</code>
142 */
143 protected double getDomainLowerBound(double p) {
144 double ret;
145
146 if (p < .5) {
147 ret = -Double.MAX_VALUE;
148 } else {
149 ret = getMean();
150 }
151
152 return ret;
153 }
154
155 /**
156 * Access the domain value upper bound, based on <code>p</code>, used to
157 * bracket a CDF root. This method is used by
158 * {@link #inverseCumulativeProbability(double)} to find critical values.
159 *
160 * @param p the desired probability for the critical value
161 * @return domain value upper bound, i.e.
162 * P(X < <i>upper bound</i>) > <code>p</code>
163 */
164 protected double getDomainUpperBound(double p) {
165 double ret;
166
167 if (p < .5) {
168 ret = getMean();
169 } else {
170 ret = Double.MAX_VALUE;
171 }
172
173 return ret;
174 }
175
176 /**
177 * Access the initial domain value, based on <code>p</code>, used to
178 * bracket a CDF root. This method is used by
179 * {@link #inverseCumulativeProbability(double)} to find critical values.
180 *
181 * @param p the desired probability for the critical value
182 * @return initial domain value
183 */
184 protected double getInitialDomain(double p) {
185 double ret;
186
187 if (p < .5) {
188 ret = getMean() - getStandardDeviation();
189 } else if (p > .5) {
190 ret = getMean() + getStandardDeviation();
191 } else {
192 ret = getMean();
193 }
194
195 return ret;
196 }
197 }