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”设置为更高的值以揭示错误):
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()
)有关,但我仍然不确定为什么会发生这种情况。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当您碰巧生成一个非常小的数字(用指数表示)时,就会出现边缘情况,例如
9.546056389808655e-8
。与将参数解释为字符串的
parseInt
相结合,地狱就乱了。正如我之前所建议的,可以使用 Math.floor 来解决。自己用这段代码尝试一下:
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 usingMath.floor
.Try it yourself with this piece of code:
当然,它是一个
parseInt()
陷阱。它首先将其参数转换为字符串,这可以强制使用科学记数法,这将导致 parseInt 执行如下操作:愚蠢的我...
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:Silly me...
我建议将您的随机数函数更改为:
这将可靠地生成 1 到 5 之间的整数值(包括 1 和 5)。
您可以在此处查看正在运行的测试函数:http://jsfiddle.net/jfriend00/FCzjF/。
在这种情况下,parseInt 不是最佳选择,因为它会将浮点数转换为字符串,该字符串可以是多种不同的格式(包括科学记数法),然后尝试解析整数它。最好直接使用 Math.floor() 操作浮点数。
I would suggest changing your random number function to this:
This will reliably generate an integer value between 1 and 5 inclusive.
You can see your test function in action here: http://jsfiddle.net/jfriend00/FCzjF/.
In this case,
parseInt
isn'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 withMath.floor()
.