Andrew Haley wrote:
> Brent proved that for every XOR-shift generator there is an
> equivalent LFSR. However, the XOR-shift form is more efficient in
> software than in its LFSR form.
I'm not convinced. A single LFSR goes from state n to 2n when the MSB
of n is not set (or, when the shift direction is the other way round,
from 2n to n, when the LSB of n is not set). Xorshift RNGs don't, they
have no such trivial relationship between two results.
LFSRs are easier to implement than xorshift generators, but have this
additional awkward property.
Brent gives an equvalent to the (1,3,10) xorshift RNG, which is what I
have used. This time for 32 bit systems only:
: xorshift ( n -- n' )
dup 1 lshift xor
dup 3 rshift xor
dup 10 lshift xor ;
This should be the equivalent LFSR, if I believe in Brent's paper:
$382d1e61 constant lfsr-eq \ polynom from the Brent paper
: lfsr dup 0< IF 2* lfsr-eq xor ELSE 2* THEN ;
If the clamed equivalence is true, xorshift and lfsr should perform the
same function. I use a Forth approach to math: let's try. For
simplicity I use 1 as starting point:
hex 1 ok
xorshift dup u. C03 ok
xorshift dup u. 5A0285 ok
xorshift dup u. CFEE3F7E ok
xorshift dup u. 8A12C1B2 ok
xorshift dup u. 4B5B9A8C ok
xorshift dup u. 82B8A266 ok
xorshift dup u. 5459267F ok
xorshift dup u. 3B6943D1 ok
xorshift dup u. 76FF48FD ok
drop 1 ok
lfsr dup u. 2 ok
lfsr dup u. 4 ok
lfsr dup u. 8 ok
lfsr dup u. 10 ok
lfsr dup u. 20 ok
lfsr dup u. 40 ok
lfsr dup u. 80 ok
lfsr dup u. 100 ok
I think we can stop here, and we have not even used the polynom Brent
proposed. Any LFSR will output this sequence with the starting point 1.
These are not equivalent functions. Whatever equivalence Brent has
proven, it's not functional equivalence. I'm pretty sure I know what an
LFSR is, so I don't think there is a misunderstanding. Did Brent test
his calculations? I mean, in the way we understand testing a Forth
program?
LFSRs have somewhat better properties when you use only the MSB.
: lfsr-seq ( seed rnd -- seed' rnd' )
2dup d+ dup 1 and IF swap lfsr-eq xor swap THEN ;
: gen-seq ( seed -- seed' rnd ) 0 $20 0 do lfsr-seq loop ;
If we start with 1, we will get 1 as first result.
1 gen-seq u. 1 ok
gen-seq u. 3DA97C19 ok
gen-seq u. 53BD8241 ok
gen-seq u. 879B88CF ok
gen-seq u. 37AE719E ok
gen-seq u. 9E525CC9 ok
gen-seq u. 36E8CFAB ok
gen-seq u. 1AFFC028 ok
gen-seq u. E86DFC12 ok
These results look better than the xorshift RNG, but they are way more
costly, and the cycle length is also smaller (only 2^(32-5) values).