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

mae*_*ics 40 javascript random google-chrome v8 parseint

在JavaScript中使用随机数字时,我发现了一个令人惊讶的错误,可能是谷歌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;
};
Run Code Online (Sandbox Code Playgroud)

现在,当我运行时,testRand5()我得到以下结果(当然,每次运行略有不同,您可能需要将"max"设置为更高的值以显示错误):

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

有趣的是,我在node.js中看到了可比较的结果,这让我相信它不是Chrome特有的.有时会有不同的或多个神秘的价值观(7,9等).

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

Jak*_*kob 76

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

结合使用parseInt,将参数解释为字符串,地狱就会松散.正如我之前所建议的那样,可以使用它来解决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
Run Code Online (Sandbox Code Playgroud)


mae*_*ics 38

当然,这是一个parseInt()问题.它首先将其参数转换为字符串,这可以强制科学记数法,这将导致parseInt做这样的事情:

var x = 0.000000004;
(x).toString(); // => "4e-9"
parseInt(x); // => 4
Run Code Online (Sandbox Code Playgroud)

傻我......

  • 很高兴知道......你可能想考虑将其发布到http://wtfjs.com/. (6认同)
  • 哇,不错的收获。我不知道 parseInt 首先将数字转换为字符串。 (2认同)

jfr*_*d00 10

我建议将随机数函数更改为:

var rand5 = function() {
  return(Math.floor(Math.random() * 5) + 1);
};
Run Code Online (Sandbox Code Playgroud)

这将可靠地生成1到5之间的整数值,包括1和5.

你可以在这里看到你的测试功能:http://jsfiddle.net/jfriend00/FCzjF/.

在这种情况下,parseInt它不是最好的选择,因为它会将你的float转换为一个字符串,该字符串可以是多种不同的格式(包括科学记数法),然后尝试从中解析一个整数.更好的是直接用浮子操作Math.floor().