以等概率生成数字

Generate number with equal probability

给你一个函数,比方说 bin(),它将以相等的概率生成 0 或 1。现在给你一系列连续的整数,比如 [a,b](包括 a 和 b)。

写一个函数说 rand() 使用 bin() 以等概率生成范围 [a,b] 内的数字

帮助,但没有代码:

  • 您可以轻松地将范围 [0,2 ** n] 移动到 [a,a+2 ** n]
  • 您可以轻松地从 [0,2**n-1]
  • 中得出相等的概率
  • 如果您需要一个不是 2 的幂的数字,只需生成一个最大为 2 ** n 的数字,如果超过您需要的数字则重新掷骰

您需要的洞察力是您的 bin() 函数 returns 单个二进制数字,或 "bit"。调用它一次会给你 0 或 1。如果你调用它两次,你会得到两位 b0b1,它们可以组合为 b1 * 2 + b0,给你一个 0、1、2 或3 概率相等。如果你调用它三次,你会得到三个位 b0b1b2。把它们放在一起,你得到 b2 * 2^2 + b1 * 2 + b0,给你 {0, 1, 2, 3, 4, 5, 6, 7} 的成员等概率。以此类推,想加多少就加多少。

您的范围 [a, b] 有 m = b-a+1 个值。您只需要足够的位来生成 0 和 2^n-1 之间的数字,其中 n 是使 2^n-1 大于或等于 m 的最小值。然后只需缩放该设置以从 a 开始就可以了。

假设给定范围 [20, 30]。那里有 11 个数字,从 20 到 30(含)。 11 大于 8 (2^3),但小于 16 (2^4),因此您需要 4 位。使用 bin() 生成四个位 b0b1b2b3。将它们放在一起作为 x = b3 * 2^3 + b2 * 2^2 + b1 * 2 + b0。您将得到一个结果 x,介于 0 和 15 之间。如果 x > 11,则生成另外四位。当 x <= 11 时,你的答案是 x + 20.

减去数字得出您的范围:

Decimal: 20 - 10 = 10
Binary : 10100 - 01010 = 1010

算出你需要多少位来表示这个:4

对于其中的每一个,生成一个随机的 1 或 0:

num_bits = 4
rand[num_bits]
for (x = 0; x < num_bits; ++x)
  rand[x] = bin()

让我们在这之后说rand[] = [0,1,0,0]。将此数字添加回您的范围的开头。

Binary: 1010 + 0100 = 1110
Decimal: 10 + 4 = 14

您可以随时将范围 [a,b] 更改为 [0,b-a],表示 X = b - a。然后你可以定义一个函数 rand(X) 如下:

function int rand(X){
   int i = 1;
   // determine how many bits you need (see above answer for why)
   while (X < 2^i) {
      i++;
   }
   // generate the random numbers
   Boolean cont = true;
   int num = 0;
   while (cont == true) {
      for (j = 1 to i) {
         // this generates num in range [0,2^i -1] with equal prob
         // but we need to discard if num is larger than X
         num = num + bin() * 2^j;
      }
      if (num <= X) { cont = false}
   }
   return num;
}