1 /*
2 * Copyright 2003-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 package org.apache.commons.math.distribution;
17
18 import java.io.Serializable;
19
20 import org.apache.commons.math.MathException;
21
22 /**
23 * The default implementation of {@link ExponentialDistribution}.
24 *
25 * @version $Revision: 355770 $ $Date: 2005-12-10 12:48:57 -0700 (Sat, 10 Dec 2005) $
26 */
27 public class ExponentialDistributionImpl extends AbstractContinuousDistribution
28 implements ExponentialDistribution, Serializable {
29
30 /** Serializable version identifier */
31 private static final long serialVersionUID = 2401296428283614780L;
32
33 /** The mean of this distribution. */
34 private double mean;
35
36 /**
37 * Create a exponential distribution with the given mean.
38 * @param mean mean of this distribution.
39 */
40 public ExponentialDistributionImpl(double mean) {
41 super();
42 setMean(mean);
43 }
44
45 /**
46 * Modify the mean.
47 * @param mean the new mean.
48 * @throws IllegalArgumentException if <code>mean</code> is not positive.
49 */
50 public void setMean(double mean) {
51 if (mean <= 0.0) {
52 throw new IllegalArgumentException("mean must be positive.");
53 }
54 this.mean = mean;
55 }
56
57 /**
58 * Access the mean.
59 * @return the mean.
60 */
61 public double getMean() {
62 return mean;
63 }
64
65 /**
66 * For this disbution, X, this method returns P(X < x).
67 *
68 * The implementation of this method is based on:
69 * <ul>
70 * <li>
71 * <a href="http://mathworld.wolfram.com/ExponentialDistribution.html">
72 * Exponential Distribution</a>, equation (1).</li>
73 * </ul>
74 *
75 * @param x the value at which the CDF is evaluated.
76 * @return CDF for this distribution.
77 * @throws MathException if the cumulative probability can not be
78 * computed due to convergence or other numerical errors.
79 */
80 public double cumulativeProbability(double x) throws MathException{
81 double ret;
82 if (x <= 0.0) {
83 ret = 0.0;
84 } else {
85 ret = 1.0 - Math.exp(-x / getMean());
86 }
87 return ret;
88 }
89
90 /**
91 * For this distribution, X, this method returns the critical point x, such
92 * that P(X < x) = <code>p</code>.
93 * <p>
94 * Returns 0 for p=0 and <code>Double.POSITIVE_INFINITY</code> for p=1.
95 *
96 * @param p the desired probability
97 * @return x, such that P(X < x) = <code>p</code>
98 * @throws MathException if the inverse cumulative probability can not be
99 * computed due to convergence or other numerical errors.
100 * @throws IllegalArgumentException if p < 0 or p > 1.
101 */
102 public double inverseCumulativeProbability(double p) throws MathException {
103 double ret;
104
105 if (p < 0.0 || p > 1.0) {
106 throw new IllegalArgumentException
107 ("probability argument must be between 0 and 1 (inclusive)");
108 } else if (p == 1.0) {
109 ret = Double.POSITIVE_INFINITY;
110 } else {
111 ret = -getMean() * Math.log(1.0 - p);
112 }
113
114 return ret;
115 }
116
117 /**
118 * Access the domain value lower bound, based on <code>p</code>, used to
119 * bracket a CDF root.
120 *
121 * @param p the desired probability for the critical value
122 * @return domain value lower bound, i.e.
123 * P(X < <i>lower bound</i>) < <code>p</code>
124 */
125 protected double getDomainLowerBound(double p) {
126 return 0;
127 }
128
129 /**
130 * Access the domain value upper bound, based on <code>p</code>, used to
131 * bracket a CDF root.
132 *
133 * @param p the desired probability for the critical value
134 * @return domain value upper bound, i.e.
135 * P(X < <i>upper bound</i>) > <code>p</code>
136 */
137 protected double getDomainUpperBound(double p) {
138 // NOTE: exponential is skewed to the left
139 // NOTE: therefore, P(X < μ) > .5
140
141 if (p < .5) {
142 // use mean
143 return getMean();
144 } else {
145 // use max
146 return Double.MAX_VALUE;
147 }
148 }
149
150 /**
151 * Access the initial domain value, based on <code>p</code>, used to
152 * bracket a CDF root.
153 *
154 * @param p the desired probability for the critical value
155 * @return initial domain value
156 */
157 protected double getInitialDomain(double p) {
158 // TODO: try to improve on this estimate
159 // Exponential is skewed to the left, therefore, P(X < μ) > .5
160 if (p < .5) {
161 // use 1/2 mean
162 return getMean() * .5;
163 } else {
164 // use mean
165 return getMean();
166 }
167 }
168 }