由于鸽子洞原理,您不能只使用
output = min + (rand() % (int)(max - min + 1))
产生公正,统一的结果。这个类似问题的答案)提供了一种解决方案,但是就消耗的随机比特而言,这是非常浪费的。
例如,如果源的随机范围很低,那么必须从源生成第二个值的机会可能会很高。替代地,使用较大的光源范围也固有地是浪费的。
虽然我确定可以得出最佳的源范围大小,但这并没有解决可能存在更好的算法而不是优化该算法的问题。
[编辑]我的想法已显示在答案中,以产生有偏见的结果。
我想到的一种方法是
消除偏差的常用方法是丢弃超出所需范围的数字。如上所述,这是浪费的。通过从大量的位开始并同时生成多个随机数,可以最大程度地减少浪费。您可以在输入到输出的范围之间实现更好的匹配。
例如,拿一卷骰子。输出有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
通过采用2的幂的对数底数6并选择最接近整数的对数来选择13位。
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位更好。