Make JavaScript Math.random() useful

Posted Aug 3, 2004
Last Updated Sep 30, 2013

The JavaScript function Math.random() randomly generates a number from 0 to slightly less than 1 (shown as <1). This is great, and all, but when was the last time someone told you to pick a number between 0 and slightly less than 1? Never? How do we transform these numbers into something usable, say a whole number between 1 and 3. (One and ten are more common, but the illustrations would be too huge.) First, we could multiply. Let’s try multiplying by 3.

Math.random() * 3

This gets us numbers from 0 to <3. But we want between 1 and 3. We’ll try multiplying and adding.

Math.random() * 2 + 1

Great. This will get us numbers from 1 to <3. (First it generates a number from 0 to <2, then adds 1.) Lets see how this looks on a number line:

1    1.5    2    2.5    3 
|-----|-----|-----|-----|

Good. But this still gives us decimal numbers such as 1.56734. We want whole number. So naturally we should round. Lets try:

Math.round(Math.random*2+1)

This will produce whole numbers between 1 and 3 inclusive. However, the numbers are perfectly random. To be perfectly random each number should appear the same number of times, but in this case the number 2 will appear most often. Let’s put this on a number line. Recall from elementary school that things <.5 round down and >.5 round up.

1    1.5    2    2.5    3 
|-----|-----|-----|-----|
1<<<<<>>>>>>2<<<<<>>>>>>3

So as you can see, the segment that rounds to two is twice as long as the segments that round to one or three.

The fix

How about we change our math a little and always round up. The function we need is called the ceiling function because it rounds a number up to the “ceiling.”

Math.ceil(Math.random()*3)

Going to the number line:

0    0.5     1    1.5    2    2.5    3 
|-----|------|-----|-----|-----|-----| 
0>>>>>>>>>>>>1>>>>>>>>>>>2>>>>>>>>>>>3 

Awesome. However, (oh no, not again) remember how the Math.random() function gives us numbers from 0 to <1? That mean there is a super-slim chance of getting exactly 0. Math.ceil(0) equals 0. So there is a slim chance we will get 0 as a result.

The real fix

We don’t have to round to get integers. We can truncate. This means that we just throw away anything after the decimal point. OK, so this is technically the same as always rounding down, but whatever. This function is called the floor function.

Math.floor(Math.random()*3+1)

Lets go through it. First we get a number between 0 and <3 and then add 1 to it. This gives us 1 to <4. Remember that slightly less than 4 could be 3.99999 but it will never be 4. So when we floor the number we will always get a whole number between 1 and 3 inclusive. Check out the number line:

1    1.5     2    2.5    3    3.5    4 
|-----|------|-----|-----|-----|-----| 
1<<<<<<<<<<<<2<<<<<<<<<<<3<<<<<<<<<<<
In conclusion, random numbers are only purely random if you transform them correctly. Otherwise you get skewed and unexpected results. Use: Math.floor(Math.random()*max+1) to get numbers between 1 and max.

Homework: make a function to get numbers between min and max. Play around with these functions at: ThePenry.net Math.random() page.

Knowledge is power. Power corrupts. You are now more corrupted.

Comment

No HTML Tags are permitted.

Ravi

Nov 7, 2014

thanks dude

Bob

Mar 28, 2013

I dispute the following: "To be perfectly random each number should appear the same number of times..."
Random means there no way to predict the next event and not equal distribution. For instance, a coin flip is a random event. If you flip a fair coin 100 times & you get heads all 100 times (a highly unlikely but possible outcome) what are the odds of getting heads on toss #101?
Your claim of equal distribution would mean that you would almost certainly get tails on toss #101 to start evening out the distribution. Whereas, the actual chance for getting heads on toss #101 is still 0.5.

vincent piel

Nov 24, 2012

the REAL fix : only floor the 'scaled' random(), not the initial value :
in your example : 1+Math.floor(3*Math.random())
general case is : firstIndex + ( Math.floor( ( lastIndex - firstIndex + 1 ) *Math.random() )

nice anyway, because if your input is allready a 'float' number (expl : 5.4256) random between
n and p (integers expl : between 4 and 10 ) and that you want to use it to find an array index you have to think about using
ceil and +0,5.

Dev Sharma

Feb 25, 2011

its a good trick

Julien de Prabère

Feb 5, 2011

Hello

Is really the value 1 exluded for Math.random() ?

If not you should write :

do {nbr = Math.floor(Math.random()*max+1)} while (nbr==max+1);

Anonymous

Mar 17, 2011

The chance of this is really low. It's safe to assume it won't, even if it is implementation-dependent. The chance of the user misreading the number is probably greater, and they can just reload the page

Julien de Prabère

Aug 13, 2013

The value 1 is really excluded !
ECMA Syandard 5.1 Edition / June 2011 (extract)
About Function Properties of the Math Object
15.8.2.14 random ( )
Returns a Number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy. This function takes no arguments.

// To choose randomly an element in an array
Array.prototype.randomChoice=function(){return this.splice(Math.floor(Math.random()*this.length),1)}

// A card game
var i,arrObj=[],nbrObj=52,crrStr='';
for (i=0;i

Comment ignored.

Aegean BM

Sep 6, 2010

A common task is get a random item from an array (list) such as a card from a deck. Using your formula above, and knowing that array.length is max+1, I use the following helper function often. It's nice in that it doesn't have to know the size of the list or even what the list holds; just go get one random item from the list.



function getRandomItemFrom(list) {

return list[Math.floor(Math.random()*list.length)];

}

[author]

Sep 22, 2010

function getRandomItemFrom(list) {

return list[Math.floor(Math.random()*list.length-1)];

}
Sky Writer