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    
018    package org.apache.commons.math3.distribution;
019    
020    import org.apache.commons.math3.exception.NumberIsTooLargeException;
021    import org.apache.commons.math3.exception.util.LocalizedFormats;
022    import org.apache.commons.math3.random.RandomGenerator;
023    import org.apache.commons.math3.random.Well19937c;
024    import org.apache.commons.math3.util.FastMath;
025    
026    /**
027     * Implementation of the uniform integer distribution.
028     *
029     * @see <a href="http://en.wikipedia.org/wiki/Uniform_distribution_(discrete)"
030     * >Uniform distribution (discrete), at Wikipedia</a>
031     *
032     * @version $Id: UniformIntegerDistribution.java 1416643 2012-12-03 19:37:14Z tn $
033     * @since 3.0
034     */
035    public class UniformIntegerDistribution extends AbstractIntegerDistribution {
036        /** Serializable version identifier. */
037        private static final long serialVersionUID = 20120109L;
038        /** Lower bound (inclusive) of this distribution. */
039        private final int lower;
040        /** Upper bound (inclusive) of this distribution. */
041        private final int upper;
042    
043        /**
044         * Creates a new uniform integer distribution using the given lower and
045         * upper bounds (both inclusive).
046         *
047         * @param lower Lower bound (inclusive) of this distribution.
048         * @param upper Upper bound (inclusive) of this distribution.
049         * @throws NumberIsTooLargeException if {@code lower >= upper}.
050         */
051        public UniformIntegerDistribution(int lower, int upper)
052            throws NumberIsTooLargeException {
053            this(new Well19937c(), lower, upper);
054        }
055    
056        /**
057         * Creates a new uniform integer distribution using the given lower and
058         * upper bounds (both inclusive).
059         *
060         * @param rng Random number generator.
061         * @param lower Lower bound (inclusive) of this distribution.
062         * @param upper Upper bound (inclusive) of this distribution.
063         * @throws NumberIsTooLargeException if {@code lower >= upper}.
064         * @since 3.1
065         */
066        public UniformIntegerDistribution(RandomGenerator rng,
067                                          int lower,
068                                          int upper)
069            throws NumberIsTooLargeException {
070            super(rng);
071    
072            if (lower >= upper) {
073                throw new NumberIsTooLargeException(
074                                LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND,
075                                lower, upper, false);
076            }
077            this.lower = lower;
078            this.upper = upper;
079        }
080    
081        /** {@inheritDoc} */
082        public double probability(int x) {
083            if (x < lower || x > upper) {
084                return 0;
085            }
086            return 1.0 / (upper - lower + 1);
087        }
088    
089        /** {@inheritDoc} */
090        public double cumulativeProbability(int x) {
091            if (x < lower) {
092                return 0;
093            }
094            if (x > upper) {
095                return 1;
096            }
097            return (x - lower + 1.0) / (upper - lower + 1.0);
098        }
099    
100        /**
101         * {@inheritDoc}
102         *
103         * For lower bound {@code lower} and upper bound {@code upper}, the mean is
104         * {@code 0.5 * (lower + upper)}.
105         */
106        public double getNumericalMean() {
107            return 0.5 * (lower + upper);
108        }
109    
110        /**
111         * {@inheritDoc}
112         *
113         * For lower bound {@code lower} and upper bound {@code upper}, and
114         * {@code n = upper - lower + 1}, the variance is {@code (n^2 - 1) / 12}.
115         */
116        public double getNumericalVariance() {
117            double n = upper - lower + 1;
118            return (n * n - 1) / 12.0;
119        }
120    
121        /**
122         * {@inheritDoc}
123         *
124         * The lower bound of the support is equal to the lower bound parameter
125         * of the distribution.
126         *
127         * @return lower bound of the support
128         */
129        public int getSupportLowerBound() {
130            return lower;
131        }
132    
133        /**
134         * {@inheritDoc}
135         *
136         * The upper bound of the support is equal to the upper bound parameter
137         * of the distribution.
138         *
139         * @return upper bound of the support
140         */
141        public int getSupportUpperBound() {
142            return upper;
143        }
144    
145        /**
146         * {@inheritDoc}
147         *
148         * The support of this distribution is connected.
149         *
150         * @return {@code true}
151         */
152        public boolean isSupportConnected() {
153            return true;
154        }
155    
156        /** {@inheritDoc} */
157        @Override
158        public int sample() {
159            final double r = random.nextDouble();
160            final double scaled = r * upper + (1 - r) * lower + r;
161            return (int) FastMath.floor(scaled);
162        }
163    }