あなたの要件を満たすと思われる線形フィードバックシフトレジスタジェネレーターソリューションを構築しました。実装はフィボナッチ LFSR に基づいているため、指定されたビット数で完全なサイクルを実現します。先に進み、最大 19 ビットの多項式係数を入力し、指定された の値に基づいて適切な係数セットを選択しましたN
。生成された値はN
船外に排出されますが、サイクル全体の値の総数はそれよりも少ないため、時間内に値2N
が生成されます。LFSR は 1 ワードの状態を保存するので、それはスペースです。N
O(N)
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