001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.math3.distribution;
018
019 import org.apache.commons.math3.exception.OutOfRangeException;
020 import org.apache.commons.math3.exception.NotPositiveException;
021 import org.apache.commons.math3.exception.util.LocalizedFormats;
022 import org.apache.commons.math3.special.Beta;
023 import org.apache.commons.math3.util.FastMath;
024 import org.apache.commons.math3.random.RandomGenerator;
025 import org.apache.commons.math3.random.Well19937c;
026
027 /**
028 * Implementation of the binomial distribution.
029 *
030 * @see <a href="http://en.wikipedia.org/wiki/Binomial_distribution">Binomial distribution (Wikipedia)</a>
031 * @see <a href="http://mathworld.wolfram.com/BinomialDistribution.html">Binomial Distribution (MathWorld)</a>
032 * @version $Id: BinomialDistribution.java 1416643 2012-12-03 19:37:14Z tn $
033 */
034 public class BinomialDistribution extends AbstractIntegerDistribution {
035 /** Serializable version identifier. */
036 private static final long serialVersionUID = 6751309484392813623L;
037 /** The number of trials. */
038 private final int numberOfTrials;
039 /** The probability of success. */
040 private final double probabilityOfSuccess;
041
042 /**
043 * Create a binomial distribution with the given number of trials and
044 * probability of success.
045 *
046 * @param trials Number of trials.
047 * @param p Probability of success.
048 * @throws NotPositiveException if {@code trials < 0}.
049 * @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
050 */
051 public BinomialDistribution(int trials, double p) {
052 this(new Well19937c(), trials, p);
053 }
054
055 /**
056 * Creates a binomial distribution.
057 *
058 * @param rng Random number generator.
059 * @param trials Number of trials.
060 * @param p Probability of success.
061 * @throws NotPositiveException if {@code trials < 0}.
062 * @throws OutOfRangeException if {@code p < 0} or {@code p > 1}.
063 * @since 3.1
064 */
065 public BinomialDistribution(RandomGenerator rng,
066 int trials,
067 double p) {
068 super(rng);
069
070 if (trials < 0) {
071 throw new NotPositiveException(LocalizedFormats.NUMBER_OF_TRIALS,
072 trials);
073 }
074 if (p < 0 || p > 1) {
075 throw new OutOfRangeException(p, 0, 1);
076 }
077
078 probabilityOfSuccess = p;
079 numberOfTrials = trials;
080 }
081
082 /**
083 * Access the number of trials for this distribution.
084 *
085 * @return the number of trials.
086 */
087 public int getNumberOfTrials() {
088 return numberOfTrials;
089 }
090
091 /**
092 * Access the probability of success for this distribution.
093 *
094 * @return the probability of success.
095 */
096 public double getProbabilityOfSuccess() {
097 return probabilityOfSuccess;
098 }
099
100 /** {@inheritDoc} */
101 public double probability(int x) {
102 double ret;
103 if (x < 0 || x > numberOfTrials) {
104 ret = 0.0;
105 } else {
106 ret = FastMath.exp(SaddlePointExpansion.logBinomialProbability(x,
107 numberOfTrials, probabilityOfSuccess,
108 1.0 - probabilityOfSuccess));
109 }
110 return ret;
111 }
112
113 /** {@inheritDoc} */
114 public double cumulativeProbability(int x) {
115 double ret;
116 if (x < 0) {
117 ret = 0.0;
118 } else if (x >= numberOfTrials) {
119 ret = 1.0;
120 } else {
121 ret = 1.0 - Beta.regularizedBeta(probabilityOfSuccess,
122 x + 1.0, numberOfTrials - x);
123 }
124 return ret;
125 }
126
127 /**
128 * {@inheritDoc}
129 *
130 * For {@code n} trials and probability parameter {@code p}, the mean is
131 * {@code n * p}.
132 */
133 public double getNumericalMean() {
134 return numberOfTrials * probabilityOfSuccess;
135 }
136
137 /**
138 * {@inheritDoc}
139 *
140 * For {@code n} trials and probability parameter {@code p}, the variance is
141 * {@code n * p * (1 - p)}.
142 */
143 public double getNumericalVariance() {
144 final double p = probabilityOfSuccess;
145 return numberOfTrials * p * (1 - p);
146 }
147
148 /**
149 * {@inheritDoc}
150 *
151 * The lower bound of the support is always 0 except for the probability
152 * parameter {@code p = 1}.
153 *
154 * @return lower bound of the support (0 or the number of trials)
155 */
156 public int getSupportLowerBound() {
157 return probabilityOfSuccess < 1.0 ? 0 : numberOfTrials;
158 }
159
160 /**
161 * {@inheritDoc}
162 *
163 * The upper bound of the support is the number of trials except for the
164 * probability parameter {@code p = 0}.
165 *
166 * @return upper bound of the support (number of trials or 0)
167 */
168 public int getSupportUpperBound() {
169 return probabilityOfSuccess > 0.0 ? numberOfTrials : 0;
170 }
171
172 /**
173 * {@inheritDoc}
174 *
175 * The support of this distribution is connected.
176 *
177 * @return {@code true}
178 */
179 public boolean isSupportConnected() {
180 return true;
181 }
182 }