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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7353592/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 23:50:09  来源:igfitidea点击:

Math.random() returns value greater than one?

javascriptgoogle-chromerandomv8parseint

提问by maerics

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

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

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):

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

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).

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

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.

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

回答by Jakob

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

当您碰巧生成一个非常小的数字时,就会发生边缘情况,用指数表示,例如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.

结合parseInt将参数解释为字符串,地狱打破了。正如我之前所建议的,可以使用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

回答by maerics

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

当然,这是一个parseInt()陷阱。它首先将其参数转换为字符串,这可以强制使用科学记数法,这将导致 parseInt 执行以下操作:

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

Silly me...

傻我...

回答by jfriend00

I would suggest changing your random number function to this:

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

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

This will reliably generate an integer value between 1 and 5 inclusive.

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

You can see your test function in action here: http://jsfiddle.net/jfriend00/FCzjF/.

您可以在此处查看您的测试功能:http: //jsfiddle.net/jfriend00/FCzjF/

In this case, parseIntisn't the best choice because it's going to convert your float to a string which can be a number of different formats (including scientific notation) and then try to parse an integer out of it. Much better to just operate on the float directly with Math.floor().

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