Math.random()返回大于一的值吗?

在JavaScript中使用随机数字时,我发现了一个令人惊讶的错误,大概是在Google Chrome的V8 JavaScript引擎中。 考虑:

// 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; }; 

现在当我运行testRand5()我得到了下面的结果(当然,每次运行都略有不同,你可能需要设置“max”到更高的值来揭示bug):

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

有趣的是,我在node.js中看到了类似的结果,导致我相信它不是特定于Chrome的。 有时会有不同的或多个神秘的值(7,9等)。

任何人都可以解释为什么我可能会得到我看到的结果? 我猜它与使用parseInt (而不是Math.floor() )有关,但我仍然不确定为什么会发生。

边缘情况发生在您碰巧生成一个非常小的数字时,用指数表示,例如9.546056389808655e-8

结合parseInt ,它将参数解释为一个string ,地狱崩溃。 正如我以前所build议的,它可以使用Math.floor来解决。

用这段代码自己试试吧:

 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 

当然,这是一个parseInt()陷阱。 它首先将它的参数转换为一个string ,然后强制使用parseInt来做这样的事情:

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

傻我…

我会build议改变你的随机数字function:

 var rand5 = function() { return(Math.floor(Math.random() * 5) + 1); }; 

这将可靠地生成1和5之间的整数值。

你可以在这里看到你的testing函数: http : //jsfiddle.net/jfriend00/FCzjF/ 。

在这种情况下, parseInt并不是最好的select,因为它将把你的float转换为一个可以是许多不同格式(包括科学记数法)的string,然后尝试从中parsing出一个整数。 直接使用Math.floor()直接对float进行操作会更好。