代码之家  ›  专栏  ›  技术社区  ›  Moeb

为什么使用C rand()函数时数字1、2和3出现得如此频繁?

  •  28
  • Moeb  · 技术社区  · 16 年前

    我想做的是生成一些随机数(不一定是一位数),比如

    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有太多的点击。我试过几次运行这个程序,每次都得到非常相似的结果。


    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
    


    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
    
    6 回复  |  直到 16 年前
        1
  •  46
  •   Matt Joiner    16 年前

    rand() 从生成值 0 RAND_MAX . 最大兰特 设置为 INT_MAX 在大多数平台上 32767 2147483647 .

    对于上面给出的例子,似乎 最大兰特 32767 . 这将导致异常高频率的 1 , 2 3 中值的最高有效位 10000 . 你可以观察到,在较小的程度上,价值高达 6 7 也将略受青睐。

        2
  •  20
  •   kennytm    16 年前

    这是因为即使您 % 10000 . 假设 RAND_MAX == 32767 ,和 rand()

    对于从0开始的每10000个数字,所有数字都将统一显示(每个数字4000个)。然而,32767不能被10000整除。因此,这2768个数字将为最终计数提供更多的前导0、1和2。

    这2768个数字的确切贡献是:

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

    将最初的30000个数字加上12000,然后除以总位数(4×32768)应给出预期分布:

    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
    

    很接近你得到的。

    拒绝 这2768个数字:

    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;
    }
    
        3
  •  7
  •   anon anon    16 年前

    看起来像是本福德定律-看到了吗 http://en.wikipedia.org/wiki/Benford%27s_law 或者不是很好的RNG。

        4
  •  2
  •   phimuemue    16 年前

    那是因为你在 0 RAND_MAX 0 10 ,其中每个数字以相同的概率出现,你会得到一个很好的分布。

        5
  •  2
  •   samiam    16 年前

    如果我了解OP(问问题的人)想要什么,他们就想制造更好的随机数。

    Mersenne twister是一种流行的随机数生成器,它适用于除加密强随机数以外的几乎所有情况;它以优异的成绩通过了所有的顽固(er)测试。

    如果需要加密强随机数(即使有人知道使用的是哪种加密强算法,也猜不到的数),那么就有很多流密码。我喜欢使用的一个叫做radiotatn[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");}}
    

        6
  •  0
  •   el.pescado - нет войне    16 年前

    当您要从范围中生成随机值时 [0, x) ,而不是 rand()%x x*((double)rand()/RAND_MAX)

    比如说,RAND_MAX等于15 rand [0, 10) [0,5] 频率将高于 [6,9] ,因为 3 == 3%10 == 13%10

    推荐文章