18
votes

How is randomness achieved with Math.random in javascript? I've made something that picks between around 50 different options randomly. I'm wondering how comfortable I should be with using Math.random to get my randomness.

5
@David: it's not true randomness as you know. Attributed to John von Neumann: "Anyone who considers arithmetical methods of producing random digits is, of course, in a state of sin." They're using a PRNG. Pseudo-Random Number Generator. - cocotwo
@cocotwo: that doesnt mean all JS has to be psuedo random, from the spec Bob posted below, it CAN be real random. It would just be up to the implementation to use a real RNG, which is not as difficult as it once was. - Neil N
As some answers below say, it really depends on what you want to do. I suspect for 99% of cases, Math.random is fine, but it can potentially be predicted. - Alex Wayne

5 Answers

14
votes

From the specifications:

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.

So the answer is that it depends on what JavaScript engine you're using.

I'm not sure if all browsers use the same strategy or what that strategy is unfortunately

It should be fine for your purposes. Only if you're doing a large amount of numbers would you begin to see a pattern

12
votes

Using Math.random() is fine if you're not centrally pooling & using the results, i.e. for OAuth.

For example, our site used Math.random() to generate random "nonce" strings for use with OAuth. The original JavaScript library did this by choosing a character from a predetermined list using Math.random(): i.e.

for (var i = 0; i < length; ++i) {
    var rnum = Math.floor(Math.random() * chars.length);
    result += chars.substring(rnum, rnum+1);
}

The problem is, users were getting duplicate nonce strings (even using a 10 character length - theoretically ~10^18 combinations), usually within a few seconds of each other. My guess this is due to Math.random() seeding from the timestamp, as one of the other posters mentioned.

3
votes

The exact implementation can of course differ somewhat depending on the browser, but they all use some kind of pseudo random number generator. Although it's not really random, it's certainly good enough for all general purposes.

You should only be worried about the randomness if you are using it for something that needs exceptionally good randomness, like encryption or simulating a game of chance in play for money, but then you would hardly use Javascript anyway.

2
votes

It's 100% random enough for your purposes. It's seeded by time, so every time you run it, you'll get different results.

Paste this into your browsers address bar...

javascript:alert(Math.random() * 2 > 1);

and press [Enter] a few times... I got "true, false, false, true" - random enough :)

1
votes

This is a little overkill...but, I couldn't resist doing this :)

You can execute this in your browser address bar. It generates a random number between 0 and 4, 100000 times. And outputs the number of times each number was generated and the number of times one random number followed the other.

I executed this in Firefox 3.5.2. All the numbers seem to be about equal - indicating no bias, and no obvious pattern in the way the numbers are generated.

javascript:
var max = 5;
var transitions = new Array(max);
var frequency = new Array(max);
for (var i = 0; i < max; i++)
{
     transitions[i] = new Array(max);
}
var old = 0, curr = 0;
for (var i = 0; i < 100000; i++)
{
   curr = Math.floor(Math.random()*max);
   if (frequency[curr] === undefined) 
   {
      frequency[curr] = -1;
   }
   frequency[curr] += 1;
   if (transitions[old][curr] === undefined)
   {
      transitions[old][curr] = -1;
   }
   transitions[old][curr] += 1;
   old = curr;
}
alert(frequency);
alert(transitions);