Retrocomputing

Random number generator in COBOL

This is a random number generator for the ANSI-74 specification of COBOL. It is an implementation of Donald Knuth's random generator from pages 221-222 in Numerical Recipes in Pascal, 1st edition. It can be used for interactive games, but not for anything serious. Since COBOL doesn't have local variable scope, the private variables and paragraphs are prefixed with 'RAN3'. Therefore the risk of name clashes when importing the code into other source files should be easy to avoid.

The generator is initialized by moving a negative number into RANDSEED. Then do a PERFORM RAND. and read the variable RANDVAR.

Example client program

This example shows how to use the random number generator in another by the use of 'copy' statements. It calculates the average of 1000 random numbers.

       IDENTIFICATION DIVISION.
       PROGRAM-ID. AVERAGES-TEST.
       AUTHOR. S. ROUG.
       ENVIRONMENT DIVISION.
       CONFIGURATION SECTION.
       SOURCE-COMPUTER. LINUX.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       COPY "rand-ws.cbl".
      * Variables for the testing
       77 AVERAGE     PIC 999V9(9) VALUE 0.

       PROCEDURE DIVISION.
       TESTIT.
           DISPLAY "TEST RANDOM NUMBER GENERATOR".
           MOVE -2992 TO RANDSEED.
           PERFORM TESTRUN 1000 TIMES.
           DIVIDE 1000 INTO AVERAGE.
           DISPLAY "AVERAGE: ", AVERAGE.
           STOP RUN.
       TESTRUN.
           PERFORM RAND.
           ADD RANDVAL TO AVERAGE
              ON SIZE ERROR DISPLAY "OVERFLOW".
      *    DISPLAY RANDVAL.

       COPY "rand-proc.cbl".

rand-ws.cbl

      * Constants
      * FAC is 1/MBIG
       77 RAN3-MSEED  PIC 9(9)   COMPUTATIONAL VALUE 161803398.
       77 RAN3-MBIG   PIC 9(10)  COMPUTATIONAL VALUE 1000000000.
       77 RAN3-FAC    PIC 9V9(9) COMPUTATIONAL VALUE 0.000000001.
      * State variables
       77 RANDSEED    PIC S9(9)  COMPUTATIONAL VALUE -1.
       77 RAN3INEXT   PIC 99     COMPUTATIONAL.
       77 RAN3EXTP    PIC 99     COMPUTATIONAL.
       77 RANDVAL     PIC 9V9(9) COMPUTATIONAL.
       01 RAN3MATRIX OCCURS 55 TIMES.
           03 RAN3MA  PIC S9(10).
       77 RAN3-MJ     PIC S9(10) COMPUTATIONAL.
       77 RAN3-MK     PIC S9(10) COMPUTATIONAL.
       77 RAN3-I      PIC 9999   COMPUTATIONAL.
       77 RAN3-J      PIC 9999   COMPUTATIONAL.
       77 RAN3-K      PIC 9999   COMPUTATIONAL.

rand-proc.cbl

      * Knuth's random generator from pages 221-222 in
      * Numerical Recipes in Pascal, 1st edition.
      * Returns a uniform random deviate between 0.0 and 1.0.
      * (Uses long integers)
      * Set randseed to any negative value to (re)initialize the sequence.
      * Returns the value in global RANDVAL.
       RAND.
           IF RANDSEED < 0
               PERFORM RAN3-INIT.
           ADD 1 TO RAN3INEXT.
           IF RAN3INEXT > 55
               MOVE 1 TO RAN3INEXT.
           ADD 1 TO RAN3EXTP.
           IF RAN3EXTP > 55
               MOVE 1 TO RAN3EXTP.
           SUBTRACT RAN3MA(RAN3EXTP) FROM RAN3MA(RAN3INEXT)
               GIVING RAN3-MJ.
           IF RAN3-MJ < 0
               ADD RAN3-MBIG TO RAN3-MJ.
           MOVE RAN3-MJ TO RAN3MA(RAN3INEXT).
           MULTIPLY RAN3-MJ BY RAN3-FAC GIVING RANDVAL.

      *
      * Initialize the storage for the random generator
      *
       RAN3-INIT.
           ADD RAN3-MSEED TO RANDSEED GIVING RAN3-MJ.
           IF RAN3-MJ < 0
               SUBTRACT RAN3-MJ FROM 0 GIVING RAN3-MJ.
           PERFORM RAN3-BELOW-MBIG UNTIL RAN3-MJ NOT > RAN3-MBIG.
           MOVE RAN3-MJ TO RAN3MA(55).
           MOVE 1 TO RAN3-MK.
           PERFORM RAN3-INITTBL VARYING RAN3-I
               FROM 1 BY 1 UNTIL RAN3-I = 55.
           PERFORM RAN3-SCRM1 4 TIMES.
           MOVE 0 TO RAN3INEXT.
           MOVE 31 TO RAN3EXTP.
           MOVE 1 TO RANDSEED.

       RAN3-INITTBL.
           MULTIPLY RAN3-I BY 21 GIVING RAN3-J.
           DIVIDE RAN3-J BY 55 GIVING RAN3-K.
           MULTIPLY 55 BY RAN3-K.
           SUBTRACT RAN3-K FROM RAN3-J.
           MOVE RAN3-MK TO RAN3MA(RAN3-J).
           SUBTRACT RAN3-MK FROM RAN3-MJ GIVING RAN3-MK.
           IF RAN3-MK < 0
               ADD RAN3-MBIG TO RAN3-MK.
           MOVE RAN3MA(RAN3-J) TO RAN3-MJ.

       RAN3-BELOW-MBIG.
           SUBTRACT RAN3-MBIG FROM RAN3-MJ.

       RAN3-SCRM1.
           PERFORM RAN3-SCRM2 VARYING RAN3-I
               FROM 1 BY 1 UNTIL RAN3-I > 55.
       RAN3-SCRM2.
           ADD 30 TO RAN3-I GIVING RAN3-J.
           DIVIDE RAN3-J BY 55 GIVING RAN3-K.
           MULTIPLY 55 BY RAN3-K.
           SUBTRACT RAN3-K FROM RAN3-J.
           ADD 1 TO RAN3-J.
           SUBTRACT RAN3MA(RAN3-J) FROM RAN3MA(RAN3-I).
           IF RAN3MA(RAN3-I) < 0
               ADD RAN3-MBIG TO RAN3MA(RAN3-I).