This function is from java.util.Random
. It returns a pseudorandom int
uniformly distributed between 0
and the given n
. Unfortunately I did not get it.
public int nextInt(int n) {
if (n <= 0)
throw new IllegalArgumentException("n must be positive");
if ((n & -n) == n) // i.e., n is a power of 2
return (int)((n * (long)next(31)) >> 31);
int bits, val;
do {
bits = next(31);
val = bits % n;
} while (bits - val + (n-1) < 0);
return val;
}
My questions are:
- Why does it treat the case where
n
is a power of two specially ? Is it just for performance ? - Why doest it reject numbers that
bits - val + (n-1) < 0
?
It does this in order to assure an uniform distribution of values between
0
andn
. You might be tempted to do something like:but this will alter the distribution of values, unless n is a divisor of
2^31
, i.e. a power of 2. This is because the modulo operator would produce equivalence classes whose size is not the same.For instance, let's suppose that
nextInt()
generates an integer between 0 and 6 inclusive and you want to draw 0,1 or 2. Easy, right?No. Let's see why:
So you have 3 values that map on 0 and only 2 values that map on 1 and 2. You have a bias now, as 0 is more likely to be returned than 1 or 2.
As always, the javadoc documents this behaviour:
The emphasis is mine.
next
generates random bits.When
n
is a power of 2, a random integer in that range can be generated just by generating random bits (I assume that always generating 31 and throwing some away is for reproducibility). This code path is simpler and I guess it's a more commonly used case so it's worth making a special "fast path" for this case.When
n
isn't a power of 2, it throws away numbers at the "top" of the range so that the random number is evenly distributed. E.g. imagine we hadn=3
, and imagine we were using 3 bits rather than 31 bits. Sobits
is a randomly generated number between 0 and 7. How can you generate a fair random number there? Answer: ifbits
is 6 or 7, we throw it away and generate a new one.