考虑一种算法来测试在特定次数的尝试后从一组 N 个唯一数字中选择某个数字的概率(例如,在 N=2 的情况下,轮盘赌(没有 0)中需要 X 次尝试的概率是多少黑赢?)。
正确的分布是 pow(1-1/N,X-1)*(1/N)。
但是,当我使用以下代码对此进行测试时,在 X=31 处总是有一个深沟,与 N 无关,也与种子无关。
这是由于使用中的 PRNG 的实现细节而无法避免的内在缺陷,这是一个真正的错误,还是我忽略了一些明显的东西?
// C
#include <sys/times.h>
#include <math.h>
#include <stdio.h>
int array[101];
void main(){
int nsamples=10000000;
double breakVal,diffVal;
int i,cnt;
// seed, but doesn't change anything
struct tms time;
srandom(times(&time));
// sample
for(i=0;i<nsamples;i++){
cnt=1;
do{
if((random()%36)==0) // break if 0 is chosen
break;
cnt++;
}while(cnt<100);
array[cnt]++;
}
// show distribution
for(i=1;i<100;i++){
breakVal=array[i]/(double)nsamples; // normalize
diffVal=breakVal-pow(1-1/36.,i-1)*1/36.; // difference to expected value
printf("%d %.12g %.12g\n",i,breakVal,diffVal);
}
}
在带有 libc6 包 2.15-0ubuntu20 和 Intel Core i5-2500 SandyBridge 的最新 Xubuntu 12.10 上进行了测试,但几年前我已经在一台较旧的 Ubuntu 机器上发现了这一点。
我还在 Windows 7 上使用 Unity3D/Mono 进行了测试(但不确定是哪个 Mono 版本),这里使用 System.Random 时,沟渠发生在 X=55,而 Unity 的内置 Unity.Random 没有可见沟渠(至少没有对于 X<100)。
分布:
区别: