MODULE Random;
IMPORT SYSTEM, Math;
CONST
max = 2147483647;
msbit = 40000000H;
allbits = 7FFFFFFFH;
halfrange = 20000000H;
step = 7;
TYPE
Generator* = OBJECT
VAR
buffer: ARRAY 250 OF SET;
index: LONGINT;
Z: LONGINT;
PROCEDURE Rand(): LONGINT;
CONST a = 16807; q = 127773; r = 2836;
VAR t: LONGINT;
BEGIN
t := a * (Z MOD q) - r * (Z DIV q);
IF t > 0 THEN Z := t ELSE Z := t + max END;
RETURN Z;
END Rand;
PROCEDURE InitSeed*(seed: LONGINT);
VAR
k, i: LONGINT;
mask, msb: LONGINT;
BEGIN
Z := seed; index := 0;
FOR i := 0 TO 249 DO
buffer[i] := SYSTEM.VAL(SET, Rand())
END;
FOR i := 0 TO 249 DO
IF Rand() > halfrange THEN
buffer[i] := buffer[i] + SYSTEM.VAL(SET,msbit);
END;
END;
msb := msbit; mask := allbits;
FOR i := 0 TO 30 DO
k := step * i + 3;
buffer[k] := buffer[k] * SYSTEM.VAL(SET,mask);
buffer[k] := buffer[k] + SYSTEM.VAL(SET, msb);
msb := msb DIV 2;
mask := mask DIV 2;
END;
END InitSeed;
PROCEDURE & Init*;
BEGIN
InitSeed(1)
END Init;
PROCEDURE Integer*(): LONGINT;
VAR newRand, j: LONGINT;
BEGIN
IF index >= 147 THEN j := index - 147 ELSE j := index + 103 END;
buffer[index] := buffer[index] / buffer[j];
newRand := SYSTEM.VAL(LONGINT, buffer[index]);
IF index >= 249 THEN index := 0 ELSE INC(index) END;
RETURN newRand
END Integer;
PROCEDURE Dice*(sides: LONGINT): LONGINT;
BEGIN
RETURN Integer() MOD sides;
END Dice;
PROCEDURE Uniform*(): REAL;
BEGIN
RETURN Integer() / allbits;
END Uniform;
PROCEDURE Exp*(mu: REAL): REAL;
BEGIN
RETURN -Math.ln(Uniform())/mu
END Exp;
END Generator;
TYPE
Sequence* = OBJECT
VAR r: Generator;
PROCEDURE InitSeed*(seed: LONGINT);
BEGIN {EXCLUSIVE}
r.InitSeed(seed)
END InitSeed;
PROCEDURE &Init*;
BEGIN
NEW(r)
END Init;
PROCEDURE Integer*(): LONGINT;
BEGIN {EXCLUSIVE}
RETURN r.Integer()
END Integer;
PROCEDURE Dice*(sides: LONGINT): LONGINT;
BEGIN {EXCLUSIVE}
RETURN r.Dice(sides)
END Dice;
PROCEDURE Uniform*(): REAL;
BEGIN {EXCLUSIVE}
RETURN r.Uniform()
END Uniform;
PROCEDURE Exp*(mu: REAL): REAL;
BEGIN {EXCLUSIVE}
RETURN r.Exp(mu)
END Exp;
END Sequence;
END Random.
(*
from the ADA version:
(c) Copyright 1997 Everett F. Carter Jr. Permission is
granted by the author to use this software for any
application provided this copyright notice is preserved.
The algorithm was originally described by
Kirkpatrick, S., and E. Stoll, 1981;
A Very Fast Shift-Register Sequence Random Number Generator,
Journal of Computational Physics, V. 40. pp. 517-526
Performance:
Its period is 2^249. This implementation is about 25% faster than
RandomNumbers.Uniform(). It also offers direct generation of
integers which is even faster (2x on PowerPC) and especially
good for FPU-challenged machines like the Shark NCs.
*)