如何以难以预测的顺序循环固定的整数范围(比如100000-999999)?
即。我想要一些比A更优雅的东西A)选择一个随机数,然后B)检查它是否已经被使用过,如果是,请回到步骤A,原因如下(除非你能说服我):
答案 0 :(得分:9)
线性同余随机数发生器(在Knuth第2卷中以极其详细的细节覆盖)将以不易重复的方式逐步遍历给定范围内的每个值而不重复。基本陈述是
v = k * v + l mod m
其中m是集合的大小,k和l是m的相对素数(我相信这足以保证它按照需要工作),而v是正在使用的值。以某种或多或少的随机方式选择初始值,然后从那里开始。
一个优点是编写起来相当快,假设你可以避免溢出(通过限制k和m,或者使用任意精度的算术例程)。
答案 1 :(得分:4)
您应该查看使用linear feedback shift register。 “最大长度”LFSR将击中范围内的每个数字(2 ^ n -1),除了0。您可以存储第一个数字,这样您就可以知道它何时回到开始,或者您可以计算样本。问题是它是确定性的,所以从技术上讲,如果你知道算法就可以预测它。此外,给定序列中的任何数字,从该点开始,序列始终相同。
你可以拥有一堆LFSR算法的列表,并在开始之前随机选择一个,这样从运行到运行就不太可预测了。但是你用来选择算法的方法也是可以预测的......
如果您需要以真正的随机性进行此操作,那么您需要一个硬件随机数生成器(算法方法始终是可预测的)并且您必须维护该范围内所有数字的列表,然后使用随机数生成器从列表中选择一个数字,并同时从列表中删除它,这样就不会再次选择它。
答案 2 :(得分:3)
如果您需要不明显但不太安全,请为范围N
选择M
的步长,使N和M相对素数并执行算术模M
。
答案 3 :(得分:3)
如果您需要以加密安全的方式执行此操作,可能需要查看我在Cryptographically Secure Permutations with Block Ciphers上的文章。简而言之,选择一个分组密码,使用一种称为XOR折叠的技术将其降低到大于所需范围的2的最小功率,然后使用以下技术仅生成所需范围内的数字:
def permute(index, max):
index = E(index)
if index > max:
return permute(index, max)
也就是说,只需“重新加密”您生成的超出所需范围的任何数字。生成整个序列所需的工作量受限于源序列中的项目数。生成单个元素的最坏情况是1 + unused_range,但这种可能性非常小。
您可以将其应用于生成1:1映射的任何内容,当然,不仅仅是分组密码示例。如果您正在处理不同类型的RNG - 例如LFSR,而不是重新应用该函数,只需跳过该元素。
答案 4 :(得分:1)
如果订单不必是真正随机的(只是不可预测的),并且如果我们允许存储小范围的值(比如N),那么:
步骤2-3是必要的,否则每个第N个返回值都是可预测的。 改变子列表大小(N)和重载阈值(N / 2),以便在内存使用,重载频率和“随机性”之间找到一个很好的折衷方案。
答案 5 :(得分:1)
使用线性同余随机数生成器并丢弃范围之外的任何整数。
答案 6 :(得分:0)
让数据库生成一个包含数字1到N的表格。
让数据库为每个N值生成一个随机数。
返回按随机数排序的N个值。