【发布时间】:2011-04-24 00:45:23
【问题描述】:
以下 python 代码准确地描述了我想要为任意大小(人口)的序列实现的目标:
import random
fixed_seed = 1 #generate the same sequence every time with a fixed seed
population = 1000
sample_count = 5 #demonstration number
num_retries = 3 #just enough to show the repeatable behaviour
for trynum in xrange(num_retries):
#generate the fresh/ordered sequence (0->population)...
seq = range(population)
#seed the random number generator the same way every time...
random.seed(fixed_seed)
#shuffle the sequence...
random.shuffle(seq)
#display results for this try...
sample_sequence = [str(x) for x in seq[:sample_count]]
print "try %s: %s..." % (trynum + 1, ", ".join(sample_sequence))
#Sample output...
#try 1: 995, 721, 62, 326, 541...
#try 2: 995, 721, 62, 326, 541...
#try 3: 995, 721, 62, 326, 541...
该方法的问题在于它需要生成整个 首先在内存中排序。对于庞大的人口来说,这可能是一个问题。
请注意,此方法的一个潜在优势是您可以随时选择任何数组位置。
现在 - 如果手头的问题恰好让您将人口规模设置为 2 的幂 (减 1),线性反馈移位寄存器可用于获得可预测的随机序列。 LFSR 很简洁,在wikipedia article 中解释得很好。
下面的 python 代码演示了这一点(我做了一堆唯一性测试以确保它像宣传的那样工作)。再次查看 wikipedia article 以了解代码的工作原理 (Galois configuration)。
TAP_MASKS = { #only one needed, but I included 3 to make the code more useful
10: 0x00000240, #taps at 10, 7
16: 0x0000B400, #taps at 16, 14, 13, 11
32: 0xE0000200, #taps at 32, 31, 30, 10
}
def MaxLengthLFSR(seed, register_length):
"Gets next value from seed in max-length LFSR using Galois configuration."
lsb = seed & 1
next_val = seed >> 1
if lsb == 1:
mask = TAP_MASKS[register_length]
next_val ^= mask
return next_val
reglen = 16 #number of bits in register
population = (2**reglen) - 1 #not used, just showing it
fixed_seed = 1 #seed == startval in this case (could randomize in population)
sample_count = 5 #demonstration number
num_retries = 3 #just enough to show the repeatable behaviour
for trynum in xrange(num_retries):
next_val = fixed_seed
seq = [fixed_seed, ]
for x in xrange(sample_count - 1):
next_val = MaxLengthLFSR(next_val, reglen)
seq.append(next_val)
seq = [str(x) for x in seq]
print "try %s: %s..." % (trynum + 1, ", ".join(seq))
#Sample output...
#try 1: 1, 46080, 23040, 11520, 5760...
#try 2: 1, 46080, 23040, 11520, 5760...
#try 3: 1, 46080, 23040, 11520, 5760...
这很好,因为您可以拥有庞大的人口并轻松计算可重复的非重复随机数序列,而无需使用大量内存。
缺点是 a) 它仅限于大小为 (2**N - 1) 的“洗牌”序列,以及 b) 您无法确定随机序列中特定位置的值在任意位置。您需要知道某个特定点的值并从那里遍历序列。
后者 (b) 大多是可以的,因为大多数时候你会按顺序生成序列,所以你只需要记住最后一个值。 2 限制 (a) 的力量是一种交易杀手,但...取决于应用程序。
如何为任意序列长度实现类似最大长度 LFSR 的非重复结果?
作为奖励,最好有一个解决方案,您可以知道给定序列位置的数字,而无需遍历序列到该位置。
注意:如果您想为最大长度的 LFSR(生成整个寄存器群而不重复一次)提供一个良好的 LFSR 抽头位置起始集,this link is quite good 并且每个寄存器大小有大量的抽头位置(最多到 32 位,无论如何)。
另外请注意,我已经看到许多与我的问题和洗牌/LFSR 密切相关的问题,但没有一个与我所追求的完全相关(任意大小线性序列的可预测洗牌)。或者至少据我所知,无论如何。
我最近一直在研究Linear Congruential Generators,这似乎很有希望,但我还没有让它们工作。我不会继续坐在这个问题上,而是会问它,如果我想通了并且它们起作用了,就会发布答案。
【问题讨论】:
标签: python algorithm random lcg