以N为模的随机数的均匀性

时间:2012-10-27 21:46:37

标签: c random uniform

[0,n)中选择随机数的一种常用方法是取rand() modulo n 的结果:rand() % n 。但是,即使可用的rand()实现返回的结果完全一致,在{{1}时,结果 [0,n)数字的一致性也不应该存在问题。 n 不能均匀划分?例如。假设RAND_MAX + 1为2,而 n 为2.然后在3个可能的RAND_MAX输出中:0,1和2,当我们使用时,我们分别获得0,1和0他们模数 n 。因此,输出根本不会是均匀的。

这在实践中是一个真正的问题吗?在 [0,n)中选择随机数的更好方法是从rand()输出中均匀推导出来,最好不要有任何浮点运算?

4 个答案:

答案 0 :(得分:7)

你是对的,rand() % N并不是精确均匀分布的。确切地说,重要的是多少取决于你想要的数字范围和你想要的随机程度,但如果你想要足够的随机性,你甚至不关心它,你也不想使用rand()。获得一个真正的随机数生成器。

那就是说,要得到一个真正的随机分布,mod到下一个2的幂并进行采样,直到你得到一个你想要的范围(例如0-9,使用while(n = rand()%0x10 > 10);)。

答案 1 :(得分:4)

这取决于:

  • RAND_MAX
  • 的值
  • 你的N
  • 的价值

我们假设你的RAND_MAX是2 ^ 32。如果N相当小(假设为2)那么偏差是1/2 ^ 31 - 或者太小而不能注意到。

但如果N相当大,比如2 ^ 20,那么偏差是1/2 ^ 12,或者大约是4096中的一个。更大,但仍然很小。

答案 2 :(得分:1)

您可以采取以下措施:

了解N的价值,您可以R_MAX = ((RAND_MAX + 1) / N) * N;进行统一。

因此,您可以执行自定义rand()功能:

int custom_rand(int mod) {
    int x = rand();
    const int R_MAX = ((RAND_MAX + 1) / mod) * mod;    

    while (x > R_MAX) { // discard the result if it is bigger
        x = rand();
    }

    return (x % mod);
}

答案 3 :(得分:1)

在减小的范围内使用余数(%不是C中的“模”运算符)对于均匀随机数存在两个问题。首先是对较小的数字(如上所述)略有偏差,其次是典型的PRNG在低阶位中往往较不随机。我似乎记得Knuth(计算机编程艺术,第二卷,数值算法)以及(从MIX转换为C之后)rand()%2是随机单位的不良来源。最好选择(rand()> RAND_MAX / 2)(或测试一个高位,如果RAND_MAX几乎是2的幂。)

其余部分应该足够好,可以在很短的时间内随意使用。避免用于模拟。实际上,对于大型模拟或“蒙特卡罗”计算,完全避免使用rand()。实现往往具有大约2 ^ 32或更小的周期。在2+ GHz处理器上进行超过40亿次试验并不难。