MODULE; RandomImprovedMcGill
Gnu CopyLefted.
Abstract: Pseudo-random number generator by Warren D. Smith.
IMPORT LongRealBasic AS R, RandomBasic, Word; IMPORT RandomRep; <* UNUSED *> CONST Module = "RandomImprovedMcGill."; CONST MULTmg = 69069; mgSIZE = 103; SCALEmg = (FLOAT(mgSIZE, R.T) / 4294967296.0D0); REVEAL T = TPublic BRANDED OBJECT MultCongMg: Word.T; (* initialize to a random odd word *) ShiftRegMg: Word.T; (* initialize to a random word with 7ff in LS 11 bits *) arrmg: ARRAY [0 .. mgSIZE - 1] OF Word.T; (* initialize to random Word.Ts *) ymg: Word.T := 0; OVERRIDES init := Init; engine := Engine; END; PROCEDURE******************************************************** McGillInit (SELF: T; initrng: RandomBasic.T; ): T = VAR BEGIN FOR i := mgSIZE - 1 TO 0 BY -1 DO SELF.arrmg[i] := initrng.generateWord(); END; SELF.MultCongMg := Word.Or(initrng.generateWord(), 2_1); SELF.ShiftRegMg := Word.Or(initrng.generateWord(), 16_7ff); RETURN SELF; END Init;
Super-duper
generator by G. Marsaglia, K. Ananthanarayana
& N. Paul; but with an improvement suggested by Marsaglia after observing that
the unmodified generator failed the MTUPLE test on low order bits.
That generator was linear and optimized for speed rather than randomness;
hence not to be relied on. It was a combination
of a shift register generator and a linear congruential generator.
Not being confident that Marsaglia's improvement will fix the MTUPLE
test problem, I have added one further improvement to the McGill generator:
I combined it with the Bays-Durham shuffling algorithm. The resulting
generator ought to pass the full Marsaglia test battery and also should
have a larger period.
********************************************************
PROCEDUREHow could this work? BaysDurham is called nowhere. (Lemming)Engine (SELF: T; ): Word.T = VAR r0, r1: Word.T; j : CARDINAL; BEGIN <* ASSERT Word.Size = 32 *> r0 := Word.RightShift(SELF.ShiftRegMg, 15); r1 := Word.Xor(SELF.ShiftRegMg, r0); r0 := Word.LeftShift(r1, 17); SELF.ShiftRegMg := Word.Xor(r0, r1); SELF.MultCongMg := Word.Times(MULTmg, SELF.MultCongMg); (** Marsaglia's improvement: we've changed Word.Xor --> Word.Plus: *) r1 := Word.Plus(SELF.MultCongMg, SELF.ShiftRegMg); (** My improvement: the normal McGill generator would just return r1 here, * but I feed it into a Bays-Durham shuffler. *) j := FLOOR(FLOAT(ybd, R.T) * SCALEmg); SELF.ymg := SELF.arrmg[j]; SELF.arrmg[j] := r1; RETURN SELF.ymg; END Engine;
CONST abd = 101; VAR arrbd: ARRAY [0 .. abd - 1] OF R.T; (* initialize to rands in [0,1) *) ybd : R.T := R.Zero; <* UNUSED *> (* it's crap, just to save the code *) PROCEDUREInputs a random real in [0,1), outputs aNewBD (initrng: RandomBasic.T; ): T = VAR SELF := NEW(T); BEGIN FOR i := abd - 1 TO 0 BY -1 DO arrbd[i] := initrng.generateReal(); END; RETURN SELF; END NewBD;
more random
one:
<* UNUSED *> PROCEDUREBaysDurhamShuffler (x: R.T; ): R.T = VAR j: CARDINAL; BEGIN j := FLOOR(FLOAT(abd, R.T) * ybd); ybd := arrbd[j]; arrbd[j] := x; RETURN ybd; END BaysDurhamShuffler; BEGIN END RandomImprovedMcGill.