001: /*
002: * Copyright 2005 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: /**
022: * Default implementation of
023: * {@link org.apache.commons.math.distribution.CauchyDistribution}.
024: *
025: * @since 1.1
026: * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
027: */
028: public class CauchyDistributionImpl extends
029: AbstractContinuousDistribution implements CauchyDistribution,
030: Serializable {
031:
032: /** Serializable version identifier */
033: private static final long serialVersionUID = 8589540077390120676L;
034:
035: /** The median of this distribution. */
036: private double median = 0;
037:
038: /** The scale of this distribution. */
039: private double scale = 1;
040:
041: /**
042: * Creates cauchy distribution with the medain equal to zero and scale
043: * equal to one.
044: */
045: public CauchyDistributionImpl() {
046: this (0.0, 1.0);
047: }
048:
049: /**
050: * Create a cauchy distribution using the given median and scale.
051: * @param median median for this distribution
052: * @param s scale parameter for this distribution
053: */
054: public CauchyDistributionImpl(double median, double s) {
055: super ();
056: setMedian(median);
057: setScale(s);
058: }
059:
060: /**
061: * For this disbution, X, this method returns P(X < <code>x</code>).
062: * @param x the value at which the CDF is evaluated.
063: * @return CDF evaluted at <code>x</code>.
064: */
065: public double cumulativeProbability(double x) {
066: return 0.5 + (Math.atan((x - median) / scale) / Math.PI);
067: }
068:
069: /**
070: * Access the median.
071: * @return median for this distribution
072: */
073: public double getMedian() {
074: return median;
075: }
076:
077: /**
078: * Access the scale parameter.
079: * @return scale parameter for this distribution
080: */
081: public double getScale() {
082: return scale;
083: }
084:
085: /**
086: * For this distribution, X, this method returns the critical point x, such
087: * that P(X < x) = <code>p</code>.
088: * <p>
089: * Returns <code>Double.NEGATIVE_INFINITY</code> for p=0 and
090: * <code>Double.POSITIVE_INFINITY</code> for p=1.
091: *
092: * @param p the desired probability
093: * @return x, such that P(X < x) = <code>p</code>
094: * @throws IllegalArgumentException if <code>p</code> is not a valid
095: * probability.
096: */
097: public double inverseCumulativeProbability(double p) {
098: double ret;
099: if (p < 0.0 || p > 1.0) {
100: throw new IllegalArgumentException(
101: "probability argument must be between 0 and 1 (inclusive)");
102: } else if (p == 0) {
103: ret = Double.NEGATIVE_INFINITY;
104: } else if (p == 1) {
105: ret = Double.POSITIVE_INFINITY;
106: } else {
107: ret = median + scale * Math.tan(Math.PI * (p - .5));
108: }
109: return ret;
110: }
111:
112: /**
113: * Modify the median.
114: * @param median for this distribution
115: */
116: public void setMedian(double median) {
117: this .median = median;
118: }
119:
120: /**
121: * Modify the scale parameter.
122: * @param s scale parameter for this distribution
123: * @throws IllegalArgumentException if <code>sd</code> is not positive.
124: */
125: public void setScale(double s) {
126: if (s <= 0.0) {
127: throw new IllegalArgumentException(
128: "Scale must be positive.");
129: }
130: scale = s;
131: }
132:
133: /**
134: * Access the domain value lower bound, based on <code>p</code>, used to
135: * bracket a CDF root. This method is used by
136: * {@link #inverseCumulativeProbability(double)} to find critical values.
137: *
138: * @param p the desired probability for the critical value
139: * @return domain value lower bound, i.e.
140: * P(X < <i>lower bound</i>) < <code>p</code>
141: */
142: protected double getDomainLowerBound(double p) {
143: double ret;
144:
145: if (p < .5) {
146: ret = -Double.MAX_VALUE;
147: } else {
148: ret = getMedian();
149: }
150:
151: return ret;
152: }
153:
154: /**
155: * Access the domain value upper bound, based on <code>p</code>, used to
156: * bracket a CDF root. This method is used by
157: * {@link #inverseCumulativeProbability(double)} to find critical values.
158: *
159: * @param p the desired probability for the critical value
160: * @return domain value upper bound, i.e.
161: * P(X < <i>upper bound</i>) > <code>p</code>
162: */
163: protected double getDomainUpperBound(double p) {
164: double ret;
165:
166: if (p < .5) {
167: ret = getMedian();
168: } else {
169: ret = Double.MAX_VALUE;
170: }
171:
172: return ret;
173: }
174:
175: /**
176: * Access the initial domain value, based on <code>p</code>, used to
177: * bracket a CDF root. This method is used by
178: * {@link #inverseCumulativeProbability(double)} to find critical values.
179: *
180: * @param p the desired probability for the critical value
181: * @return initial domain value
182: */
183: protected double getInitialDomain(double p) {
184: double ret;
185:
186: if (p < .5) {
187: ret = getMedian() - getScale();
188: } else if (p > .5) {
189: ret = getMedian() + getScale();
190: } else {
191: ret = getMedian();
192: }
193:
194: return ret;
195: }
196: }
|