我基本上坚持相当简单的问题:
扔N个硬币,发现有多少个正面朝上
解决方案的性能不能依赖于 N,所以我们不能只调用Math.random() < 0.5
N 次。显然,有高斯分布来拯救。
我使用了 Box-Muller 方法:
function gaussian_random(mean, variance) {
var s;
var x;
var y;
do {
x = Math.random() * 2.0 - 1.0;
y = Math.random() * 2.0 - 1.0;
s = Math.pow(x, 2) + Math.pow(y, 2);
} while ( (s > 1) || (s == 0) );
var gaussian = x * Math.sqrt(-2*Math.log(s)/s);
return mean + gaussian * Math.sqrt(variance);
}
数学说,N次抛硬币的平均值N/2
是,方差是N/4
然后,我进行了测试,将 N 个硬币投掷了 M 次,给出了最小、最大和平均正面数量。
我比较了朴素方法(Math.random()
多次)和高斯 Box-Muller 方法的结果。
有典型的测试输出:
Toss 1000 coins, 10000 times
Straight method:
Elapsed time: 127.330 ms
Minimum: 434
Maximum: 558
Average: 500.0306
Box-Muller method:
Elapsed time: 2.575 ms
Minimum: 438.0112461962819
Maximum: 562.9739632480057
Average: 499.96195358695064
Toss 10 coins, 10000 times
Straight method:
Elapsed time: 2.100 ms
Minimum: 0
Maximum: 10
Average: 5.024
Box-Muller method:
Elapsed time: 2.270 ms
Minimum: -1.1728354576573263
Maximum: 11.169478925333504
Average: 5.010078819562535
正如我们所见,N = 1000
它几乎完美契合。
但是,在N = 10
Box-Muller 上发疯了:它允许这样的测试结果,我可以从 10 次抛硬币中得到(很少,但有可能)11.17 个正面!:)
毫无疑问,我做错了什么。但究竟是什么?
更新 x2:看来,以前我没有很好地描述问题。它有一个通用版本:
如何在摊销常数时间内获得N 个均匀随机值(离散或连续)的样本均值。高斯分布对于大N是有效的,但是有没有办法让它在小N上工作得很好?或者在哪个N上,解决方案应该从高斯方法切换到其他方法(例如简单的)。