【问题标题】:C puzzle: Make a fair coin from a biased coinC 谜题:用有偏见的硬币制作公平的硬币
【发布时间】:2011-07-22 16:35:37
【问题描述】:

如何确定函数在以下情况下返回 0 或 1 的概率:

function_A 返回 0 概率 40% 和 1 概率 60%。生成一个function_B 概率 50-50 仅使用 function_A 仅限。

我想到了以下几点:

 function_B()
 {
     int result1=function_A();
     int result2=function_A();
     //two times 40% would result in 16% and 40%+60% would be 24%... two times 60%                        would be 36%
 }

什么组合可以得到 50-50?

【问题讨论】:

  • 这是作业吗?如果你应该为作业做这个,我不想直接告诉你答案。
  • 不,不是作业...我无法通过两个函数调用来回答..

标签: c algorithm math puzzle probability


【解决方案1】:
h for head, t for tail and p() for probability of.

Lets suppose the following:
    p(h) = 0.6
    p(t) = 0.4

Lets define an event => Event: Flip the coin twice (flip1 , flip2) 

Flipping the coin twice could produce the following results
=> {h, h} , {t, t}, {h, t}, {t, h}

Here are the different probabilities for each event

{h, h} = 0.6 * 0.6 = 0.18
{t, t} = 0.4 * 0.4 = 0.12
{h, t} = 0.6 * 0.4 = 0.24
{t, h} = 0.4 * 0.6 = 0.24

正如我们所见,{h, t}{t, h} 的概率相等。 我们可以以此为基础产生一个等概率的结果,因为 我们可以继续触发我们的事件,直到它返回{h, t}{t, h}。 此时我们返回事件的第一次尝试(假设该事件包括两次翻转)

这是解决方案的快速递归实现

def unfair_foo():
      # Some code here to produce unfair result
 
def fair_foo():
    flip_1, flip_2 = unfair_foo(), unfair_foo()
 
    if flip_1  flip_2:
      # Base case
      return flip1

     return  fair_foo()  # Recursive call

【讨论】:

    【解决方案2】:
    def fairCoin(biasedCoin):
    coin1, coin2 = 0,0
    while coin1 == coin2:
    coin1, coin2 = biasedCoin(), biasedCoin()
    return coin1
    

    这原本是冯诺依曼的聪明主意。如果我们有一个有偏差的硬币(即出现正面概率不同于 1/2 的硬币),我们可以通过掷硬币对来模拟一个公平的硬币,直到两个结果不同。鉴于我们有不同的结果,第一个是“正面”,第二个是“反面”的概率与“反面”然后是“正面”的概率相同。因此,如果我们简单地返回第一枚硬币的价值,我们将以相同的概率得到“正面”或“反面”,即 1/2。这个答案来自 - http://jeremykun.com/2014/02/08/simulating-a-fair-coin-with-a-biased-coin/http://en.wikipedia.org/wiki/Fair_coin#Fair_results_from_a_biased_coin了解更多信息

    【讨论】:

    • 这是当前接受的答案的副本。
    【解决方案3】:

    鉴于:

    1. 事件 = {头、尾}
    2. 硬币不公平 => P(head) = p and P(tail) = 1-p

    算法:

    1. 使用不公平硬币生成 N1 事件(正面或反面)样本
    2. 估计其样本均值 m1 = (#heads)/N1
    3. 使用不公平硬币生成另一个 N2 事件样本(正面或反面)
    4. 估计其样本均值 m2 = (#heads)/N2
    5. if (m1 > m2) 返回头部,否则返回尾部

    注意事项:

    1. 上述第 5 步中返回的事件的概率相同(P(head) = P(tail) = 0.5)
    2. 如果 #5 重复多次,则其样本均值 --> 0.5,与 p 无关
    3. 如果 N1 --> 无穷大,则 m1 --> 真均值 p
    4. 要生成公平的硬币输出,您需要对不公平的硬币进行多次独立采样(这里是抛硬币)。越多越好。

    直觉:虽然硬币是不公平的,但估计均值与真实均值的偏差是随机的,可能是正数或负数,概率相同。由于没有给出真实均值,因此这是从另一个样本中估计出来的。

    【讨论】:

      【解决方案4】:

      这是一种可行的方法,但需要反复试验。

      1. function_A 返回 1 的概率: P(1) = p(例如 p=60%)
      2. function_A 返回 0 的概率: P(0) = 1 - p
      3. 特定序列的机会 连续返回值 a,b,... 对function_A 的调用是 P(a)P(b)...
      4. 观察某些组合会 以相同的几率出现​​,例如:

              P(a)*P(b) === P(b)*P(a)
         P(a)*P(b)*P(c) === P(b)*P(c)*P(a)
        
         etc.
        
      5. 我们可以在仅选择时使用该事实 (1,0) 或 (0,1) 的序列,然后我们 知道 其中一个的机会是

            P(1)*P(0)/(P(1)*P(0) + P(0)*P(1)) 
         => x / (x + x)
         => 1 / 2
        

      然后,这成为了 实现一个function_B:

      • 反复拨打function_A,直到我们 接收 (0,1) 或 (1,0) 的序列
      • 我们始终返回第一个或 序列的最后一个元素(两者都会 0 或 1 的几率相同)


      function_B()
      {
          do
          {
              int a = function_A();
              int b = function_A();
          } while( (a ^ b) == 0 ); // until a != b
      
          return a;
      }
      

      【讨论】:

      • @MAK:这个想法是让 0 和 1 的概率相同。如果您观察,当函数返回一个值时,该值上有 50-50 为 0 或 1。
      • @Shamim:“如果你观察......” - 你是否这样做并不重要(这不是薛定谔的猫)。我想你的意思可能是“我不知道怎么解释,你自己弄明白”:)
      • @sehe:好吧,我可以解释一下,但是评论框会很拥挤:)。其实我用的那句话是陈词滥调,有些教科书用这种语言解释答案。
      • @Shamim:我一半在嘲笑解释的缺失(或草率?)(a)所以不是教科书(b)教科书使用 observe 来伴随演绎步骤推理 - 你大多只是建议有一些合乎逻辑的步骤(c)我在你的答案框中找到了一些空间来解决问题。 (提示:剪裁的 cmets 不是正确的位置;评论框同上)
      • @sehe:嗯。感谢您添加的解释和建议:)
      【解决方案5】:

      我想知道递归是否应该起作用,随着深度的增加,0 或 1 的机会应该越来越接近 0.5。在 1 级,修改后的机会是 p'=p*p+(p-1)*(p-1)

      depth = 10;
      int coin(depth) {
          if (depth == 0) {
              return function_A();
          }
          p1 = coin(depth-1);
          p2 = coin(depth-1);
          if (p1 == p2) {
              return 1;
          } else {
              return 0;
          }
      }
      

      【讨论】:

        【解决方案6】:

        这是一个经典的概率谜题,据我所知,仅调用两次函数是无法做到的。但是,您可以通过对函数的预期次调用来做到这一点。

        观察结果是,如果你有一个有偏见的硬币以概率 p 出现正面,并且如果你掷硬币两次,那么:

        • 两次正面朝上的概率是 p2
        • 先正面后反面的概率是 p(1-p)
        • 先反后反的概率为 (1-p)p
        • 它出现两次的概率是 (1-p)2

        现在,假设您反复翻转两个硬币,直到它们得到不同的值。如果发生这种情况,第一枚硬币正面朝上的概率是多少?好吧,如果我们应用贝叶斯定律,我们就会明白

        P(第一个硬币是正面|两个硬币不同)=P(两个硬币不同|第一个硬币是正面)P(第一个硬币是正面)/P(两个硬币不同)

        第一个硬币正面朝上的概率是 p,因为任何一次抛硬币正面朝上的概率都是 p。假设第一枚硬币正面朝上,两枚硬币不同的概率是第二枚硬币反面出现的概率,即 (1 - p)。最后,两个硬币不同的概率是 2p(1-p),因为如果您查看上面的概率表,有两种可能发生这种情况的方式,每一种都有概率 p(1-p)。简化,我们明白了

        P(第一个硬币是正面|两个硬币不同)= p(1-p)/(2p(1-p))= 1 / 2。

        但是,如果硬币不同,那么第一枚硬币出现反面的概率是多少?嗯,这与两枚硬币不同时第一枚硬币没有正面朝上的概率相同,即 1 - 1/2 = 1/2。

        换句话说,如果你不断翻转两个硬币直到它们产生不同的值,然后取你翻转的第一个硬币的值,你最终会从有偏差的硬币中得到一个公平的硬币!

        在 C 中,这可能如下所示:

        bool FairCoinFromBiasedCoin() {
            bool coin1, coin2;
        
            do {
                coin1 = function_A();
                coin2 = function_A();
            } while (coin1 == coin2);
        
            return coin1;
        }
        

        这可能看起来非常低效,但实际上并没有那么糟糕。它在每次迭代中终止的概率是 2p(1 - p)。按照预期,这意味着我们需要 1/(2p(1-p)) 次迭代才能终止此循环。对于 p = 40%,这是 1/(2 x 0.4 x 0.6) = 1/0.48 ~= 2.083 次迭代。每次迭代都会翻转两个硬币,因此我们预计需要大约 4.16 次硬币翻转才能获得公平的翻转。

        希望这会有所帮助!

        【讨论】:

        • 这应该得到很好的答案徽章。 +1
        • 您实际上可以做得更好,但是编码有点混乱。这个想法是,如果序列 HHTT 和 TTHH 具有相同的发生概率(其中 H 是正面,T 是反面)。您甚至可以使用更长的序列。对于那些感兴趣的人,this paper 非常适合阅读。
        • @FelixCQ 我收到错误You don't have permission to access /~libcs124/CS/coinflip3.pdf on this server. 还有其他链接可以分享吗?
        • @ac_c0der,这是同一篇论文的another link。无论如何,您应该能够通过名称找到它:Michael Mitzenmacher 的“Tossing a Biased Coin”。
        • @RafayKhan 您可以将硬币正面朝上的次数想象成正面朝上的概率为 q 的geometric random variable,参数为 q。查看有关矩的部分,以证明该变量的预期值为 1/q。
        【解决方案7】:

        可行。但是,对该函数的 2 次调用是不够的。想想一遍又一遍地调用函数,并越来越接近 50/50

        【讨论】:

        • 这是一种近似方法,但可能存在浮点错误。这样做可能不会出现任何浮点错误。
        • 为什么近似方法与浮点错误有关?你得到 0 或 1 的机会不是 50%。
        猜你喜欢
        • 2014-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-09
        • 2011-05-11
        • 1970-01-01
        • 2019-07-17
        • 1970-01-01
        相关资源
        最近更新 更多