View Javadoc

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 &lt; 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 &lt; 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 &lt; 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 &lt; <i>lower bound</i>) &lt; <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 &lt; <i>upper bound</i>) &gt; <code>p</code> 
136      */
137     protected double getDomainUpperBound(double p) {
138         // NOTE: exponential is skewed to the left
139         // NOTE: therefore, P(X < &mu;) > .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 < &mu;) > .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 }