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 018package org.apache.commons.math3.distribution; 019 020import org.apache.commons.math3.exception.NumberIsTooLargeException; 021import org.apache.commons.math3.exception.util.LocalizedFormats; 022import org.apache.commons.math3.random.RandomGenerator; 023import org.apache.commons.math3.random.Well19937c; 024 025/** 026 * Implementation of the uniform integer distribution. 027 * 028 * @see <a href="http://en.wikipedia.org/wiki/Uniform_distribution_(discrete)" 029 * >Uniform distribution (discrete), at Wikipedia</a> 030 * 031 * @since 3.0 032 */ 033public class UniformIntegerDistribution extends AbstractIntegerDistribution { 034 /** Serializable version identifier. */ 035 private static final long serialVersionUID = 20120109L; 036 /** Lower bound (inclusive) of this distribution. */ 037 private final int lower; 038 /** Upper bound (inclusive) of this distribution. */ 039 private final int upper; 040 041 /** 042 * Creates a new uniform integer distribution using the given lower and 043 * upper bounds (both inclusive). 044 * <p> 045 * <b>Note:</b> this constructor will implicitly create an instance of 046 * {@link Well19937c} as random generator to be used for sampling only (see 047 * {@link #sample()} and {@link #sample(int)}). In case no sampling is 048 * needed for the created distribution, it is advised to pass {@code null} 049 * as random generator via the appropriate constructors to avoid the 050 * additional initialisation overhead. 051 * 052 * @param lower Lower bound (inclusive) of this distribution. 053 * @param upper Upper bound (inclusive) of this distribution. 054 * @throws NumberIsTooLargeException if {@code lower >= upper}. 055 */ 056 public UniformIntegerDistribution(int lower, int upper) 057 throws NumberIsTooLargeException { 058 this(new Well19937c(), lower, upper); 059 } 060 061 /** 062 * Creates a new uniform integer distribution using the given lower and 063 * upper bounds (both inclusive). 064 * 065 * @param rng Random number generator. 066 * @param lower Lower bound (inclusive) of this distribution. 067 * @param upper Upper bound (inclusive) of this distribution. 068 * @throws NumberIsTooLargeException if {@code lower > upper}. 069 * @since 3.1 070 */ 071 public UniformIntegerDistribution(RandomGenerator rng, 072 int lower, 073 int upper) 074 throws NumberIsTooLargeException { 075 super(rng); 076 077 if (lower > upper) { 078 throw new NumberIsTooLargeException( 079 LocalizedFormats.LOWER_BOUND_NOT_BELOW_UPPER_BOUND, 080 lower, upper, true); 081 } 082 this.lower = lower; 083 this.upper = upper; 084 } 085 086 /** {@inheritDoc} */ 087 public double probability(int x) { 088 if (x < lower || x > upper) { 089 return 0; 090 } 091 return 1.0 / (upper - lower + 1); 092 } 093 094 /** {@inheritDoc} */ 095 public double cumulativeProbability(int x) { 096 if (x < lower) { 097 return 0; 098 } 099 if (x > upper) { 100 return 1; 101 } 102 return (x - lower + 1.0) / (upper - lower + 1.0); 103 } 104 105 /** 106 * {@inheritDoc} 107 * 108 * For lower bound {@code lower} and upper bound {@code upper}, the mean is 109 * {@code 0.5 * (lower + upper)}. 110 */ 111 public double getNumericalMean() { 112 return 0.5 * (lower + upper); 113 } 114 115 /** 116 * {@inheritDoc} 117 * 118 * For lower bound {@code lower} and upper bound {@code upper}, and 119 * {@code n = upper - lower + 1}, the variance is {@code (n^2 - 1) / 12}. 120 */ 121 public double getNumericalVariance() { 122 double n = upper - lower + 1; 123 return (n * n - 1) / 12.0; 124 } 125 126 /** 127 * {@inheritDoc} 128 * 129 * The lower bound of the support is equal to the lower bound parameter 130 * of the distribution. 131 * 132 * @return lower bound of the support 133 */ 134 public int getSupportLowerBound() { 135 return lower; 136 } 137 138 /** 139 * {@inheritDoc} 140 * 141 * The upper bound of the support is equal to the upper bound parameter 142 * of the distribution. 143 * 144 * @return upper bound of the support 145 */ 146 public int getSupportUpperBound() { 147 return upper; 148 } 149 150 /** 151 * {@inheritDoc} 152 * 153 * The support of this distribution is connected. 154 * 155 * @return {@code true} 156 */ 157 public boolean isSupportConnected() { 158 return true; 159 } 160 161 /** {@inheritDoc} */ 162 @Override 163 public int sample() { 164 final int max = (upper - lower) + 1; 165 if (max <= 0) { 166 // The range is too wide to fit in a positive int (larger 167 // than 2^31); as it covers more than half the integer range, 168 // we use a simple rejection method. 169 while (true) { 170 final int r = random.nextInt(); 171 if (r >= lower && 172 r <= upper) { 173 return r; 174 } 175 } 176 } else { 177 // We can shift the range and directly generate a positive int. 178 return lower + random.nextInt(max); 179 } 180 } 181}