Showing posts with label rounding. Show all posts
Showing posts with label rounding. Show all posts

Thursday, 19 November 2009

Don't take your random() for granted...

In my current project, we use a functionality which chooses a random colour for a machine. To do this, we need to select a colour from a set of 8 colours. In our Flex application we use a function called randomInt, which generates a random integer between a and b:

public static function randomInt(a:int, b:int):int {
return Math.round(Math.random()*(b-a))+a;
}


Usually we look for functions like these on the internet, but I’d like to emphasize that you also should unit-test functions which are made by others.

So I’ve generated 5000 integers between 0 and 20 in a test application, and put that in a graph:



Note that the numbers on the boundaries, 0 and 20, are significantly chosen less times than the others (1-19). This would mean, that if this function is used for picking a random machine colour, the colours 0 and 7 have only a 7% chance to be selected, while others have a 14% chance!

I’ve talked about this to someone who knows a lot of these mathematical things. The problem is the rounding. Since Math.round() returns a pseudo-random number n, where 0 <= n <>
We need to include the boundaries to produce a evenly distributed random integer. This is the new function:
private function randomInt(a:int, c:int):int {
var b:int = c + 1;
return Math.floor(Math.random()*(b-a))+a;
}


Doing the same test, produces this graph:



As you can see, each integer is chosen about the same number of times. Now we know for sure that colours 0 and 7 won’t stay in storage, but are also sold!