假设您已获得int randBit()
函数,该函数返回,均匀分布,0或1。
编写一个randNumber(int max)函数。
这是我的实施,但我无法证明/反驳它是对的。
// max number of bits
int i = (int)Math.floor(Math.log(max) / Math.log(2)) + 1;
int ret = randBit();
while (i-- > 0) {
ret = ret << 1 | randBit();
}
return ret;
我的基本想法是
答案 0 :(得分:1)
在我看来,用随机位填充int的方法是正确的方法。但是,由于您的算法仅在最大功率为2且在循环中偏离1时有效,我建议进行此修改:
// max number of bits
int i = (int)Math.floor(Math.log(max) / Math.log(2)) + 1;
int rnd = 0;
int mask = 1;
while (i-- > 0) {
rnd = rnd << 1 | randBit();
mask <<= 1; // or: mask *= 2
}
double q = (double)rnd / mask; // range is [0, 1)
return (int)((max + 1) * q);
我们来看看这个:
i
将始终等于max
占用的位数。当循环结束时,rnd
将包含随机填充0或1的位数,mask-1
将包含填充1s的位数。因此,可以安全地假设rnd
和mask-1
的商均匀分布在0和1之间。这与max
相乘会产生0到max
之间的范围内的结果,就浮动/实际价值而言,也是均匀分布的。
现在这个结果必须映射到整数,当然你也希望它们统一分布。这里唯一的问题是1.如果rnd
和mask-1
的商正好是1,那么会有一个边缘情况会在缩放到所需的结果范围时造成麻烦:会有{ {1}}值均匀分布,但0 .. max-1
是一种罕见的例外情况。
为了处理这种情况,必须构建商,使其范围从0到1,但使用1 exclusive 。这是通过max
实现的。通过乘以rnd / mask
并转换为int,可以轻松将此范围映射到均匀扩展的整数0 .. max
。