Created
January 11, 2017 17:27
-
-
Save inmatarian/9635d0d03eeec943acac13a2bff25b96 to your computer and use it in GitHub Desktop.
Linear Feedback Shift Register pseudorandom number generator in lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- LFSRs are good for games where you want a random number generator with a short period, | |
-- so that speed runners can device tactics to control the RNG's state. | |
-- Otherwise they're a bit of an obsolete piece of tech. | |
-- See: https://en.wikipedia.org/wiki/Linear-feedback_shift_register | |
-- LFSRs work by shifting all of the bits to the right by one, and using the shifted | |
-- out bit to XOR in at specific taps. Another way to put it is that they first check | |
-- if the state is odd, then divides by two, and if it was odd, Exclusive-Ors in a value. | |
-- The bit shifted out is suitably random. Want more bits, cycle the generator more. | |
-- Note: Uses bit library and not bit32, would need minor conversion between the two. | |
require 'bit' | |
LFSR = { | |
value = 46080, -- taps 16 14 13 11 | |
state = 44257 | |
} | |
LFSR.__index = LFSR | |
function LFSR:seed(state) | |
self.state = bit.band(state, 65535) | |
if self.state <= 0 then self.state = 1 end | |
end | |
function LFSR:randBits(n) | |
n = n or 8 | |
local state, value, ret, b = self.state, self.value, 0 | |
repeat | |
b = bit.band(state, 1) | |
state = bit.bxor(bit.rshift(state, 1), bit.band(-b, value)) | |
ret, n = bit.lshift(ret, 1) + b, n - 1 | |
until n <= 0 | |
self.state = state | |
return ret | |
end | |
-- | |
function calculatePeriod(R) | |
local start, iter = R.state, 0, 0 | |
repeat | |
R:randBits(1) | |
iter = iter + 1 | |
assert(iter < 10000000) | |
until R.state == start | |
return iter | |
end | |
function showSample(R) | |
for i = 1, 16 do | |
for j = 1, 12 do | |
io.write(R:randBits(8), '\t') | |
end | |
io.write('\n') | |
end | |
end | |
print("Period:", calculatePeriod(setmetatable({}, LFSR))) | |
showSample(setmetatable({}, LFSR)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment