    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    }