如何穿越{ 0 , 1 , ... ,2n− 1 }{0,1,…,2n−1}随机顺序?

计算科学 随机数生成
2021-12-19 18:28:59

这里,n可能是几百,甚至几千,所以不可能预先生成一个列表

{0,1,,2n1}
并洗牌。因为是遍历,所以没有一个数应该被访问两次。我希望尽快生成下一个数字的过程。

我试图使用 LCG,但它太慢了(O(n2)) 生成下一个数字。就效率而言,线性反馈移位寄存器 (LFSR) 可能是一种选择(O(n)),但我不能确保 LFSR 始终处于任意的最大重复周期n. 有什么方法可以有效地完成这项工作吗?

2个回答

随机数生成器将为您提供随机数,您可以将其调整到零之间2^n,因此它将允许您在间隔内对随机位置进行采样。原则上,这些数字可能会重复自己——所以它们不是遍历,但这可能并不重要,原因如下:

  • 如果很大(以千计),无论如何您将无法访问感兴趣区间内的所有数字。例如,对于,此区间内有整数,但在单个处理器上,您最多每秒可以访问约次——所以是不可能的。nn=1000210001010010910100

  • 如果您真的使用随机顺序,您甚至无法存储您已经访问过的号码。

因此,随机顺序或使用实际(非重复)排列的前几十亿或万亿个元素之间几乎没有实际差异。

使用一个普通的位计数器,并在除ECB或 CTR 之外的任何配置中使用分组密码对其进行加密,从作为第一个块的最低有效位开始,这样小的变化就会传播到结果的所有其他位。n

如果不能被分组密码的大小整除,那么您需要使用格式保留加密处理余数,因为输出必须与输入大小相同。n

这为您提供了新的索引。

如果您有解密计数器的方法,那么您可以简单地证明这个序列只访问每个值一次:如果任何两个输入状态映射到相同的输出,那么您将无法解密计数器并且加密本身将被证明是破碎的。

一个警告是,如果您在序列中向前跳,例如(假定是您的分组密码大小的倍数),那么加密计数的前位不会改变. 如果您对此不满意,请反转位的顺序并再次加密。仍然是 O(n),但稍微复杂一些。22562256

显然,密码原语不是加快速度的好方法,但它展示了如何使事情线性化。如果你采用这种结构,但用更经济的东西(例如,64 位完美哈希)替换块密码,那么你可以恢复很多损失的性能。