非常基本的问题,但我似乎无法在Google上找到答案。标准PRNG将生成一系列随机位。我如何使用它来产生一系列随机整数,其均匀概率分布在[0,N]范围内?此外,每个整数应使用(期望值)log_2(N)位。
答案 0 :(得分:3)
如果你想要一个介于1和N之间的随机数:
您可以计算将N转换为二进制数所需的位数。那是:
n_bits = ceiling(log_2(N))
天花板是"围绕"操作。 (例如:ceiling(3)= 3,ceiling(3.7)= 4)
您选择随机二进制列表的前n_bits并将其更改为十进制数。
如果你的十进制数高于N,那么......你丢弃它并再次尝试使用n_bits的下一位,直到它起作用。
例如N = 12:
n_bits = ceiling(log_2(12))= 4
你取随机位序列的4个第一位,可能是" 1011"
你转过" 1011"到一个十进制数字给出13.这超过12,没有好处。所以:
取随机序列中的4个下一位,可能是" 1110"。
转' 1110'到小数,给出7.这有效!
希望它有所帮助。
答案 1 :(得分:0)
实际上,大多数标准PRNG(如线性同余生成器或Mersenne twister)会生成整数值序列。甚至通用的反馈移位寄存器技术通常在寄存器/字级实现。我不知道任何实际在比特级操作的常用技术。这并不是说它们不存在,但它们并不常见......
生成从1到N的值通常是通过将生成的整数值取模为所需的界限,然后进行接受/拒绝阶段来确保您不受模偏差的影响。例如,请参阅Java的nextInt(int bound)
方法,了解如何实现此方法。 (在结果中加1,得到[1,N]而不是[0,N-1]。)
答案 2 :(得分:0)
理论上这是可能的。找到a,b这样2 ^ a> N ^ b但非常接近。 (这可以通过迭代log2(N)的倍数来完成。)取第一个位,然后将其解释为二进制数,将其转换为基数N(同时检查该数字是否小于N ^ b)。数字给出了所需序列的b项。
问题在于转换为基数N是非常昂贵的,并且比基本上任何PRNG都要花费更多,所以这主要是理论上的答案。
答案 3 :(得分:-1)
从范围[0, N-1]
开始,然后使用0
和1
来执行二分搜索:
0
:下半部分1
:上半部分 e.g。当N = 16时,您从[0, 15]
开始,序列0, 1, 1, 0
将给出:
[0, 7]
[4, 7]
[6, 7]
[6]
如果N不是2的幂,则在任何迭代中,剩余数字列表的长度可能是奇数,在这种情况下,需要做出决定将中间数作为下半部分的一部分或上半部分。这可以在算法开始时确定。滚动一次:0表示包括下半部分的所有中间数字实例,1表示包括右半部分的所有中间数字实例。
我认为这至少比你要求的统一分布更接近于生成log(N)
位并采用它或取mod N
的常用方法。
为了说明我的意思,使用我的方法生成[0, 9]
范围内的数字:
To generate 0
0: 0, 0, 0, 0
1: 0, 0, 0
To generate 1
0: 0, 0, 0, 1
1: 0, 0, 1
To generate 2
0: 0, 0, 1
1: 0, 1, 0
To generate 3
0: 0, 1, 0
1: 0, 1, 1, 0
To generate 4
0: 0, 1, 1
1: 0, 1, 1, 1
To generate 5
0: 1, 0, 0, 0
1: 1, 0, 0
To generate 6
0: 1, 0, 0, 1
1: 1, 0, 1
To generate 7
0: 1, 0, 1
1: 1, 1, 0
To generate 8
0: 1, 1, 0
1: 1, 1, 1, 0
To generate 9
0: 1, 1, 1
1: 1, 1, 1, 1
另一个简单的答案是生成一个足够大的二进制数,使得mod N
不会(统计上)偏向某些数字而不是其他数字。但我认为你不会喜欢这个答案,因为从你的评论判断到另一个答案,你似乎在考虑生成的比特数的效率。
简而言之,我不确定为什么我对这个答案进行了低估,因为与它使用的位数(〜log(N)
)相比,这个算法似乎提供了一个很好的分布。
答案 4 :(得分:-1)
N
所需的位数(=值为1的最高位的位置) - 让我们称之为k
。k
位 - 让我们将其称为X
。Result = X mod N
。k
位,并从步骤2开始重复生成下一个随机数。或者,为了更好地分发,可以应用此步骤而不是步骤3: