Reputation: 145
I wanted a random number ranging from 0 to 3 and tried the following code just to see how it works.
int[] count = new int[4];
for (int i = 0; i < 1000; i++) {
int t = (int)(Math.round((Math.random() *3)));
count[t] +=1;
}
for (int i = 0; i < count.length; i++) {
System.out.println(count[i]);
}
Weird thing now is that 0 and 3 hit about half the times 1 and 2 hit, how is that possible?
Upvotes: 0
Views: 162
Reputation: 4223
class Math {
...
public static long round(double a) {
return (long)floor(a + 0.5d);
}
...
}
There is more probability to hit 1 and 2
int t = (int)(Math.ceil((Math.random() * 4))) - 1;
Using ceil instead of round gives better distribution:
250
239
242
269
Upvotes: 1
Reputation: 8586
http://docs.oracle.com/javase/6/docs/api/java/lang/Math.html#round(double)
Returns the closest long to the argument. The result is rounded to an integer by adding 1/2, taking the floor of the result, and casting the result to type long.
You're creating buckets of unequal size:
0 - 0.4999... => 0 (.5)
0.5 - 1.499... => 1 (1)
1.5 - 2.499... => 2 (1)
2.5 - 2.99999... => 3 (.5)
To fix, either use:
Random.nextInt(4);
Er... typo, thanks @TedHopp - I mean:
Random r = new Random();
...
r.nextInt(4);
Or do
(int) (Math.random() * 4);s
Which will do what you expect.
Upvotes: 2
Reputation: 54621
Look at the intervals that round to each integer:
|----+----|----+----|----+----|
0 1 2 3
<...>
Rounds to 0
<........>
Rounds to 1
<........>
Rounds to 2
<....>
Rounds to 3
You can see that the range that round to 0 and 3 is half the size as the others, so if you choose uniformly you hit them half as often.
Upvotes: 6
Reputation: 2242
This happens because you are rounding. 0 can only be rounded to if its less than 0.5. However 1 could be picked if its between 0.5 and 1.5. Therefore giving it twice the chance of occurring. The same thing happens for 2, between 1.5 and 2.5. And 3 is only from 2.5 to 3.
Upvotes: 1