考慮一種算法來測試在特定次數的嘗試後從一組N個唯一數字中挑選出某個數字的概率(例如,在N = 2的情況下,輪盤賭中的概率是多少(無0)試圖讓黑方獲勝?)。libc隨機數發生器有瑕疵?
正確的分佈是pow(1-1/N,X-1)*(1/N)。
但是,當我使用下面的代碼測試它時,總是在X = 31處有一個深溝,與N無關,並且獨立於種子。
這是一個內在的缺陷,由於使用PRNG的實現細節無法防止,這是一個真正的bug,還是我忽略了一些明顯的東西?
// 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);
}
}
測試上了最新的Xubuntu 12.10與libc6的軟件包2.15-0ubuntu20和Intel Core i5-2500 SandyBridge的,但我在幾年前就已經發現了這個舊的Ubuntu的機器上。
我也在Windows 7上使用Unity3D/Mono測試了這個(不知道哪個單聲道版本),這裏溝渠在使用System.Random時發生在X = 55,而Unity的內置Unity.Random沒有可見的溝渠(至少不適用於X < 100)。
分佈:
的差異:
我不認爲任何人都聲稱glibc中的隨機函數特別「高質量」,如果你想要更好的東西,那麼使用Mersenne Twister或其他「專業級」RNG。C庫[和其他類似的庫]提供的一個往往是爲了簡單而寫的,而不是「完美」。 –
1)主要應該返回int 2)模36是可疑的,我建議你先嚐試模32,或者另一個2的冪。 – wildplasser
我可以確認這個行爲(Debian Sid)爲模36和32. – liori