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    }