如何使用最少的位在任意范围内生成无偏的随机数

时间:2013-12-27 17:19:00

标签: algorithm random uniform

由于鸽子洞的原则,你不能只使用

output = min + (rand() % (int)(max - min + 1))

生成无偏见,统一的结果。这个类似问题的answer提供了一个解决方案,但就消耗的随机比特而言,这是非常浪费的。

例如,如果源的随机范围较低,那么必须从源生成第二个值的可能性非常高。另外,使用更大的光源范围本身就是浪费。

虽然我确定可以推导出最佳的源范围大小,但这并没有解决可能有更好的算法的问题,而不是优化这个算法。

[编辑]我的想法已在答案中显示,产生有偏见的结果。

我遇到的一种方法是

  1. 消耗覆盖所需范围所需的最小位数。
  2. 如果该值超出所需范围,则只丢弃一位并再消耗一位。
  3. 根据需要重复。

2 个答案:

答案 0 :(得分:4)

消除偏见的常用方法是丢弃超出所需范围的数字。如上所述,这是浪费。通过从更多位开始并同时生成多个随机数,可以最大限度地减少浪费;您可以在输入范围与输出之间实现更好的匹配。

例如,拿一卷模具。输出有6种可能性。对于每个产生的随机数,天真的方法将需要3个随机位。第一个例子展示了鸽子洞问题。

def pigeon_die(total_bit_count):
    for i in xrange(total_bit_count // 3):
        bits = random.getrandbits(3)
        yield 1 + bits * 6 // 8

1 : 832855
2 : 417835
3 : 416012
4 : 833888
5 : 416189
6 : 416554
total 3333333
max/min 2.00448063998

第二个例子是常用的浪费方法。您可以看到它从相同数量的随机位产生较少的随机数,但偏差被消除。

def wasteful_die(total_bit_count):
    for i in xrange(total_bit_count // 3):
        bits = random.getrandbits(3)
        if bits < 6:
            yield 1 + bits

1 : 417043
2 : 415812
3 : 417835
4 : 416012
5 : 416645
6 : 417243
total 2500590
max/min 1.00486517946

最后一个例子一次取13位,并从中生成5个随机数。这比天真的方法产生的数字更多!

def optimized_die(total_bit_count):
    for i in xrange(total_bit_count // 13):
        bits = random.getrandbits(13)
        if bits < 6**5:
            for j in range(5):
                yield 1 + bits % 6
                bits //= 6

1 : 608776
2 : 608849
3 : 608387
4 : 608119
5 : 607855
6 : 608559
total 3650545
max/min 1.00163525841

13位的选择是通过取2的幂的对数基数6并选择最接近整数的那个。

def waste_list(n):
    for bit in range(1, 31):
        potential = math.log(2**bit, n)
        count = int(potential)
        if count > 0:
            waste = potential - count
            yield waste, bit, count

for waste, bit, count in sorted(waste_list(6)):
    print bit, count, waste
    if bit == 3:
        break

13 5 0.029086494049
26 10 0.0581729880981
8 3 0.0948224578763
21 8 0.123908951925
3 1 0.160558421704

正如您所看到的,有4种选择比简单的3位更好。

答案 1 :(得分:0)

我担心你建议的做法有偏见。

假设随机数生成器的数字从0到255,但您想要一个0到254范围内的随机数。

如果随机数生成器产生了255(二进制的1111_1111),那么你的方法会抛弃一个位并再添加一个,直到最终你得到数字254(二进制的1111_1110)。 (如果我已正确理解你的方法。)

因此,对于每个数字,您生成的数字的概率为1/256,除了254,其概率为1/128。