随机数,Math.floor(...)与Math.ceil(...)的区别

7

我看到很多代码都是这样生成随机数的

// random integers in the interval [1, 10]
Math.floor(Math.random()*10 + 1)

无论如何,我觉得我错过了什么。为什么人们不使用更简洁的方式呢?

Math.ceil(Math.random()*10);

?

我尝试测试随机性,目前看来是真实的。

事实上,下面的代码

// will generate random integers from 1 to 4
var frequencies = [ 0, 0, 0, 0, 0 ]; // not using the first place
var randomNumber;
for ( var i = 0; i < 1*1000*1000; ++i ) {
   randomNumber = Math.ceil(Math.random()*4);
   frequencies[randomNumber]++;
}

for ( var i = 1; i <= 4; ++i ) {
   console.log(i +": "+ frequencies[i]);
}

打印输出

1: 250103
2: 250161
3: 250163
4: 249573

我错过了什么?

快速离题:是否有更简洁的方法来声明和初始化 frequencies?就像 C++ 中的 frequencies[5] = { 0 };...


4
Math.ceil(Math.random()*10); 生成 [0,10],尽管 0 的概率非常非常小... - Passerby
此外,数字10的概率比1~9略微小一些,因为 Math.random() 永远不会返回1。 - Passerby
关于您的 OT 问题:并不完全如此。JavaScript 没有数组初始化。JavaScript 数组基本上只是带有数字键名称和长度属性的对象。您能够获得的最接近的是 new Array(size),但它不会初始化为0,而是为 undefined - jwueller
还有一个有趣的发现是,Math.ceil 比 Math.floor 慢了约90%:http://jsperf.com/convert-to-integer - Red15
3个回答

10
根据MDN参考,关于Math.random()

返回一个浮点数,范围在[0,1)之间。也就是说,从0(包括)到1(不包括)之间的伪随机数,您可以将其缩放到所需的范围。

由于Math.random可能返回0,因此Math.ceil(Math.random()*10)也可能返回0,而该值超出了您的[1..10]范围。


关于您的第二个问题,请参见如何高效地创建零填充的JavaScript数组?


1
我现在非常好奇是否真的可能得到0,如果可能的话,实际概率是多少!我用问题脚本的编辑版本尝试了几次,排除零,并生成了十亿个随机整数,大约需要7秒钟才能运行,但frequencies[0]总是返回零。 - Isaac Reefman
1
等等,如果Math.random()返回16位小数精度,那么应该是一万亿分之一的概率吧?类似这样的数字? - Isaac Reefman
@IsaacReefman 你知道墨菲定律吗? :D。无论如何,概率几乎为零但不是完全为零。 - Fabrizio Calderan
3
@FabrizioCalderan 可以证实墨菲定律。我之前使用的一个 Node.js 包在可靠地运行数月后,当我向我的团队演示一个无关的新功能时,由于 Math.random() 在那个时刻第一次返回了 0,出现了一个前所未见的错误。教训是:如果在一个功能中使用 Math.random(),请编写针对其的测试,用多种值的数组来代替随机值运行它,并在该数组中包括 0 - user56reinstatemonica8

6

由于 Math.random() 的范围限制,建议使用 Math.floor()

例如,Math.random() * 10 的取值范围是 [0, 10)。如果使用 Math.floor(),永远不会得到 10 的值,而使用 Math.ceil() 可能会得到 0


1

在区间 [1, 10] 中生成随机整数:

Math.floor(Math.random()*10 + 1)

随机整数在区间[0, 10]内:
Math.ceil(Math.random()*10);

只要看你需要什么。


1
当使用 ceil() 函数获取 [0,10] 范围内的随机数时,这将是一种非常糟糕的方式,因为零实际上会被忽略。 - Ja͢ck
没错...但因为一个非常罕见的情况,有一天系统中的某个部分崩溃了会很遗憾。 - d'alar'cop
不确定您的意思。但是,如果您指望随机调用(random() call)不返回0,那么有一天您可能会感到不愉快。这就是我想说的全部。此外,这个答案的整个重点是为了说明两者之间的区别——他暗示它们是相同的... - d'alar'cop
你应该删除这个答案。当你想生成随机整数时,Math.ceil()从来不是正确的函数。始终使用Math.floor(),如果下限不为零,则添加下限。以你的第二个例子Math.ceil(Math.random()*10)为试图获取0到10之间的数字,正确的方法是Math.floor(Math.random()*11) - Michael Geary

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接