[comp.lang.fortran] Random number generators

v087mxgb@ubvmsa.cc.buffalo.edu (Shawn E Thompson) (10/18/90)

Anyone need an excellent random number generator????


In my graduate studies, I am writing an optimization 
program based on the relatively unexploited 'Genetic
Algorithms' technique for the University of Buffalo.

In my wanderings (and beggings), I was given a terrific
random number generator, by ......um......oh......shoot -
I forget (I will make sure he gets credit, but the name
escapes me right now).

Anyway I will pass it along (he said its ok), if anyone needs
it. Again it is terriffic. 

It operates as follows;

   First a subroutine is called to initialize it, which
requests 2 user seeds between 0 & 32000 (an enormity of
  seed combos!). Then it is called as a mere function every 
   time you need a random number (between 0 & 1 but scalable)

Apparently (again, I forget exactly) but I think it is capable
of generating 10E6 random numbers from each pair of seeds!!!!




Up for grabs....



Shawn Thompson

V087MXGB@UBVMS.CC.BUFFALO.EDU
(Grad School of Mechanical Engineering)

Leica, Inc.
PO Box 123 
Buffalo, NY 14240-0123
(716) 891-3375

v087mxgb@ubvmsa.cc.buffalo.edu (Shawn E Thompson) (10/19/90)

**************************************************************************
**************************************************************************
I lost part of the text header that accompanied this, when I received it,
so here are some vitals (it came with no instructions, so those and the 
comments are mine);

I received this from STUART@ADS.COM, and feel you should drop THAT person 
a note of thanks from yourself and me. Stuart's original, that he sent me 
said that this originally appeared in "Toward a Universal Random Number
Generator" by George Marsaglia and Arif Zaman. Florida State University
Report: FSU-SCRI-87-50 (1987). It was later modified by F. James and 
published in "A Review of Pseudo-random Number Generators"

The highest recognition is due to these authors, who made this available.


Stuart says this is the BEST KNOWN RANDOM NUMBER GENERATOR available.
It passes all tests for a random number generator, and has a period
of 2^144, and will give bit-identical results on all machines with
at least 24-bit manitissas in the floating point representation.

I have run it on a machine that I believe has a 16 bit mantissa in the
floating point, and it was NOT identical results. But it still functioned
perfectly for my applications!

The algorithm is a combination of Fibonacci sequence (with lags of 97
and 33, and operation "subtraction plus one, modulo one") and an 
"arithmetic sequence" (using subtraction.

There are three routines contained herein. I have separated them and the 
notes with double lines of asterisks (just delete all between them and the
lines of asterisks).

The first program, called TstRAN is a test for correct operation.

The second part, RANMAR, is the function itself, which must be included 
in any program where you wish to call it from. 

The third part is the initialization routine, which asks for the number seeds.

The first would actually be replaced by YOUR application (note the way the
function is called, for anyone not familiar). The value returned by the RANMAR
function is fully scalable (I use it between 0 & 100 % by saying

           x=100*RANMAR()

Now, RMARIN and RANMAR share initialization variables in a common block,
so they can be separated between subroutines, etc (again, for anyone 
unfamiliar, I call RMARIN as a subroutine from my main, and then include
RANMAR as a function in some of my subroutines where I need to generate
random numbers).
**************************************************************************
**************************************************************************
      PROGRAM TstRAN
      INTEGER IJ, KL, I
C These are the seeds needed to produce the test case results
      IJ = 1802
      KL = 9373
C Do the initialization
      call rmarin(ij,kl)
C Generate 20000 random numbers
      do 10 I = 1, 20000
         x = RANMAR()
10    continue
C If the random number generator is working properly, the next six random
C numbers should be:
C           6533892.0  14220222.0  7275067.0
C           6172232.0  8354498.0   10633180.0
      write(*,20) (4096.0*4096.0*RANMAR(), I=1,6)
20    format (3f12.1)
      end
**************************************************************************
**************************************************************************
      subroutine RMARIN(IJ,KL)
C This is the initialization routine for the random number generator
C     RANMAR()
C NOTE: The seed variables can have values between:    0 <= IJ <= 31328
C                                                      0 <= KL <= 30081
      real U(97), C, CD, CM
      integer I97, J97
      logical TEST
      common /raset1/ U, C, CD, CM, I97, J97, TEST
      DATA TEST /.FALSE./
      if( IJ .lt. 0  .or.  IJ .gt. 31328  .or.
     *    KL .lt. 0  .or.  KL .gt. 30081 ) then
          print '(A)', ' The first random number seed must have a value
     *between 0 and 31328'
          print '(A)',' The second seed must have a value between 0 and
     *30081'
            stop
      endif
      i = mod(IJ/177, 177) + 2
      j = mod(IJ    , 177) + 2
      k = mod(KL/169, 178) + 1
      l = mod(KL,     169)
      do 2 ii = 1, 97
         s = 0.0
         t = 0.5
         do 3 jj = 1, 24
            m = mod(mod(i*j, 179)*k, 179)
            i = j
            j = k
            k = m
            l = mod(53*l+1, 169)
            if (mod(l*m, 64) .ge. 32) then
               s = s + t
            endif
            t = 0.5 * t
3        continue
         U(ii) = s
2     continue
      C = 362436.0 / 16777216.0
      CD = 7654321.0 / 16777216.0
      CM = 16777213.0 /16777216.0
      I97 = 97
      J97 = 33
      TEST = .TRUE.
      return
      end
**************************************************************************
**************************************************************************
      function ranmar()
      real U(97), C, CD, CM
      integer I97, J97
      logical TEST
      common /raset1/ U, C, CD, CM, I97, J97, TEST
      integer ivec
      if( .NOT. TEST ) then
         print '(A)',' Call the init routine (RMARIN) before calling RAN
     *MAR'
         stop
      endif
         uni = U(I97) - U(J97)
         if( uni .lt. 0.0 ) uni = uni + 1.0
         U(I97) = uni
         I97 = I97 - 1
         if(I97 .eq. 0) I97 = 97
         J97 = J97 - 1
         if(J97 .eq. 0) J97 = 97
         C = C - CD
         if( C .lt. 0.0 ) C = C + CM
         uni = uni - C
         if( uni .lt. 0.0 ) uni = uni + 1.0
         RANMAR = uni
      return
      END
**************************************************************************