View Javadoc

1   /*
2    * Copyright 2004 The Apache Software Foundation.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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: 1.13 $ $Date: 2004/07/24 21:41:36 $
29   */
30  public class NormalDistributionImpl extends AbstractContinuousDistribution 
31  		implements NormalDistribution, Serializable {
32      
33      /*** Serializable version identifier */
34      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 &lt; <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 &lt; 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 &lt; 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 &lt; <i>lower bound</i>) &lt; <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 &lt; <i>upper bound</i>) &gt; <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 }