假设您有一些统一的分发 rnd(x)函数将返回0或1。 如何使用此函数创建任何 rnd(x,n)函数,从0到n返回均匀分布的数字?
我的意思是每个人都在使用它,但对我而言,它并不那么聪明。例如,我可以创建具有右边界2 ^ n-1([0-1],[0-3],[0-7]等)的分布,但无法找到如何对范围执行此操作的方法比较[0-2]或[0-5]而没有使用非常大的数字来获得合理的精确度。
答案 0 :(得分:0)
假设您需要创建函数rnd(n)
,它通过使用另一个返回0或1的函数rnd1()
返回范围[0,n]中的均匀分布的随机数。
k
2^k >= n+1
k
位组成的数字,并使用rnd1()
填充所有位。结果是在[0,2 ^ k-1] n
进行比较。如果它小于或等于n,则返回它。否则转到第2步。一般来说,这是如何通过使用库函数生成小范围内的统一数字的变体:
unsigned int rnd(n) {
while (true) {
unsigned int x = rnd_full_unsigned_int();
if (x < MAX_UNSIGNED_INT / (n+1) * (n+1)) {
return x % (n+1);
}
}
}
上述代码的说明。如果您只是返回rnd_full_unsigned_int() % (n+1)
,那么这会产生对小值数字的偏差。黑色螺旋表示从0到MAX_UNSIGNED_INT的所有可能值,从内部计算。单圈路径的长度为(n + 1)。红线表示偏差发生的原因。因此,为了消除这种偏差,我们首先在[0,MAX_UNSIGNED_INT]范围内创建随机数x(通过位填充很容易)。然后,如果x落入偏置生成区域,我们重新创建它。我们不断重新创建它,直到它不会落入偏置生成区域。 x此时的格式为a*(n+1)-1
,因此x % (n+1)
是均匀分布的数字[0,n]。