[net.lang.mod2] random number generator for Logitech

dan@CASEUS.WISC.EDU (Daniel M. Frank) (05/13/86)

   Here is a random number generator my partner and I used for a simulation
project last spring.  It's not terribly good, but the distributions seemed
adequate for what we were doing (and we did run some tests).  Actually, we
built a pretty nifty simulation system using processes, with interprocess
communication via mailboxes.  Worked fine, although a bit slow (on an XT).

#!/bin/sh ----cut here-----cut here-----cut here-----cut here-----
#    This is a shell archive.
#    Run the following text with /bin/sh to extract.

YASASTART=`pwd`

cat - << \Funky!Stuff! > rand.def
DEFINITION MODULE Rand;

EXPORT QUALIFIED
  Random ;

PROCEDURE Random (): REAL;

END Rand.
Funky!Stuff!
cat - << \Funky!Stuff! > rand.mod
IMPLEMENTATION MODULE Rand;

CONST
  MAXINT = 32767;  (* ? *)
  DEFAULTSEED = 7321;
  NUMCALLS = 4;

VAR
  a : ARRAY[0..54] OF INTEGER;
  seed, maxRand: INTEGER;
  p, range: INTEGER;    (* p indexes into array a of random #'s, range
                            is range of numbers in array *)

(***************************************************************)


PROCEDURE RandGen();
VAR
  i, ran: INTEGER;
BEGIN
  FOR i := 0 TO 23 DO
    ran := a[i] - a[i + 31];
    IF ran < 0 THEN
      INC(ran,maxRand);
    END;
    a[i] := ran;
  END;

  FOR i := 24 TO 54 DO
    ran := a[i] - a[i - 24];
    IF ran < 0 THEN
      INC(ran,maxRand);
    END;
    a[i] := ran;
  END;
END RandGen;

(*******************************************************************)

PROCEDURE InitRandom(VAR iRange, iSeed: INTEGER): INTEGER;
VAR
  m, i, j, minSeed, maxSeed: INTEGER;
  f, fPrev, fTmp: INTEGER;  (* for computing Fibonacci numbers *)

BEGIN
(* Set the range and the window for legal seed values *)

  IF iRange <= 0 THEN
    iRange := MAXINT;
  END;
  minSeed := iRange DIV 10;
  maxSeed := iRange - minSeed;
  maxRand := iRange;

(* Set the first seed value *)
  iSeed := DEFAULTSEED;
  WHILE (iSeed < minSeed) DO
    iSeed := iSeed * 3;
  END;

  WHILE (iSeed > maxSeed) DO
    iSeed := iSeed DIV 3;
  END;

(* Scatter other values through the array to get things started.
   The values are (-1)^i * (iSeed*F(i-1) - F(i)) MOD MAXINT, 0<i<55,
   where F(i) is the ith Fibonacci number.  Scale the results to lie in
   [0,maxRand).  Then bake a few batches of random numbers to make things
   even more random.  *)

  fPrev := iSeed;
  a[0] := iSeed MOD maxRand;
  f := 1;
  FOR i := 1 TO 54 DO
    j := (21 * i) MOD 55;
    a[j] := f MOD maxRand;
    m := a[j];
    fTmp := f;    f:= fPrev - f;    fPrev := fTmp;
    IF (f < 0) THEN
      INC(f, MAXINT);
    END;
  END;

  FOR i:= 1 TO NUMCALLS DO
    RandGen();
  END;
  p := 54;

  RETURN (iSeed);
END InitRandom;

(***************************************************************)

PROCEDURE RandomInt(seed: INTEGER): INTEGER;
BEGIN
  DEC(p);
  IF p < 0 THEN
    RandGen();
    p := 54;
  END;
  RETURN (a[p]) ;
END RandomInt;

(*******************************************************************)

PROCEDURE Random(): REAL;
VAR
  rNum: REAL;
  i: INTEGER;

BEGIN
  i := RandomInt(seed);
  rNum := FLOAT(i) /  FLOAT(MAXINT) ;
  RETURN (rNum);
END Random ;

BEGIN
  range := 0;  seed := 0;
  seed := InitRandom(range, seed);
END Rand .
Funky!Stuff!