Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Math.random() returns value greater than one?

While playing around with random numbers in JavaScript I discovered a surprising bug, presumably in the V8 JavaScript engine in Google Chrome. Consider:

// Generate a random number [1,5]. var rand5 = function() {   return parseInt(Math.random() * 5) + 1; };  // Return a sample distribution over MAX times. var testRand5 = function(dist, max) {   if (!dist) { dist = {}; }   if (!max) { max = 5000000; }   for (var i=0; i<max; i++) {     var r = rand5();     dist[r] = (dist[r] || 0) + 1;   }   return dist; }; 

Now when I run testRand5() I get the following results (of course, differing slightly with each run, you might need to set "max" to a higher value to reveal the bug):

var d = testRand5(); d = {   1: 1002797,   2: 998803,   3: 999541,   4: 1000851,   5: 998007,   10: 1 // XXX: Math.random() returned 4.5?! } 

Interestingly, I see comparable results in node.js, leading me to believe it's not specific to Chrome. Sometimes there are different or multiple mystery values (7, 9, etc).

Can anyone explain why I might be getting the results I see? I'm guessing it has something to do with using parseInt (instead of Math.floor()) but I'm still not sure why it could happen.

like image 725
maerics Avatar asked Sep 08 '11 19:09

maerics


People also ask

What does the Math random () return?

Math.random() The Math.random() function returns a floating-point, pseudo-random number that's greater than or equal to 0 and less than 1, with approximately uniform distribution over that range — which you can then scale to your desired range.

Does Math random generate 1?

The Math. random() method returns a random number from 0 (inclusive) up to but not including 1 (exclusive).

Can a random random return 1?

A random number generator always returns a value between 0 and 1, but never equal to one or the other. Any number times a randomly generated value will always equal to less than that number, never more, and never equal.

What is the range of numbers that Math random () function returns?

random() function: The Math. random() function is used to return a floating-point pseudo-random number between range [0,1) , 0 (inclusive) and 1 (exclusive).


2 Answers

The edge case occurs when you happen to generate a very small number, expressed with an exponent, like this for example 9.546056389808655e-8.

Combined with parseInt, which interprets the argument as a string, hell breaks loose. And as suggested before me, it can be solved using Math.floor.

Try it yourself with this piece of code:

var test = 9.546056389808655e-8;  console.log(test); // prints 9.546056389808655e-8 console.log(parseInt(test)); // prints 9 - oh noes! console.log(Math.floor(test)) // prints 0 - this is better 
like image 59
Jakob Avatar answered Sep 30 '22 14:09

Jakob


Of course, it's a parseInt() gotcha. It converts its argument to a string first, and that can force scientific notation which will cause parseInt to do something like this:

var x = 0.000000004; (x).toString(); // => "4e-9" parseInt(x); // => 4 

Silly me...

like image 32
maerics Avatar answered Sep 30 '22 12:09

maerics