从随机位生成随机数

时间:2014-03-03 03:07:06

标签: algorithm random

所以我有一个函数给我随机位rand(0,1)我想将它推广到rand(a,b),它给出了a到b范围内的随机数。

我的想法是只计算b - a中的位数,然后将它们一起追加。我认为这会奏效,但不会是统一的。我觉得它会支持更大的数字而不是更小的数字(数字更接近a)。不是真的要求直接回答只是一些帮助会很好。

编辑: 到目前为止,这是我的想法,只是在统一部分上不确定

    pseudo code:
    function rand_range(a, b):
        n = b - a
        sum = a
        for i in range(n):
            sum += rand(0,1)

        return sum

5 个答案:

答案 0 :(得分:2)

是的,它不会是统一的。

考虑3位的简单情况:

0+0+0  0
0+0+1  1
0+1+0  1
0+1+1  2
1+0+0  1
1+0+1  2
1+1+0  2
1+1+1  3

很明显,1和2比0或3更容易发生。

当你增加位数时会变得更加不均匀 - 0并且最大值永远不会出现多次,中间出现的次数最多。


对于随机分布,我能想到的最好的方法是抛弃一些生成的数字。

b-a舍入到最接近的2减1的幂,然后单独生成每个位,如果结果大于b-a,请再试一次。

因此,如果b-a为5,则向上舍入为7,并生成所涉及的3位以使最大数量为7:

000  0
001  1
010  2
011  3
100  4
101  5
110  6
111  7

现在,在6或7的情况下,扔掉它们再试一次。

这可以通过使用字符串并连接0或1,并在结尾转换为数字,或者在每一步,乘以2(将所有位移到一个位置)来完成加0或1。

最后,您仍会将结果添加到a

答案 1 :(得分:0)

要获得统一分布,您需要拒绝抽样

假设您想要生成4,5,6(含)之间的数字,那么2位就足够了。映射00 - > 401 - > 510 - > 611 - > reject

pseudo code:
function rand_range(a, b):
    n = ceil(log2(b - a))
    m = b-a

    while(true)
        sum = a
        bits = []
        for i in range(n):
            bits.append(rand(0,1))
        sum += ToBase10(bits)
        if sum <= b:
            break

    return sum

答案 2 :(得分:0)

好吧,不仅结果不是随机的,而且你可能无法在(a,b)之间生成一个值,因为rand(0,1)总是会生成0,因此会产生一个超出的数字你的范围(如果是a>0)。

存在的问题是因为我们假设范围为(0,5)0只有1个表示为00000,而1则为5 10000,01000,00100,00010,00001 。实现这一点,直接解决方案应该是bijective映射,因此最简单的解决方案是将您的01视为数字的位,因为任何数字都具有唯一的表示形式基地2。

因此伪代码:

const MAX_BITS = 9;
const MAX_VAL = 1023; 
fun rand_range(a,b){
    sum = 0;
    for i<MAX_BITS
        sum += pow(2,i)*rand(1,0)
    // rescale
    return (b-a) * sum/MAX_VAL + a

}

可以选择输入到MAX_BITS的{​​{1}}和MAX_VAL数据类型限制,以便保证每个输入都能正确重新调整。

答案 3 :(得分:0)

认为以下是更好的方法: -

1. find log2(b-a) (number of bits to represent b-a)
2. generate log2(b-a) bits at random and construct decimal number from it.
3. if number is greater than (b-a) reject it and repeat 2.
4. else evaluate a + rand(b-a).

时间复杂度: - 如果随机数生成器是真正随机的,那么您将进行两次迭代以获得范围b-a中的随机数,因此T(a,b) = log(b-a)

以下是java实现: -

public class RNG {

    public static int rand(int a,int b) {
        int bits = 0;
        int diff = b-a;
        Random r = new Random();
        while(diff>0) {
            bits++;
            diff = diff/2;
        }
        while(true) {
            int acc = 0;
            for(int i=0;i<bits;i++) {
                acc = 2*acc +  r.nextInt(2);
            }
            if(acc<=b-a) {
                return(a+acc);
            }

        }

    }


    public static void main(String[] args) {

        int a = 150;
        int b = 300;
        int freq[] = new int[b+1];
        for(int i=0;i<1000;i++) {
          int k = rand(a,b);
          freq[k]++;

        }
        System.out.println("freq:");
        for(int j=a;j<=b;j++) {
            System.out.println(j+" : "+freq[j]);
        }
    }

}

答案 4 :(得分:0)

在Python中,您可以继承random.Random class以获得包括randint(a, b)在内的完整界面。

import random

class Random(random.Random):
    def random(self):
        """Get the next random number in the range [0.0, 1.0)."""
        return self.getrandbits(53) * 2**-53
    def getrandbits(self, k):
        """getrandbits(k) -> x.  Generates an int with k random bits."""
        return sum(rand(0, 1) << r for r in range(k))

    def seed(self, *args, **kwargs): # unused methods
        return None
    def getstate(self, *args, **kwargs):
        raise NotImplementedError
    def setstate(self, *args, **kwargs):
        raise NotImplementedError

x = rand(a,b)可以表示为r = Random(); x = r.randint(a, b)

优点是,如果您正确定义random()getrandbits()方法,那么其余代码已经过测试并且正常工作。 _randbelow() method显示了如何使用这些基元返回[0,n)范围{{1}}中的随机int。