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

2023-12-11

我想找到一种在 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; 
}

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


是的,它是有偏差的,除非你的 RAND_MAX 恰好是 10 的倍数。

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

  1. RAND_MAX 是 10 的倍数,并且堆的结果是均匀的。
  2. RAND_MAX 不是 10 的倍数,并且堆出来的结果不均匀。
  3. 首先,您将其分成不均匀的组,但丢弃所有会使其不均匀的“额外内容”。

您很少能够控制 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;
}

对于任何质疑这种方法是否会留下一些偏差的人,我还编写了一个相当不同的版本,纯粹用于测试。这个使用了一个范围非常有限的绝对非随机生成器,因此我们可以简单地迭代every范围内的数量。它看起来像这样:

#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环形。正如现在所写的,它分配并打印出一个额外的存储桶。当我运行它时,我在每个桶 0..9 中得到 100,在桶 10 中得到 0。如果我注释掉do/while循环中,我在 0..9 中的每个中看到 100,在存储桶 10 中看到 9。

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

另一个细节:我在此算法中使用除法而不是余数是有原因的。通过良好(甚至体面)的实施rand()这是无关紧要的,but当您使用除法将数字限制在一个范围内时,您会保留upper输入的位。当你用余数做这件事时,你保留了lower输入的位。碰巧的是,对于典型的线性同余伪随机数生成器,较低位往往不如较高位随机。合理的实现将丢弃许多最低有效位,从而使其变得无关紧要。另一方面,有一些非常糟糕的实现rand周围,​​并与most其中,通过使用除法而不是余数,您最终会获得更好的输出质量。

我还应该指出的是are生成器的作用大致相反——低位比高位更随机。至少根据我的经验,这些都是相当罕见的。较高位更随机的是相当比较普遍;普遍上。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

“n * (rand() / RAND_MAX)”是否会产生倾斜的随机数分布? 的相关文章

随机推荐