c – “n *(rand()/ RAND_MAX)”是否产生倾斜的随机数分布?

我想找到一个在C中获得随机数字的一个不偏不倚的方式(尽管最多我将使用它的值为0-20,更可能只有0-8).我看过这个公式,但经过一些测试,我不知道是否偏斜.任何帮助?

这是使用的全部功能

int randNum() 
{ 
    return 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
}

我使用:

unsigned int iseed = (unsigned int)time(NULL);
srand (iseed);

下面提出的一个拒绝为我工作,我试过

int greek; 
for (j=0; j<50000; j++) 
{ 
greek =rand_lim(5); 
printf("%d," greek); 
greek =(int) (NUM * (rand() / (RAND_MAX + 1.0))); 
int togo=number[greek]; 
number[greek]=togo+1; 
}

它停止工作,并给我相同的数字50000次当我注释掉printf.

解决方法

是的,它是倾斜的,除非你的RAND_MAX是10的倍数.

如果你把数字从0到RAND_MAX,并尝试把它们分成10个堆,你真的只有三种可能性:

> RAND_MAX是10的倍数,桩甚至出来.
> RAND_MAX不是10的倍数,堆不均匀.
>你把它分成不均匀的群体开始,但把所有的“额外”都放在一起,使它变得不平衡.

你很少能控制RAND_MAX,而且它通常是一个素数.这真的只有2和3作为可能性.

第三个选项大致如下:
[编辑]经过一番思考,我修改了这个数字,产生范围为0 …(limit-1)的数字,以适应C和C中大多数事情的工作方式.这也简化了代码(一点点).

int rand_lim(int limit) {
/* return a random number in the range [0..limit)
 */

    int divisor = RAND_MAX/limit;
    int retval;

    do { 
        retval = rand() / divisor;
    } while (retval == limit);

    return retval;
}

对于任何人来说,这种方法是否可能会有一些偏差,我也写了一个相当不同的版本,纯粹用于测试.这个使用非常有限范围的非随机发生器,所以我们可以简单地遍历范围内的每个数字.看起来像这样:

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

#define MAX 1009

int next_val() {
    // just return consecutive numbers
    static int v=0;

    return v++;
}

int lim(int limit) {
    int divisor = MAX/limit;
    int retval;

    do {
        retval = next_val() / divisor;
    } while (retval == limit);

    return retval;
}

#define LIMIT 10

int main() {

    // we'll allocate extra space at the end of the array:
    int buckets[LIMIT+2] = {0};
    int i;

    for (i=0; i<MAX; i++)
        ++buckets[lim(LIMIT)];

    // and print one beyond what *should* be generated
    for (i=0; i<LIMIT+1; i++)
        printf("%2d: %d\n",i,buckets[i]);
}

所以,我们从0到1009(1009是素数)的数字开始,所以它不会是我们选择的任何范围的精确倍数.所以,我们从1009个数字开始,并将其分成10个桶.这应该在每个桶中给100个,剩下的9个剩饭(可以这么说)被do / while循环“吃掉”了.正如它现在写的,它分配和打印出一个额外的桶.当我运行它时,我在桶10中的每个桶0..9和0中都准确地得到了100个.如果我注释掉了do / while循环,我在桶10中看到了每个0..9和9中的100个.

只要确定,我已经重新运行测试与各种其他数字,所产生的范围(主要使用素数)和桶的数量.到目前为止,我无法让它在任何范围内产生倾斜的结果(当然,只要do / while循环启用).

一个细节:有一个原因我在这个算法中使用除数而不是余数.有一个很好(甚至是体面的)rand()实现它是无关紧要的,但是当你使用除法将数字钳制到一个范围时,你保留输入的高位.当你用余数做的时候,你保留输入的低位.如发生的那样,使用典型的线性同余伪随机数发生器,较低位往往比较高位随机.合理的实施将会抛出一些最不重要的位,这使得这无关紧要.另一方面,有一些相当糟糕的rand的实现,并且大多数它们通过使用除法而不是余数来得到更好的输出质量.

我还应该指出,有大致相反的发生器 – 低位比高位更随机.至少在我的经验中,这些都是不常见的.高位更随机的是相当普遍的.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...