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 Init (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;
********************************************************
McGill 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.