1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
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.Beta;
23
24 /**
25 * Default implementation of
26 * {@link org.apache.commons.math.distribution.FDistribution}.
27 *
28 * @version $Revision: 619917 $ $Date: 2008-02-08 08:44:11 -0700 (Fri, 08 Feb 2008) $
29 */
30 public class FDistributionImpl
31 extends AbstractContinuousDistribution
32 implements FDistribution, Serializable {
33
34 /** Serializable version identifier */
35 private static final long serialVersionUID = -8516354193418641566L;
36
37 /** The numerator degrees of freedom*/
38 private double numeratorDegreesOfFreedom;
39
40 /** The numerator degrees of freedom*/
41 private double denominatorDegreesOfFreedom;
42
43 /**
44 * Create a F distribution using the given degrees of freedom.
45 * @param numeratorDegreesOfFreedom the numerator degrees of freedom.
46 * @param denominatorDegreesOfFreedom the denominator degrees of freedom.
47 */
48 public FDistributionImpl(double numeratorDegreesOfFreedom,
49 double denominatorDegreesOfFreedom) {
50 super();
51 setNumeratorDegreesOfFreedom(numeratorDegreesOfFreedom);
52 setDenominatorDegreesOfFreedom(denominatorDegreesOfFreedom);
53 }
54
55 /**
56 * For this distribution, X, this method returns P(X < x).
57 *
58 * The implementation of this method is based on:
59 * <ul>
60 * <li>
61 * <a href="http://mathworld.wolfram.com/F-Distribution.html">
62 * F-Distribution</a>, equation (4).</li>
63 * </ul>
64 *
65 * @param x the value at which the CDF is evaluated.
66 * @return CDF for this distribution.
67 * @throws MathException if the cumulative probability can not be
68 * computed due to convergence or other numerical errors.
69 */
70 public double cumulativeProbability(double x) throws MathException {
71 double ret;
72 if (x <= 0.0) {
73 ret = 0.0;
74 } else {
75 double n = getNumeratorDegreesOfFreedom();
76 double m = getDenominatorDegreesOfFreedom();
77
78 ret = Beta.regularizedBeta((n * x) / (m + n * x),
79 0.5 * n,
80 0.5 * m);
81 }
82 return ret;
83 }
84
85 /**
86 * For this distribution, X, this method returns the critical point x, such
87 * that P(X < x) = <code>p</code>.
88 * <p>
89 * Returns 0 for p=0 and <code>Double.POSITIVE_INFINITY</code> for p=1.</p>
90 *
91 * @param p the desired probability
92 * @return x, such that P(X < x) = <code>p</code>
93 * @throws MathException if the inverse cumulative probability can not be
94 * computed due to convergence or other numerical errors.
95 * @throws IllegalArgumentException if <code>p</code> is not a valid
96 * probability.
97 */
98 public double inverseCumulativeProbability(final double p)
99 throws MathException {
100 if (p == 0) {
101 return 0d;
102 }
103 if (p == 1) {
104 return Double.POSITIVE_INFINITY;
105 }
106 return super.inverseCumulativeProbability(p);
107 }
108
109 /**
110 * Access the domain value lower bound, based on <code>p</code>, used to
111 * bracket a CDF root. This method is used by
112 * {@link #inverseCumulativeProbability(double)} to find critical values.
113 *
114 * @param p the desired probability for the critical value
115 * @return domain value lower bound, i.e.
116 * P(X < <i>lower bound</i>) < <code>p</code>
117 */
118 protected double getDomainLowerBound(double p) {
119 return 0.0;
120 }
121
122 /**
123 * Access the domain value upper bound, based on <code>p</code>, used to
124 * bracket a CDF root. This method is used by
125 * {@link #inverseCumulativeProbability(double)} to find critical values.
126 *
127 * @param p the desired probability for the critical value
128 * @return domain value upper bound, i.e.
129 * P(X < <i>upper bound</i>) > <code>p</code>
130 */
131 protected double getDomainUpperBound(double p) {
132 return Double.MAX_VALUE;
133 }
134
135 /**
136 * Access the initial domain value, 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 initial domain value
142 */
143 protected double getInitialDomain(double p) {
144 return getDenominatorDegreesOfFreedom() /
145 (getDenominatorDegreesOfFreedom() - 2.0);
146 }
147
148 /**
149 * Modify the numerator degrees of freedom.
150 * @param degreesOfFreedom the new numerator degrees of freedom.
151 * @throws IllegalArgumentException if <code>degreesOfFreedom</code> is not
152 * positive.
153 */
154 public void setNumeratorDegreesOfFreedom(double degreesOfFreedom) {
155 if (degreesOfFreedom <= 0.0) {
156 throw new IllegalArgumentException(
157 "degrees of freedom must be positive.");
158 }
159 this.numeratorDegreesOfFreedom = degreesOfFreedom;
160 }
161
162 /**
163 * Access the numerator degrees of freedom.
164 * @return the numerator degrees of freedom.
165 */
166 public double getNumeratorDegreesOfFreedom() {
167 return numeratorDegreesOfFreedom;
168 }
169
170 /**
171 * Modify the denominator degrees of freedom.
172 * @param degreesOfFreedom the new denominator degrees of freedom.
173 * @throws IllegalArgumentException if <code>degreesOfFreedom</code> is not
174 * positive.
175 */
176 public void setDenominatorDegreesOfFreedom(double degreesOfFreedom) {
177 if (degreesOfFreedom <= 0.0) {
178 throw new IllegalArgumentException(
179 "degrees of freedom must be positive.");
180 }
181 this.denominatorDegreesOfFreedom = degreesOfFreedom;
182 }
183
184 /**
185 * Access the denominator degrees of freedom.
186 * @return the denominator degrees of freedom.
187 */
188 public double getDenominatorDegreesOfFreedom() {
189 return denominatorDegreesOfFreedom;
190 }
191 }