Javascript’s Math.random() – when random isn’t random


Yesterday I wrote a function in Javascript that should return random integers in a given range; basically just the same as the PHP function rand($min, $max). But after a few test runs I noticed that the numbers were not quite as random as they should be; some of them appeared more often than expected, others less. It turned out that rounding with Math.round() was the culprit.

Math.round() – not such a round thing

Suppose you want to generate a random number bewtween 1 and 10. That might look like this:

randomNumber = Math.round(Math.random() * 9) + 1;

The expected result would be that all numbers will occur with a probability of 1/10 (or 10%). Unfortunately, they don’t. Instead, 1 and 10 appear less often than the remaining numbers. Why is that so?
Quite simple: The result of Math.random()*9 can take any value between 0 and 8,9. And now let’s have a look at how the values are rounded afterwards:

0 – 0,49 0,5 – 1,49 1,5 – 2,49 2,5 – 3,49 3,5 – 4,49 4,5 – 5,49 5,5 – 6,49 6,5 – 7,49 7,5 – 8,49 8,5 – 8,99
0 1 2 3 4 5 6 7 8 9

As you can see in this table (I tried to make it visually clearer using different column widths), there’s only an interval of 0.5 each that has the chance of becoming rounded to 0 or 9, while for all the other numbers it’s an interval of 1. This explains why the desired minimum and maximum values occur only half as often as the remaining numbers. But how else can we get rid of the decimal places?

Math.floor() is your friend! :)

Exactly, let’s just always round the number down. But wait! What about the 10? It will no longer show up then, because the maximum possible value of Math.random()*9 will always be rounded down to 8! True – so we’ll simply increase the multiplier by 1:

randomNumber = Math.floor(Math.random() * 10) + 1;

Now the random numbers are distributed as expected, that is about evenly. With this knowledge you can now finally write a properly functioning, easy to use, PHP-like random function:

function rand(min, max) {
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

P.S.: There is no seed parameter!

There is a persistent rumor that one could pass a value (a so-called “seed” parameter) to the random() function, which it should then use as the basis for its random calculation. Thus, it has become a bad habit to pass the current seconds or milliseconds to the function in the hope that the numbers will somehow become more “random”:

now = new Date();
seed = now.getMilliseconds();
randomNumber = Math.floor(Math.random(seed) * 10) + 1

Well … Unfortunately, this is nonsense. :) Such a parameter does not exist. You won’t find it in any Javascript documentation either. Any value that you pass to the function is simply being ignored. (However, the construction with the time is kind of extra foolish, because Math.random() always uses the current time as its calculation basis anyway.)


One response to “Javascript’s Math.random() – when random isn’t random”

Leave a Reply

Your email address will not be published. Required fields are marked *