【问题标题】:How to write a function to generate random number 0/1 use another random function?如何编写一个函数来生成随机数 0/1 使用另一个随机函数?
【发布时间】:2012-08-25 12:51:41
【问题描述】:

如果我有一个名为 rand1() 的函数生成数字 0(30% 概率)或 1(70% 概率),如何编写一个生成数字 0 或 1 等概率的函数 rand2() 使用 rand1() ?

更新:

最后在Introduction to Algorithms (2nd)这本书上发现了这个问题(我已经买了这本书的中文版),Excercise 5.1-3,原来的问题是:

5.1-3 假设您要以概率 1/2 输出 0,以概率 1/2 输出 1。 您可以使用一个程序 BIASED-RANDOM,它输出 0 或 1。它 以某个概率 p 输出 1,以概率 1− p 输出 0,其中 0

解决方案是: (见:http://www.cnblogs.com/meteorgan/archive/2012/05/04/2482317.html

要获得一个无偏的随机位,只需要调用 BIASED-RANDOM,调用 BIASED-RANDOM 两次。反复这样做,直到两个调用返回不同 值,当发生这种情况时,返回两个位中的第一个:

UNBIASED-RANDOM
while TRUE
do
x ← BIASED-RANDOM
y ← BIASED-RANDOM
if x != y
then return x

要查看 UNBIASED-RANDOM 以 1/2 的概率返回 0 和 1,请观察 给定迭代返回 0 的概率是

Pr {x = 0 and y = 1} = (1 − p)p ,

给定迭代返回 1 的概率为

Pr {x = 1 and y = 0} = p(1 − p) .

(我们依赖 BIASED-RANDOM 返回的位是独立的。)因此, 给定迭代返回 0 的概率等于它返回 1 的概率。 由于 UNBIASED-RANDOM 没有其他方法可以返回值,因此返回 0 和 1 每个概率为 1/2。

【问题讨论】:

  • 不是真正的50/50,而是49/51:你可以用rand1()生成两次,如果都是1,那么你可以分配0;为其他情况分配 1。
  • 家庭作业?面试题?
  • 今天的面试题,没思路。
  • @JensGustedt - 我不这么认为。 rand() 是一个通用函数,不是特定于 C 的。已删除 C 标记。

标签: algorithm random numbers


【解决方案1】:

生成两个数字,ab

如果 a 为 0,b 为 1(21% 的机会),则生成 0。
如果a 为 1,b 为 0(21% 的几率),则生成 1。

对于所有其他情况(58% 的机会),只需生成一个新的 ab 并重试。

【讨论】:

  • 这个算法不终止的概率是多少? :-)
  • @KerrekSB 在 N 次调用 rand1 后它没有终止的概率是 0.58^N
  • @KerrekSB 它是运行次数的en.wikipedia.org/wiki/Geometric_distribution,p=0.42。所以平均值是 1/p,或大约 2.38。
  • +1 这是一种拒绝技术,由于对称性,它是精确的,尽管它可能没有预期的那么有效。
  • 这称为白化随机序列。这是迄今为止描述的最常见的方法,但它不是最有效的。见here
【解决方案2】:

如果您调用rand1 两次,获得[1 0][0 1] 的机会相同,因此如果您返回每个不匹配对中的第一个(并丢弃匹配对),平均而言,您将获得,0.5(1 - p<sup>2</sup> - (1-p)<sup>2</sup>) 每个输入位的输出位(其中prand1 返回1 的概率;在您的示例中为0.7)并且独立于p,每个输出位将为1,概率为0.5。

但是,我们可以做得更好。

与其丢弃匹配对,我们可以记住它们,希望它们后面跟着相反的匹配对 - 序列[0 0 1 1][1 1 0 0] 的可能性也相同,并且我们可以再次返回第一位我们看到了这样一个序列(仍然输出概率为 0.5。)我们可以无限期地继续组合它们,寻找像 [0 0 0 0 1 1 1 1] 之类的序列。

我们可以走得更远——考虑输入序列[0 0 0 1][0 1 0 0] 产生相同的输出 ([0]),但这两个序列的可能性也相同,因此我们可以提取额外的位的输出,对于第一种情况返回 [0 0][0 1] 第二个。不过,这就是它变得更加复杂的地方,因为您需要开始缓冲输出位。

这两种技术都可以递归应用,并达到无损的极限(即,如果rand1 的概率为 0.5,则平均每个输入位都有一个输出位。)

完整描述(包括数学)在这里:http://www.eecs.harvard.edu/~michaelm/coinflipext.pdf

【讨论】:

    【解决方案3】:

    你需要弄清楚你想要接近 50% 0 50% 1。

    如果您将重复调用的结果添加到 rand1.如果结果为 0 或 2,则返回值为 0,如果为 1,则返回 1。(在代码中您可以使用模 2)

    int val = rand1();   // prob 30%      0, and 70%      1
    
    val=(val+rand1())%2; // prob 58%      0, and 42%      1  (#1 see math bellow)
    val=(val+rand1())%2; // prob 46.8%    0, and 53.2%    1  (#2 see math bellow)
    val=(val+rand1())%2; // prob 51.28%   0, and 48.72%   1
    val=(val+rand1())%2; // prob 49.488%  0, and 50.512%  1
    val=(val+rand1())%2; // prob 50.2048% 0, and 49.7952% 1
    

    你明白了。所以由你决定你想要的概率有多接近。每次后续调用都会使您接近 50% 50%,但永远不会完全相等。

    如果你想计算概率:

    1

    prob ((val+rand1()%2) = 0) = (prob(val = 0)*prob(rand1() = 0)) + (prob(val = 1)*prob(rand1() = 1)
                               = (0.3*0.3)+(0.7*0.7)
                               = 0.09 + 0.49
                               = 0.58
                               = 58%
    
    prob ((val+rand1()%2) = 1) = (prob(val = 1)*prob(rand1() = 0)) + (prob(val = 0)*prob(rand1() = 1)
                               = (0.7*0.3)+(0.3*0.7)
                               = 0.21 + 0.21
                               = 0.42 
                               = 42%
    

    2

     prob ((val+rand1()%2) = 0) = (prob(val = 0)*prob(rand1() = 0)) + (prob(val = 1)*prob(rand1() = 1)
                                = (0.58*0.3)+(0.42*0.7)
                                = 0.174 + 0.294
                                = 0.468
                                = 46.8%
    
     prob ((val+rand1()%2) = 1) = (prob(val = 1)*prob(rand1() = 0)) + (prob(val = 0)*prob(rand1() = 1)
                                = (0.42*0.3)+(0.58*0.7)
                                = 0.126 + 0.406
                                = 0.532
                                = 53.2%
    

    【讨论】:

    • 我想知道和理解你写的内容,但我没有解释清楚
    • @ShivanshJagga,关键是您可以绝对精确地确定需要调用多少次 val=(val+rand1())%2 才能获得接近分布的最终值50% 0 和 50% 1 由您决定。我表明,在 6 次调用之后,您的比例为 50.2% 0,49.8% 1。如果您需要更好的分布,请多做几次。自己算算。我也非常喜欢 finnw 的回答。
    【解决方案4】:

    rand2 函数下方将提供 50% 的概率出现 0 或 1。

    #define LIMIT_TO_CALCULATE_PROBABILITY 10 //set any even numbers
    
    int rand2()
    {
        static int one_occurred = 0;
        static int zero_occured = 0;
        int rand_value = 0;
        int limit = (LIMIT_TO_CALCULATE_PROBABILITY / 2);
    
        if (LIMIT_TO_CALCULATE_PROBABILITY == (one_occured + zero_occured))
        {
            one_occured = 0;
            zero_occured = 0;
        }
    
        rand_value = rand1();   
    
        if ((1 == rand_value) && (one_occured < limit))
        {
            one_occured++;
            return rand_value;
        }
        else if ((0 == rand_value) && (zero_occured < limit))
        {
            zero_occured++;
            return rand_value;
        }
        else if (1 == rand_value)
        {
            zero_occured++;
            return 0;
        }
        else if (0 == rand_value)
        {
            one_occured++;
            return 1;
        }   
    }
    

    【讨论】:

    • 这将产生 correlated 输出,这通常是不可取的。
    • 如果我们将 LIMIT_TO_CALCULATE_PROBABILITY 保持得越小越好,那么相关输出的发生率就会非常少。
    猜你喜欢
    • 2013-11-09
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 2020-07-24
    • 1970-01-01
    • 2023-01-03
    • 2013-05-20
    • 2014-05-26
    相关资源
    最近更新 更多