Random Integers

If you have ever tried to get a random integer in JavaScript, you have probably been frustrated with converting the method Math.random results (values between 0 and slightly less than 1) to integers. There are several gotchas when converting the floating points from Math.random, in JavaScript, to integers. Todays article will walk through how to build a proper random integer generator and each gotcha you might run into.

On a first pass, one would probably come up with a method like the following:

Example 1: Math.RadomInteger() Version 1

Math.RandomInteger = function(n) {
	var i = Math.random();
	var num = Math.round(i * n);
	return num;
};

For all RandomInteger methods that we discuss today, the parameter n is the upper range of the random number, so if you want number 1 through 4, then n would equal 4. There are two issues with this version of the method: 1) the round method will sometimes round down to 0 causing a distribution of 0 through 4, and 2) the numbers will distribute themselves more frequently to integers 1 through 9. Here is the distribution you can expect from this method (for 1000 tries and digits 1 through 10):

Example 2: Math.RadomInteger() Version 1 Distribution

0 = 36
1 = 118
2 = 93
3 = 100
4 = 108
5 = 99
6 = 99
7 = 109
8 = 98
9 = 96
10 = 44
11 = 0

A random integer generator should have an equal distribution between all desired integers (so values 1 through 10 should each have occurred about 100 times). As you can see, ZERO has been returned and ten has too low of a distribution. We fix that by adding 1 to the number returned by multiplication of the random value and n:

Example 3: Math.RadomInteger() Version 2

Math.RandomInteger = function(n) {
	var i = Math.random();
	var num = Math.round(i * (n - 1) + 1);
	return num;
};

Example 4: Math.RadomInteger() Version 2 Distribution

0 = 0
1 = 52
2 = 97
3 = 116
4 = 95
5 = 128
6 = 111
7 = 113
8 = 114
9 = 122
10 = 52
11 = 0

Now we are returning the correct integers (only 1 through 10), but both ten and one have the wrong distribution (about half of what they should). The problem is using Math.round causes ten and one to loose about 50% of their values, because half rounds down for 9 < x < 9.5 and up for 1.5 <= x < 2. Instead we should use Math.floor or Math.ceil, which will consider all values between two integers to round to only 1 integer, fixing the distribution:

Example 5: Math.RadomInteger() Version 3
Math.RandomInteger = function(n) {
	var i = Math.random();
	var num = Math.ceil(i * n);
	return num;
};

Example 6: Math.RadomInteger() Version 3 Distribution

0 = 0
1 = 91
2 = 112
3 = 103
4 = 82
5 = 105
6 = 99
7 = 112
8 = 110
9 = 99
10 = 87
11 = 0

This distribution looks great, so we are done, right? Well, no, because as I mentioned above, Math.random returns ZERO through slightly less than 1. There is a very, very small chance that ZERO will be returned (although, out of several thousand tries, I was never able to get ZERO, you still want to prevent it). So, instead of using the Math.ceil, we should use Math.floor on the value we rounded in Example 3. Here is the final method:

Example 7: Math.RadomInteger() Final Version

Math.RandomInteger = function(n) {
	var i = Math.random();
	var num = Math.floor(i * n + 1);
	return num;
};

Example 8: Math.RadomInteger() Final Version Distribution

0 = 0
1 = 96
2 = 114
3 = 83
4 = 108
5 = 105
6 = 98
7 = 97
8 = 106
9 = 93
10 = 100
11 = 0

This is a pretty good distribution, and there is no chance of getting either ZERO or 11. So, this is the correct function. However, lets make one final improvement, allowing you to pass both a maximum and minimum value, returning a random integer in that range, inclusive of the end points.

Example 9: Math.RadomInteger() Max & Min Version

Math.RandomInteger = function(n, m) {
	if (! m) {m = 1;} // default range starts at 1
	var max = n > m ? n : m; // doesnt matter which value is min or max
	var min = n === max ? m : n; // min is value that is not max
	var d = max - min + 1; // distribution range
	return Math.floor(Math.random() * d + min);
};

Example 10: Math.RadomInteger() Max & Min Version (range 6-10)

0 = 0
1 = 0
2 = 0
3 = 0
4 = 0
5 = 0
6 = 197
7 = 203
8 = 204
9 = 215
10 = 181
11 = 0

Note that the 1000 values are nearly evenly distributed through six and ten. This method also supports passing just a single value (the maximum) and working as the Example 8, ranging between 1 and the maximum. I have also created a Math.RandomInteger test page, if you want to see the distributions yourself. Reload the page to have it compute the values again.

I have also included a new Math.js which I will use to augment the JavaScript native Math Object in the future.

--------------

A commenter pointed out that this method isnt the most efficient/effective random number generator available. He is correct, this is just the simplest and most easy to understand version. If you want a better random number generator then check out Mersenne Twister (MT), which has already been converted to JavaScript.