【问题标题】:use rand1 to implement randx [duplicate]使用 rand1 实现 randx [重复]
【发布时间】:2017-04-26 02:39:06
【问题描述】:

你有int rand1(),它以相同的概率输出 0 或 1。

你需要实现int randx(int x),它输出0,1,2,3,4,...,x,每个值的概率应该相等。

很容易根据rand1 输出为rand3rand7 等函数设置位。对于rand3,只需调用rand1 两次并根据输出设置位0 和1,00、01、10、11 将有相同的概率获得选择(25%)。但是像rand4 这样的函数呢?

【问题讨论】:

  • 嗨 martianwars,我编辑了问题,提到 randx 应该以相等的概率输出 0,1,...,x,这就是为什么我认为你以前的方法可能行不通的原因。跨度>
  • 查看新答案

标签: function math random


【解决方案1】:

在这个问题中,您需要保留一些虚拟输出(如@Gene 指出的那样,拒绝采样),在这些输出上重复执行的实验。

我在这里提供了两个实现。 第一个是次优的,但更容易理解。 第二个更理想,但有点困难。最后,我尝试概述证明并链接到 Math StackExchange 答案


第一种方法 -

第 1 步 - 运行 rand1() x + 1 次。

第 2 步 - 检查输出是否为 one-hot。我的意思是,只有 1 个 x + 1 运行导致 1 和所有其他 0。如果不是这样,请重复第 1 步。否则转到第 3 步。

第 3 步 - 打印索引 1 作为输出。

python 代码将如下所示 -

def randx(x):
    choice = -1
    while choice == -1:
        for i in range(0, x+1):
            c = rand1()
            if c == 1 and choice == -1:
                choice = i
            elif c == 1 and choice != -1:
                choice = -1
                break

第二种方法 -

当然,第一种方法是次优的。你可以做得更好,但它需要更多的代码。假设我们想要在 x+1 值(0x)之间进行预测。您至少需要进行实验k = ceil(log(x+1)) 次。现在,每个结果都有1 / 2^k的相等概率。

在这些2^k 的可能性中,将一些分配给数字(由于我们选择了k,您将看到您可以将一个数字分配给至少一半的可能性)。调用其他可能性 dummy 输出。

当您获得 dummy 输出时,您只需重复实验即可。如果不这样做,则输出与该输出对应的数字。

例如,如果 x = 4,x + 1 = 5。因此我们需要k = 3。分配 0, 1, 2, 3, 4 它们的二进制表示(000 到 101),并将剩余的 3 保留为哑元。伪代码如下所示,

function randx(x):
    choice = -1
    runs = ceil(log(x+1))
    while choice == -1:
        output = 0
        for i in range(0, runs):
            output += pow(2, i)*rand1()
        if output <= x:
            choice = output

为什么会这样?

我们给所有的数字赋予相等的可能事件。如果这些事件都没有发生,我们只是重复这个实验。如果你看得到一个数字i的总概率,

Let p = 1 / 2^k
Let q = 1 - (x+1)*p
Total probability of getting i = p + q*p + q*q*p + q*q*q*p ...
= p/(1-q)
= 1/(x+1)
Hence this sums up to 1 / (x+1).

有关 MathJax 的更完整解释,请参阅https://math.stackexchange.com/questions/2356/is-it-possible-to-split-coin-flipping-3-ways

【讨论】:

  • 很酷,但我认为您做出的选择概率为(x+1)/2^(x+1),例如:对于rand4,您将在@987654341 中选择10000、01000、00100、00010、00001 @可能性。
  • 不,我指的是第三部分中的第二种最佳方法
  • 第二种方法不是做x+1次实验,而是做ceil(log(x+1))次
  • 对于您的第一种方法,我再想一次,现在我认为您的第一种方法会起作用,对于 10000、01000、00100、00010 和 00001 这 5 个选项,您正在随机选择它,所以它是 1/5。
  • 是的,两者都可以,但首先是次优的。如果效率是一个问题,请使用第二个
【解决方案2】:

你的想法是对的。您需要通过连接随机位来生成一个大于您需要的二进制数。但是除非x+1 是2 的幂,否则您需要使用rejection sampling 来确保randx 返回的每个值的概率相同。为了使拒绝的概率很小,比如小于 2^-p,你生成的 2 的幂应该有p+1 位超过必要的位。拒绝的方法如下:

int rand(int x) {
  choose b such that m = 2^b >= x+1 
  let r_max = m - m mod (x+1)
  do {
    r = base-2 number of r pseudo-random bits
  } while (r > r_max)
  return r mod (x+1)
}

请注意,当x+1 是 2 的幂时,循环总是只执行一次。如果不是,则每次迭代的概率取决于b。将 1 加到 b 会使再次迭代的概率减半。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-04-27
    • 2012-07-03
    • 2017-07-11
    • 1970-01-01
    • 2011-02-22
    • 2014-07-25
    • 2011-08-02
    • 2023-03-24
    相关资源
    最近更新 更多