Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!ut-sally!husc6!think!ames!sdcsvax!ucsdhub!hp-sdd!hplabs!hpcea!hpfcdc!hpldola!hp-lsd!dag
From: dag@hp-lsd.HP.COM (David Geiser)
Newsgroups: comp.misc
Subject: Re: anybody got a *good* random algorithm?
Message-ID: <3500003@hp-lsd.HP.COM>
Date: Mon, 6-Jul-87 11:10:36 EDT
Article-I.D.: hp-lsd.3500003
Posted: Mon Jul  6 11:10:36 1987
Date-Received: Sat, 11-Jul-87 05:42:34 EDT
References: <6552@reed.UUCP>
Organization: HP Logic Systems Division - ColoSpgs, CO
Lines: 168


The header pretty much says it.  I'm operating on a PDP-11/73, which gives
the time only down to the second, so it can't use time as a seed (actually,
I guess you can get tenths of a second, but that still doesn't help).

      .....

May vi rot in /dev/null.
----------------------------------------------------------------------

The random # stuff that follows is from a recent  edition of BYTE.  I think it
was done in Pascal in the article; I've re-done it in Modula-2.  I think it is
pretty  slick and can be  adapted  to many  different  CPUs -- that's  why I'm
posting instead of E-mailing.

I had to do some "Mickey Mouse" stuff with a 'tmp' variable to work around a
compiler defect with REAL numbers. (Sorry Mickey).

If I remembered who the author(s) were, I'd give credit.... sorry.

dag





IMPLEMENTATION MODULE utils;
VAR
x, y, z : INTEGER;
x1,y1,z1: REAL;

PROCEDURE rand ( ) : REAL;
(*

Anyone who considers  arithmetical  methods of producing  random digits is, of
course, in a state of sin.

	  --John von Neumann  (1951)


...

Many  generator use a simple  multiplicative  rule to generate the next number
based on a fixed prime  number and a  multiplier.  For  instance, if the prime
number were 30269 and the multiplier 171, you would have

    x(i+1) = (171*x(i)) MOD 30269

where 'i' is the iteration number (dag) ...


The  solution  depends upon two  techniques.  First,  consider  the problem of
using a high-level  language.  The simple generator given above can be written
as x := (171 * x) MOD 30269.  In practice this coding will not work adequately
on all  machines.  The values of x are  restricted  to the range 1 - 30268 and
therefore  will fit into a 16 bit  word.  This is not true for  171*x,  so the
expression  will  malfunction  on many  machines.  You could perform the above
calculation  "double length", but this either requires machine code or is very
expensive  in both time and  space.  If we write x in the form  177*r+s  where
0<=s<=176, then

171*x = 171*s +171*177*r 
      = 171*s + 30267*r 
      = 171*s + 30269*r - 2*r

Since 30269*r MOD 30269 = 0,
 
      (171*x) MOD 30269 = (171*s - 2*r) MOD 30269

Therefore, the statement above can be written as 
x := 171 * (x MOD 177) - 2 * (x DIV 177);

There is one problem, however.  It can return a negative number if we do not
add the following:

IF x < 0 THEN x := x + 30269;


We now have a mechanism  for making a simple  generator  for a 16 bit machine.
We choose a prime just slightly less than 32768 and then a multiplier  (around
the square root of the prime).  By using the above  coding  trick, the problem
of overflow can be eliminated  with the  equivalent of five or six  additional
instrutions.

But such a simple  generator on its own is  inadequate.  It will repeat itself
too  soon, and its  statistical  properties  are not near  enough  to those of
randomness.  To improve it, we need a second  technique  that  combines two or
more generators to make a new generator that is statistically  superior to any
of its components.  To understand this method,  consider the random numbers x1
and x2 in the range  0