在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;
};
现在,当我运行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()
)有关,但我仍然不确定为什么会发生这种情况。
答案 0 :(得分:75)
边缘情况发生在您碰巧生成一个非常小的数字时,用指数表示,例如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
答案 1 :(得分:37)
当然,这是一个parseInt()
陷阱。它首先将其参数转换为字符串,这可以强制科学记数法,这将导致parseInt做这样的事情:
var x = 0.000000004;
(x).toString(); // => "4e-9"
parseInt(x); // => 4
傻傻的我......
答案 2 :(得分:10)
我建议将随机数函数更改为:
var rand5 = function() {
return(Math.floor(Math.random() * 5) + 1);
};
这将可靠地生成介于1和5之间的整数值。
您可以在此处查看您的测试功能:http://jsfiddle.net/jfriend00/FCzjF/。
在这种情况下,parseInt
不是最好的选择,因为它会将你的float转换为一个字符串,该字符串可以是多种不同的格式(包括科学记数法),然后尝试解析一个整数它。使用Math.floor()
直接操作浮点运算会好得多。
答案 3 :(得分:-1)
使用 javascript 创建一个等于或大于 1 的随机数:
<div id="randomNum"></div>
<script type="text/javascript">
var randomN, underone = Math.random(), digits;
digits = "10";
randomN = Math.floor(underone * Math.pow(10, digits));
document.getElementById("randomNum").innerHTML = "Your random number with " + digits + " digits is: " + randomN;
</script>