簡體   English   中英

為什么數字1,2和3使用C rand()函數經常出現?

[英]Why do digits 1, 2 and 3 appear so frequently using C rand() function?

我想要做的是生成一些隨機數(不一定是單個數字)

29106
7438
5646
4487
9374
28671
92
13941
25226
10076

然后計算我得到的位數:

count[0] =       3  Percentage =  6.82
count[1] =       5  Percentage = 11.36
count[2] =       6  Percentage = 13.64
count[3] =       3  Percentage =  6.82
count[4] =       6  Percentage = 13.64
count[5] =       2  Percentage =  4.55
count[6] =       7  Percentage = 15.91
count[7] =       5  Percentage = 11.36
count[8] =       3  Percentage =  6.82
count[9] =       4  Percentage =  9.09

這是我正在使用的代碼:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int main() {

    int i;
    srand(time(NULL));
    FILE* fp = fopen("random.txt", "w");    
    // for(i = 0; i < 10; i++)
    for(i = 0; i < 1000000; i++)
        fprintf(fp, "%d\n", rand());
    fclose(fp);

    int dummy;
    long count[10] = {0,0,0,0,0,0,0,0,0,0};
    fp = fopen("random.txt", "r");
    while(!feof(fp)) {
        fscanf(fp, "%1d", &dummy);
        count[dummy]++;                 
    }
    fclose(fp);

    long sum = 0;
    for(i = 0; i < 10; i++)
        sum += count[i];

    for(i = 0; i < 10; i++)
        printf("count[%d] = %7ld  Percentage = %5.2f\n",
            i, count[i], ((float)(100 * count[i])/sum));

}

如果我生成大量隨機數(1000000),這是我得到的結果:

count[0] =  387432  Percentage =  8.31
count[1] =  728339  Percentage = 15.63
count[2] =  720880  Percentage = 15.47
count[3] =  475982  Percentage = 10.21
count[4] =  392678  Percentage =  8.43
count[5] =  392683  Percentage =  8.43
count[6] =  392456  Percentage =  8.42
count[7] =  391599  Percentage =  8.40
count[8] =  388795  Percentage =  8.34
count[9] =  389501  Percentage =  8.36

請注意,1,2和3的命中次數太多。 我嘗試過多次運行,每次都得到非常相似的結果。

我試圖理解什么可能導致1,2和3比任何其他數字更頻繁地出現。


從Matt Joiner和Pascal Cuoq所指出的暗示,

我更改了要使用的代碼

for(i = 0; i < 1000000; i++)
    fprintf(fp, "%04d\n", rand() % 10000);
// pretty prints 0
// generates numbers in range 0000 to 9999

這就是我得到的(多次運行時類似的結果):

count[0] =  422947  Percentage = 10.57
count[1] =  423222  Percentage = 10.58
count[2] =  414699  Percentage = 10.37
count[3] =  391604  Percentage =  9.79
count[4] =  392640  Percentage =  9.82
count[5] =  392928  Percentage =  9.82
count[6] =  392737  Percentage =  9.82
count[7] =  392634  Percentage =  9.82
count[8] =  388238  Percentage =  9.71
count[9] =  388352  Percentage =  9.71

0,1和2受到青睞的原因是什么?


感謝大家。 運用

int rand2(){
    int num = rand();
    return (num > 30000? rand2():num);     
}

    fprintf(fp, "%04d\n", rand2() % 10000);

我明白了

count[0] =  399629  Percentage =  9.99
count[1] =  399897  Percentage = 10.00
count[2] =  400162  Percentage = 10.00
count[3] =  400412  Percentage = 10.01
count[4] =  399863  Percentage = 10.00
count[5] =  400756  Percentage = 10.02
count[6] =  399980  Percentage = 10.00
count[7] =  400055  Percentage = 10.00
count[8] =  399143  Percentage =  9.98
count[9] =  400104  Percentage = 10.00

rand()生成一個從0RAND_MAX的值。 在大多數平台上, RAND_MAX設置為INT_MAX ,可以是327672147483647

對於上面給出的示例,看起來RAND_MAX32767 這將會把異常高的頻率123為用於從值最顯著數字1000032767 你可以觀察到,在較小的程度上,最多67值也會略微受到青睞。

關於編輯的問題,

這是因為即使您是% 10000 ,數字仍然不均勻分布。 假設RAND_MAX == 32767 ,並且rand()完全一致。

對於從0開始計數的每10,000個數字,所有數字將均勻顯示(每個4,000個)。 但是,32,767不能被10,000整除。 因此,這些2,768個數字將為最終計數提供更多前導0,1和2。

這2,768個數字的確切貢獻是:

digits count
0      1857
1      1857
2      1625
3      857
4      857
5      857
6      855
7      815
8      746
9      746

將最初的30,000個數字加12,000加到計數中,然后除以總數位數(4×32,768),可以得到預期的分布:

number  probability (%)
0       10.5721
1       10.5721
2       10.3951
3        9.80911
4        9.80911
5        9.80911
6        9.80759
7        9.77707
8        9.72443
9        9.72443

這是接近你得到的。

如果您想要真正統一的數字分布,您需要拒絕這2,768個數字:

int rand_4digits() {
  const int RAND_MAX_4_DIGITS = RAND_MAX - RAND_MAX % 10000;
  int res;
  do {
    res = rand();
  } while (res >= RAND_MAX_4_DIGITS);
  return res % 10000;
}

看起來像本福德定律 - 見http://en.wikipedia.org/wiki/Benford%27s_law ,或者是一個不太好的RNG。

那是因為你生成0RAND_MAX之間的數字。 生成的數字是均勻分布的(即每個數字的概率大致相同),但是,數字1,2,3比該范圍內的其他數字更頻繁地出現。 嘗試在010之間生成,其中每個數字以相同的概率出現,您將得到一個很好的分布。

如果我理解OP(提出問題的人)想要什么,他們想要制作更好的隨機數。

rand()和random(),坦率地說,不要做很好的隨機數; 當他們對死硬和頑固分子(兩個用於測試隨機數質量的軟件包)進行測試時,它們都表現不佳。

Mersenne twister是一個流行的隨機數生成器,除了加密的隨機數之外幾乎所有的東西都很好; 它以絢麗的色彩通過了所有的死硬測試。

如果需要加密強的隨機數(無法猜到的數字,即使有人知道正在使用哪種特定的加密算法),那里有許多流密碼。 我喜歡使用的那個叫做RadioGatún[32],這里有一個緊湊的C表示:

/*Placed in the public domain by Sam Trenholme*/
#include <stdint.h>
#include <stdio.h> 
#define p uint32_t
#define f(a) for(c=0;c<a;c++)
#define n f(3){b[c*13]^=s[c];a[16+c]^=s[c];}k(a,b 
k(p *a,p *b){p A[19],x,y,r,q[3],c,i;f(3){q[c]=b[c
*13+12];}for(i=12;i;i--){f(3){b[c*13+i]=b[c*13+i- 
1];}}f(3){b[c*13]=q[c];}f(12){i=c+1+((c%3)*13);b[
i]^=a[c+1];}f(19){y=(c*7)%19;r=((c*c+c)/2)%32;x=a
[y]^(a[(y+1)%19]|(~a[(y+2)%19]));A[c]=(x>>r)|(x<<
(32-r));}f(19){a[c]=A[c]^A[(c+1)%19]^A[(c+4)%19];
}a[0]^=1;f(3){a[c+13]^=q[c];}}l(p *a,p *b,char *v
){p s[3],q,c,r,x,d=0;for(;;){f(3){s[c]=0;}for(r=0
;r<3;r++){for(q=0;q<4;q++){if(!(x=*v&255)){d=x=1;
}v++;s[r]|=x<<(q*8);if(d){n);return;}}}n);}}main(
int j,char **h){p a[39],b[39],c,e,g;if(j==2){f(39
){a[c]=b[c]=0;}l(a,b,h[1]);f(16){k(a,b);}f(4){k(a
,b);for(j=1;j<3;++j){g=a[j];for(e=4;e;e--){printf
("%02x",g&255);g>>=8;}}}printf("\n");}}

那里還有很多其他非常好的隨機數發生器。

如果要從范圍[0, x)生成隨機值,而不是執行rand()%x ,則應該應用公式x*((double)rand()/RAND_MAX) ,這將為您提供分布良好的隨機值。

再說了,RAND_MAX等於15,所以rand會給你的整數從0到15當您使用模運算符從中獲取隨機數[0, 10)[0,5]將具有高於頻率[6,9] ,因為3 == 3%10 == 13%10

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM