我已经构建了一个线性反馈移位寄存器生成器解决方案,我认为它可以满足您的要求。该实现基于斐波那契 LFSR,因此它实现了给定位数的完整周期。我继续输入最多 19 位的多项式系数,并根据 的指定值选择适当的系数集N
。生成的值大于N
被丢弃的值,但整个周期中的值总数小于,2N
因此它会及时生成您的N
值O(N)
。LFSR 保留一个状态字,所以它是O(1)
空间。
这是Ruby中的实现:
#!/usr/bin/env ruby -w
# Linear Feedback Shift Register generator which operates on smallest bit
# range possible for a specified integer range, and skips over values outside
# the specified range. Since this attains full cycle length for the specified
# number of bits, and the number of bits is minimized relative to the specified
# N, the total number of iterations is bounded by 2N and is therefore O(N).
class LFSR
# Polynomials for maximal LFSRs determine shift amounts for up to 19 bits.
# See https://en.wikipedia.org/wiki/Linear_feedback_shift_register for
# details. Add more entries if you need more than 19 bits.
SHIFT_AMT = [
[], [], [1], [1], [1], [2], [1], [1], [2, 3, 4], [4], [3], [2],
[1, 2, 8], [1, 2, 5], [1, 2, 12], [1], [2, 3, 5], [3], [7], [1, 2, 5]
]
# Constructor for the LFSR. Specify the N and seed value.
def initialize(n, seed)
@n = n
@state = (seed % n) + 1
@num_bits = Math.log2(n).floor + 1
end
# Generate the next iterate of the LFSR. If it's above the specified N,
# keep trying until you're done.
def next_value
loop do
bit = @state
SHIFT_AMT[@num_bits].each { |amt| bit ^= (@state >> amt) }
@state = ((@state >> 1) | ((bit & 1) << (@num_bits - 1)))
return @state if @state <= @n
end
end
end
N = (ARGV.shift || 100).to_i # Specify the 'N' value on cmd line. Default = 100
SEED = (ARGV.shift || 0x7FFF).to_i # Optionally specify a "seed" for the LFSR
my_lfsr = LFSR.new(N, SEED) # Instantiate an LFSR object
N.times { p my_lfsr.next_value } # Invoke it N times, print the results