    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    }