在 [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()
输出中均匀推导出来,最好不要有任何浮点运算?
答案 0 :(得分:7)
你是对的,rand() % N
并不是精确均匀分布的。确切地说,重要的是多少取决于你想要的数字范围和你想要的随机程度,但如果你想要足够的随机性,你甚至不关心它,你也不想使用rand()
。获得一个真正的随机数生成器。
那就是说,要得到一个真正的随机分布,mod到下一个2的幂并进行采样,直到你得到一个你想要的范围(例如0-9,使用while(n = rand()%0x10 > 10);
)。
答案 1 :(得分:4)
这取决于:
我们假设你的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亿次试验并不难。