【问题标题】:generate a random int given a random bit function给定一个随机位函数生成一个随机整数
【发布时间】:2018-04-03 12:29:03
【问题描述】:

假设给你一个 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;

我的基本想法是

  • 找出数字中存在的位数
  • 然后通过连续连接 LSB 直到满足位长来生成数字

【问题讨论】:

  • 这种方法对于 2 的幂(或 2 的幂减一:你不清楚max 是包含还是排除)是合理的,但是想想当数字是不是 2 的幂。例如,当 max 是 6 时。
  • 如果最大值为 2,我会得到 0 到 7 之间的结果。

标签: random binary numbers bit-manipulation bit


【解决方案1】:

在我看来,用随机位填充 int 的方法是正确的方法。但是,由于您的算法仅在 max 是 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 将包含填充 1 的位数。因此可以安全地假设rndmask-1 的商均匀分布在0 和1 之间。乘以max 将得到0 和max 之间的结果,也均匀分布在浮动/真实值。

现在这个结果必须映射到整数,当然你也希望它们是均匀分布的。这里唯一的问题是 1。如果 rndmask-1 的商正好为 1,则在缩放到所需结果范围时会出现一个边缘情况:将有统一的 0 .. max-1 值已分发,但 max 将是一个罕见的例外。

要处理这种情况,必须构建商,使其范围从 0 到 1,但 不包含 1。这是通过rnd / mask 实现的。通过乘以 max+1 并转换为 int,可以轻松地将这个范围映射到均匀分布的整数 0 .. max

【讨论】:

  • 不应该(double)rnd/mask yield [0,1](包括1)?因为 rnd 有可能都是 1s
  • 请解释最后一次 (int) 转换将如何产生均匀分布(例如在 [0,5) 中给定 8 个 3 位 000 到 111 的等概率组合)
  • @aka.nice 在max==4(3 位)的情况下,(double)rnd/mask 的范围从 0 到 7/8。这乘以 5 (max+1) 得到[0/8, 35/8]。所以rnd 映射如下:000..001=>0, 010..011=>1, 100=>2, 101..110=>3, 111=>4.
  • @OneTwoThree 掩码是 2 的幂,总是最大 rnd 值 + 1。
猜你喜欢
  • 2011-09-18
  • 1970-01-01
  • 2011-08-09
  • 2020-11-19
  • 2011-06-26
  • 1970-01-01
  • 2023-01-03
  • 2018-04-21
  • 2023-03-28
相关资源
最近更新 更多