001: /*
002: * Copyright 2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.commons.math.distribution;
018:
019: import java.io.Serializable;
020:
021: import org.apache.commons.math.MathException;
022: import org.apache.commons.math.special.Erf;
023:
024: /**
025: * Default implementation of
026: * {@link org.apache.commons.math.distribution.NormalDistribution}.
027: *
028: * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
029: */
030: public class NormalDistributionImpl extends
031: AbstractContinuousDistribution implements NormalDistribution,
032: Serializable {
033:
034: /** Serializable version identifier */
035: private static final long serialVersionUID = 8589540077390120676L;
036:
037: /** The mean of this distribution. */
038: private double mean = 0;
039:
040: /** The standard deviation of this distribution. */
041: private double standardDeviation = 1;
042:
043: /**
044: * Create a normal distribution using the given mean and standard deviation.
045: * @param mean mean for this distribution
046: * @param sd standard deviation for this distribution
047: */
048: public NormalDistributionImpl(double mean, double sd) {
049: super ();
050: setMean(mean);
051: setStandardDeviation(sd);
052: }
053:
054: /**
055: * Creates normal distribution with the mean equal to zero and standard
056: * deviation equal to one.
057: */
058: public NormalDistributionImpl() {
059: this (0.0, 1.0);
060: }
061:
062: /**
063: * Access the mean.
064: * @return mean for this distribution
065: */
066: public double getMean() {
067: return mean;
068: }
069:
070: /**
071: * Modify the mean.
072: * @param mean for this distribution
073: */
074: public void setMean(double mean) {
075: this .mean = mean;
076: }
077:
078: /**
079: * Access the standard deviation.
080: * @return standard deviation for this distribution
081: */
082: public double getStandardDeviation() {
083: return standardDeviation;
084: }
085:
086: /**
087: * Modify the standard deviation.
088: * @param sd standard deviation for this distribution
089: * @throws IllegalArgumentException if <code>sd</code> is not positive.
090: */
091: public void setStandardDeviation(double sd) {
092: if (sd <= 0.0) {
093: throw new IllegalArgumentException(
094: "Standard deviation must be positive.");
095: }
096: standardDeviation = sd;
097: }
098:
099: /**
100: * For this disbution, X, this method returns P(X < <code>x</code>).
101: * @param x the value at which the CDF is evaluated.
102: * @return CDF evaluted at <code>x</code>.
103: * @throws MathException if the algorithm fails to converge.
104: */
105: public double cumulativeProbability(double x) throws MathException {
106: return 0.5 * (1.0 + Erf.erf((x - mean)
107: / (standardDeviation * Math.sqrt(2.0))));
108: }
109:
110: /**
111: * For this distribution, X, this method returns the critical point x, such
112: * that P(X < x) = <code>p</code>.
113: * <p>
114: * Returns <code>Double.NEGATIVE_INFINITY</code> for p=0 and
115: * <code>Double.POSITIVE_INFINITY</code> for p=1.
116: *
117: * @param p the desired probability
118: * @return x, such that P(X < x) = <code>p</code>
119: * @throws MathException if the inverse cumulative probability can not be
120: * computed due to convergence or other numerical errors.
121: * @throws IllegalArgumentException if <code>p</code> is not a valid
122: * probability.
123: */
124: public double inverseCumulativeProbability(final double p)
125: throws MathException {
126: if (p == 0) {
127: return Double.NEGATIVE_INFINITY;
128: }
129: if (p == 1) {
130: return Double.POSITIVE_INFINITY;
131: }
132: return super .inverseCumulativeProbability(p);
133: }
134:
135: /**
136: * Access the domain value lower bound, based on <code>p</code>, used to
137: * bracket a CDF root. This method is used by
138: * {@link #inverseCumulativeProbability(double)} to find critical values.
139: *
140: * @param p the desired probability for the critical value
141: * @return domain value lower bound, i.e.
142: * P(X < <i>lower bound</i>) < <code>p</code>
143: */
144: protected double getDomainLowerBound(double p) {
145: double ret;
146:
147: if (p < .5) {
148: ret = -Double.MAX_VALUE;
149: } else {
150: ret = getMean();
151: }
152:
153: return ret;
154: }
155:
156: /**
157: * Access the domain value upper bound, based on <code>p</code>, used to
158: * bracket a CDF root. This method is used by
159: * {@link #inverseCumulativeProbability(double)} to find critical values.
160: *
161: * @param p the desired probability for the critical value
162: * @return domain value upper bound, i.e.
163: * P(X < <i>upper bound</i>) > <code>p</code>
164: */
165: protected double getDomainUpperBound(double p) {
166: double ret;
167:
168: if (p < .5) {
169: ret = getMean();
170: } else {
171: ret = Double.MAX_VALUE;
172: }
173:
174: return ret;
175: }
176:
177: /**
178: * Access the initial domain value, based on <code>p</code>, used to
179: * bracket a CDF root. This method is used by
180: * {@link #inverseCumulativeProbability(double)} to find critical values.
181: *
182: * @param p the desired probability for the critical value
183: * @return initial domain value
184: */
185: protected double getInitialDomain(double p) {
186: double ret;
187:
188: if (p < .5) {
189: ret = getMean() - getStandardDeviation();
190: } else if (p > .5) {
191: ret = getMean() + getStandardDeviation();
192: } else {
193: ret = getMean();
194: }
195:
196: return ret;
197: }
198: }
|