(* This is a port of the A2 RNG. Although not suitable for cryptographic applications, naclcl.lisp used the built-in RNG so it's good enough to get started *) MODULE Random; IMPORT SYSTEM, Texts, Oberon; CONST max = 2147483647; msbit = 40000000H; allbits = 7FFFFFFFH; halfrange = 20000000H; step = 7; VAR buffer: ARRAY 250 OF SET; index: INTEGER; Z: INTEGER; W: Texts.Writer; PROCEDURE Rand(): INTEGER; CONST a = 16807; q = 127773; r = 2836; VAR t: INTEGER; 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: INTEGER); VAR k, i: INTEGER; mask, msb: INTEGER; 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 Integer*(): INTEGER; VAR newRand, j: INTEGER; BEGIN IF index > 147 THEN j := index - 147 ELSE j := index + 103 END; buffer[index] := buffer[index] / buffer[j]; newRand := SYSTEM.VAL(INTEGER, buffer[index]); IF index >= 249 THEN index := 0 ELSE INC(index) END; RETURN newRand END Integer; PROCEDURE Test*; BEGIN (* Texts.WriteHex(W, Integer()); Texts.WriteLn(W); *) Texts.WriteHex(W, LSL(16, 2)); Texts.WriteLn(W); Texts.WriteHex(W, LSL(16, -2)); Texts.WriteLn(W); Texts.Append(Oberon.Log, W.buf) END Test; (* TODO: really need to seed this, or we always get the same sequence. As I probably should expect. *) BEGIN InitSeed(1); Texts.OpenWriter(W) END Random.