这里,可能是几百,甚至几千,所以不可能预先生成一个列表
我试图使用 LCG,但它太慢了() 生成下一个数字。就效率而言,线性反馈移位寄存器 (LFSR) 可能是一种选择(),但我不能确保 LFSR 始终处于任意的最大重复周期. 有什么方法可以有效地完成这项工作吗?
这里,可能是几百,甚至几千,所以不可能预先生成一个列表
我试图使用 LCG,但它太慢了() 生成下一个数字。就效率而言,线性反馈移位寄存器 (LFSR) 可能是一种选择(),但我不能确保 LFSR 始终处于任意的最大重复周期. 有什么方法可以有效地完成这项工作吗?
随机数生成器将为您提供随机数,您可以将其调整到零之间2^n
,因此它将允许您在间隔内对随机位置进行采样。原则上,这些数字可能会重复自己——所以它们不是遍历,但这可能并不重要,原因如下:
如果很大(以千计),无论如何您将无法访问感兴趣区间内的所有数字。例如,对于,此区间内有整数,但在单个处理器上,您最多每秒可以访问约次——所以是不可能的。
如果您真的使用随机顺序,您甚至无法存储您已经访问过的号码。
因此,随机顺序或使用实际(非重复)排列的前几十亿或万亿个元素之间几乎没有实际差异。
使用一个普通的位计数器,并在除ECB或 CTR 之外的任何配置中使用分组密码对其进行加密,从作为第一个块的最低有效位开始,这样小的变化就会传播到结果的所有其他位。
如果不能被分组密码的大小整除,那么您需要使用格式保留加密处理余数,因为输出必须与输入大小相同。
这为您提供了新的索引。
如果您有解密计数器的方法,那么您可以简单地证明这个序列只访问每个值一次:如果任何两个输入状态映射到相同的输出,那么您将无法解密计数器并且加密本身将被证明是破碎的。
一个警告是,如果您在序列中向前跳,例如(假定是您的分组密码大小的倍数),那么加密计数的前位不会改变. 如果您对此不满意,请反转位的顺序并再次加密。仍然是 O(n),但稍微复杂一些。
显然,密码原语不是加快速度的好方法,但它展示了如何使事情线性化。如果你采用这种结构,但用更经济的东西(例如,64 位完美哈希)替换块密码,那么你可以恢复很多损失的性能。