生成随机(a,b)调用Random(0,1)

时间:2011-12-10 17:23:23

标签: algorithm random

有一个已知的Random(0,1)函数,它是一个统一的随机函数,这意味着,它将给出0或1,概率为50%。实施只调用Random(a, b)

Random(0,1)

我到目前为止,将范围a-b放在基于0的数组中,然后我有索引0,1,2 ... b-a。

然后调用RANDOM(0,1) b-a次,将结果作为生成的idx求和。并返回元素。

然而,由于书中没有答案,我不知道这种方式是正确的还是最好的。如何证明返回每个元素的概率完全相同且为1/(b-a+1)

这样做的正确/更好的方法是什么?

5 个答案:

答案 0 :(得分:9)

如果您的RANDOM(0,1)返回0或1,每个概率为0.5,那么您可以生成位,直到您有足够的数字表示二进制数(b-a + 1)。这为您提供了一个稍微过大的随机数:如果失败,您可以测试并重复。像这样(在Python中)。

def rand_pow2(bit_count):
    """Return a random number with the given number of bits."""
    result = 0
    for i in xrange(bit_count):
        result = 2 * result + RANDOM(0, 1)
    return result

def random_range(a, b):
    """Return a random integer in the closed interval [a, b]."""
    bit_count = math.ceil(math.log2(b - a + 1))
    while True:
        r = rand_pow2(bit_count)
        if a + r <= b:
            return a + r

答案 1 :(得分:1)

当你对随机数求和时,结果不再均匀分布 - 它看起来像一个高斯函数。查阅“大数定律”或阅读任何概率书/文章。就像翻转硬币100次一样,极不可能给出100个头。它可能会有近50个头和50个尾巴。

答案 2 :(得分:1)

您倾向于将0范围从a-b放到m=a-b是正确的。但是,你不能按照你的说法去做。 This question确切地询问如何执行此操作,the answer使用唯一因子分解。在基础2中写下e,跟踪所需的最大指数,例如m。然后,找到小于2^e的{​​{1}}的最大倍数,将其称为k。最后,使用e生成RANDOM(0,1)个数字,将其作为某个数字2的基础x扩展,如果x < k*m,则返回x,否则再试一次。该程序看起来像这样(当m <2 ^ 2时的简单情况):

int RANDOM(0,m) {

    // find largest power of n needed to write m in base 2
    int e=0;
    while (m > 2^e) {
        ++e;
    }

    // find largest multiple of m less than 2^e
    int k=1;
    while (k*m < 2^2) {
        ++k
    }
    --k; // we went one too far

    while (1) {
        // generate a random number in base 2
        int x = 0;
        for (int i=0; i<e; ++i) {
            x = x*2 + RANDOM(0,1); 
        }
        // if x isn't too large, return it x modulo m
        if (x < m*k) 
            return (x % m);
    }
}

现在,您只需将a添加到结果中,即可在ab之间获得均匀分布的数字。

答案 3 :(得分:0)

分而治之可以帮助我们使用随机(0,1)生成范围[a,b]中的随机数。这个想法是

  1. 如果a等于b,则随机数为
  2. 查找范围[a,b]
  3. 的中间位置
  4. 生成随机(0,1)
  5. 如果大于0,则使用递归
  6. 返回[a,mid]范围内的随机数
  7. else使用递归
  8. 返回范围[mid + 1,b]中的随机数

    工作'C'代码如下。

    int random(int a, int b)
    { 
        if(a == b)
            return a;
    
        int c = RANDOM(0,1); // Returns 0 or 1 with probability 0.5
        int mid = a + (b-a)/2;
    
        if(c == 0)
           return random(a, mid);
        else
           return random(mid + 1, b);
    }
    

答案 4 :(得分:0)

如果您的RNG以相同的概率返回{0, 1},您可以轻松创建一个以相同概率返回数字{0, 2^n}的RNG。

要执行此操作,您只需使用原始RNG n次,即可获得0010110111之类的二进制数字。每个数字(从0到2 ^ n)都是相同的。

现在很容易从ab获得RNG,其中b - a = 2^n。您只需创建一个以前的RNG并向其添加a

现在最后一个问题是如果b-a不是2^n,您应该怎么做?

好东西,你几乎什么都不做。依靠rejection sampling技术。它告诉你,如果你有一个大集合并且在该集合上有一个RNG并且需要从该集合的子集中选择一个元素,你可以继续从一个更大的集合中选择一个元素并丢弃它们,直到它们存在于你的子集中

所以你要做的就是找b-a并找到第一个n b-a <= 2^n。然后使用拒绝采样,直到您选择一个较小的b-a元素。比你刚添加a