* /*
      * ------------------------------------------------------------------------------
      * readable.c: My random number generator, ISAAC.
      * (c) Bob Jenkins, March 1996, Public Domain
      * You may use this code in any way you wish, and it is free.  No warrantee.
      * ------------------------------------------------------------------------------
      * */
      * #ifndef STANDARD
      * #include "standard.h"
      * #endif

      *
      * Original can be found at : http://burtleburtle.net/bob/rand/isaacafa.html
      *

      * This COBOL implementation is created by Gerald Moull - www.MyDocz.com
      *
      * Original C code is commented out with the COBOL equivalent following.
      *
      * I believe it is true to ANSI-85 compatibility, or at least should compile in all
      * COBOL compilers, with the exception of RM/COBOL specific C$ calls for bitwise
      * operations.  These would need adapting for other COBOL dialects.

       ID Division.
       Program-ID. ISAAC.
       
       Data Division.
       Working-Storage Section.

      * /* a ub4 is an unsigned 4-byte quantity */
      *
      * /* external results */
      * ub4 randrsl[256], randcnt;
      *
      * /* internal state */
      * static    ub4 mm[256];
      * static    ub4 aa=0, bb=0, cc=0;

       01  RandomData.
           03  mmBlock.
               05  mm                  Pic 9(10) Binary(4) Occurs 256.
           03  AA                      Pic 9(10) Binary(4) Value 0.
           03  BB                      Pic 9(10) Binary(4) Value 0.
           03  CC                      Pic 9(10) Binary(4) Value 0.
           03  RandRslBlock.
               05  RandRsl             Pic 9(10) Binary(4) Occurs 256.
           03  RandCnt                 Pic 9(10) Binary(4) Value 0.

           03  AAs                     Pic 9(10) Binary(4).

      *    register ub4 i,x,y;

           03  i                       Pic 9(10) Binary(4) Value 0.
           03  x                       Pic 9(10) Binary(4) Value 0.
           03  y                       Pic 9(10) Binary(4) Value 0.

           03  i2                      Pic 9(10) Binary(4).
           03  i2r                     Pic 999.
           03  i4                      Pic 999.
           03  ir                      Pic 999.
           03  xs                      Pic 9(10) Binary(4).
           03  ys                      Pic 9(10) Binary(4).

      * word i;
      * ub4 a,b,c,d,e,f,g,h;

           03  a                       Pic 9(10) Binary(4) Value 0.
           03  b                       Pic 9(10) Binary(4) Value 0.
           03  c                       Pic 9(10) Binary(4) Value 0.
           03  d                       Pic 9(10) Binary(4) Value 0.
           03  e                       Pic 9(10) Binary(4) Value 0.
           03  f                       Pic 9(10) Binary(4) Value 0.
           03  g                       Pic 9(10) Binary(4) Value 0.
           03  h                       Pic 9(10) Binary(4) Value 0.

      * word flag;

           03  Flag                    Pic 9.

      *    ub4 i,j;

           03  iMain                   Pic 9(10) Binary(4) Value 0.
           03  jMain                   Pic 9(10) Binary(4) Value 0.

           03  MainDispLine.
               05  MainDisp            Pic x(8) Occurs 8.
           03  MainLines               Pic 999.
           03  MainPos                 Pic 999.
           03  MainPause               Pic x.

           03  tMix                    Pic 9(10) Binary(4).

           03  HexValue.
               05  HexValueChar        Pic x     Occurs 4.
           03  Hex.
               05  HexChar                       Occurs 4.
                   07  HexCharH        Pic x.
                   07  HexCharL        Pic x.
           03  iHex                    Pic 999.
           03  HexWorkX.
               05  HexWork9            Pic 999   Binary(1).
           03  HexLetters            Pic x(16) Value "0123456789abcdef".
           03                          Redefines HexLetters.
               05  HexLetter           Pic x     Occurs 16.

       Procedure Division.

      *****************************************************************
      * int main()
      *  {
      *****************************************************************

       main.
           Display "ISAAC Test".
       
      *    aa=bb=cc=(ub4)0;

           Move 0                      to aa.
           Move 0                      to bb.
           Move 0                      to cc.
           
      *    for (i=0; i<256; ++i) mm[i]=randrsl[i]=(ub4)0;

           Perform Varying iMain From 1 By 1 Until iMain > 256
               Move 0                  to mm      (iMain)
               Move 0                  to RandRsl (iMain)
           End-Perform.
          
      *    randinit(TRUE);

           Move 1                      to Flag.
           Perform randinit.
          
      *    for (i=0; i<2; ++i)  {

           Move 0                      to MainLines.
           Move 0                      to MainPos.
           Perform Varying iMain From 1 By 1 Until iMain > 2         

      *        isaac();
      
               Perform isaac
               
      *        for (j=0; j<256; ++j) {

               Perform Varying jMain From 1 By 1 Until jMain > 256
      
      *            printf("%.8lx",randrsl[j]);
      *            if ((j&7)==7) printf("\n");

                   Move RandRsl (jMain) (1:) to HexValue
                   Perform ToHex
                   Add 1                to MainPos
                   Move Hex             to MainDisp (MainPos)
                   If MainPos = 8
                       Display MainDispLine
                       Move Spaces      to MainDispLine
                       Move 0           to MainPos
                       Add 1            to MainLines
                       If MainLines = 20
                           Display "Press return to continue..."
                           Accept MainPause Col 0
                           Move 0       to MainLines
                       End-if
                   End-if
               End-Perform
           End-Perform.
      *    } } }
           Display "Press return to continue...".
           Accept MainPause Col 0.
           Stop Run.
           

      *****************************************************************
      * void isaac() {
      *****************************************************************

       isaac.

      *    cc = cc + 1;    /* cc just gets incremented once per 256 results */
      *    bb = bb + cc;   /* then combined with bb */

           Add 1                       to CC.
           Add CC                      to BB.

      *    for (i=0; i<256; ++i)

           Perform Varying i From 1 By 1 Until i > 256

      *         x = mm[i];

               Move mm (i)             to x

      *        switch (i%4) {
      *         case 0: aa = aa^(aa<<13); break;
      *         case 1: aa = aa^(aa>>6); break;
      *         case 2: aa = aa^(aa<<2); break;
      *         case 3: aa = aa^(aa>>16); break; }

               Divide i By 4           giving i4 remainder ir
               Move AA                 to AAs
               Evaluate ir
                 When 1 Call "C$LogicalShiftLeft"  Using AAs (1:), 13
                 When 2 Call "C$LogicalShiftRight" Using AAs (1:),  6
                 When 3 Call "C$LogicalShiftLeft"  Using AAs (1:),  2
                 When 0 Call "C$LogicalShiftRight" Using AAs (1:), 16
               End-Evaluate
               Call "C$LogicalXor" Using AA (1:), AAs (1:)
 
      *        aa = mm[(i+128)%256] + aa;

               Add 128, i              giving i2
               Divide i2 By 256        giving i2 Remainder i2r
               If i2r = 0
                   Move 256            to i2r
               End-if
               Add mm (i2r)            to AA

      *        mm[i] = y = mm[(x>>2)%256] + aa + bb;

               Move x                  to xs
               Call "C$LogicalShiftRight" Using xs (1:), 2
               Add 1                   to xs
               Divide xs By 256        giving i2 Remainder i2r
               If i2r = 0
                   Move 256            to i2r
               End-if
               Compute y = mm (i2r) + AA + BB
               Move y                  to mm (i)

      *        randrsl[i] = bb = mm[(y>>10)%256] + x;

               Move y                  to ys
               Call "C$LogicalShiftRight" Using ys (1:), 10
               Add 1                   to ys
               Divide ys By 256        giving i2 Remainder i2r
               If i2r = 0
                   Move 256            to i2r
               End-if
               Compute BB = mm (i2r) + x
               Move BB                 to RandRsl (i)

           End-Perform.
      
      *    /* Note that bits 2..9 are chosen from x but 10..17 are chosen
      *       from y.  The only important thing here is that 2..9 and 10..17
      *       don't overlap.  2..9 and 10..17 were then chosen for speed in
      *       the optimized version (rand.c) */
      *    /* See http://burtleburtle.net/bob/rand/isaac.html
      *       for further explanations and analysis. */
      *  }




      *****************************************************************
      * /* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */
      *
      * void randinit(flag)
      * word flag;
      * {
      *****************************************************************

       randinit.

      *    aa=bb=cc=0;
      *    a=b=c=d=e=f=g=h=0x9e3779b9;  /* the golden ratio */

           Move 0                      to AA.
           Move 0                      to BB.
           Move 0                      to CC.
           Move x"9e3779b9"            to a (1:).
           Move a                      to b.
           Move a                      to c.
           Move a                      to d.
           Move a                      to e.
           Move a                      to f.
           Move a                      to g.
           Move a                      to h.

      *    for (i=0; i<4; ++i)          /* scramble it */
      *    {
      *      mix(a,b,c,d,e,f,g,h);
      *    }

           Perform mix 4 Times.

      *    for (i=0; i<256; i+=8)   /* fill in mm[] with messy stuff */ 
      *    {

           Perform Varying i From 1 By 8 Until i > 256
           
      *        if (flag)                  /* use all the information in the seed */
      *        {
      *          a+=randrsl[i  ]; b+=randrsl[i+1]; c+=randrsl[i+2]; d+=randrsl[i+3];
      *          e+=randrsl[i+4]; f+=randrsl[i+5]; g+=randrsl[i+6]; h+=randrsl[i+7];
      *        }
      
               If Flag = 1
                   Move i              to i2
                   Add RandRsl (i2)    to a
                   Add 1               to i2
                   Add RandRsl (i2)    to b
                   Add 1               to i2
                   Add RandRsl (i2)    to c
                   Add 1               to i2
                   Add RandRsl (i2)    to d
                   Add 1               to i2
                   Add RandRsl (i2)    to e
                   Add 1               to i2
                   Add RandRsl (i2)    to f
                   Add 1               to i2
                   Add RandRsl (i2)    to g
                   Add 1               to i2
                   Add RandRsl (i2)    to h
               End-if
     
      *        mix(a,b,c,d,e,f,g,h);

               Perform mix

      *        mm[i  ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d;
      *        mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h;

               Move i                  to i2
               Move a                  to mm (i2)
               Add 1                   to i2
               Move b                  to mm (i2)
               Add 1                   to i2
               Move c                  to mm (i2)
               Add 1                   to i2
               Move d                  to mm (i2)
               Add 1                   to i2
               Move e                  to mm (i2)
               Add 1                   to i2
               Move f                  to mm (i2)
               Add 1                   to i2
               Move g                  to mm (i2)
               Add 1                   to i2
               Move h                  to mm (i2)
           End-Perform.

      *    if (flag)
      *    {        /* do a second pass to make all of the seed affect all of mm */

           If Flag = 1
           
      *        for (i=0; i<256; i+=8) {

               Perform Varying i From 1 By 8 Until i > 256
               
      *            a+=mm[i  ]; b+=mm[i+1]; c+=mm[i+2]; d+=mm[i+3];
      *            e+=mm[i+4]; f+=mm[i+5]; g+=mm[i+6]; h+=mm[i+7];

                   Move i              to i2
                   Add mm (i2)         to a
                   Add 1               to i2
                   Add mm (i2)         to b
                   Add 1               to i2
                   Add mm (i2)         to c
                   Add 1               to i2
                   Add mm (i2)         to d
                   Add 1               to i2
                   Add mm (i2)         to e
                   Add 1               to i2
                   Add mm (i2)         to f
                   Add 1               to i2
                   Add mm (i2)         to g
                   Add 1               to i2
                   Add mm (i2)         to h
      
      *            mix(a,b,c,d,e,f,g,h);

                   Perform mix

      *            mm[i  ]=a; mm[i+1]=b; mm[i+2]=c; mm[i+3]=d;
      *            mm[i+4]=e; mm[i+5]=f; mm[i+6]=g; mm[i+7]=h;

                   Move i              to i2
                   Move a              to mm (i2)
                   Add 1               to i2
                   Move b              to mm (i2)
                   Add 1               to i2
                   Move c              to mm (i2)
                   Add 1               to i2
                   Move d              to mm (i2)
                   Add 1               to i2
                   Move e              to mm (i2)
                   Add 1               to i2
                   Move f              to mm (i2)
                   Add 1               to i2
                   Move g              to mm (i2)
                   Add 1               to i2
                   Move h              to mm (i2)

               End-Perform
           End-if.
      
      *     }
      *    }
      *    isaac();            /* fill in the first set of results */
      *    randcnt=256;        /* prepare to use the first set of results */

           Perform ISAAC.
           Move 256                    to randcnt.


      *****************************************************************
      * #define mix(a,b,c,d,e,f,g,h) \
      *       
      * { \
      *****************************************************************

       mix.
       
      *    a^=b<<11; d+=a; b+=c; \

           Move b                      to tMix.
           Call "C$LogicalShiftLeft"   Using tMix (1:), 11.
           Call "C$LogicalXor"         Using a (1:),    tMix (1:).
           Add a                       to d.
           Add c                       to b.
           
      *    b^=c>>2;  e+=b; c+=d; \

           Move c                      to tMix.
           Call "C$LogicalShiftRight"  Using tMix (1:), 2.
           Call "C$LogicalXor"         Using b (1:),    tMix (1:).
           Add b                       to e.
           Add d                       to c.
           
      *    c^=d<<8;  f+=c; d+=e; \

           Move d                      to tMix.
           Call "C$LogicalShiftLeft"   Using tMix (1:), 8.
           Call "C$LogicalXor"         Using c (1:),    tMix (1:).
           Add c                       to f.
           Add e                       to d.
           
      *    d^=e>>16; g+=d; e+=f; \

           Move e                      to tMix.
           Call "C$LogicalShiftRight"  Using tMix (1:), 16.
           Call "C$LogicalXor"         Using d (1:),    tMix (1:).
           Add d                       to g.
           Add f                       to e.
           
      *    e^=f<<10; h+=e; f+=g; \

           Move f                      to tMix.
           Call "C$LogicalShiftLeft"   Using tMix (1:), 10.
           Call "C$LogicalXor"         Using e (1:),    tMix (1:).
           Add e                       to h.
           Add g                       to f.
           
      *    f^=g>>4;  a+=f; g+=h; \

           Move g                      to tMix.
           Call "C$LogicalShiftRight"  Using tMix (1:), 4.
           Call "C$LogicalXor"         Using f (1:),    tMix (1:).
           Add f                       to a.
           Add h                       to g.
           
      *    g^=h<<8;  b+=g; h+=a; \

           Move h                      to tMix.
           Call "C$LogicalShiftLeft"   Using tMix (1:), 8.
           Call "C$LogicalXor"         Using g (1:),    tMix (1:).
           Add g                       to b.
           Add a                       to h.
           
      *    h^=a>>9;  c+=h; a+=b; \

           Move a                      to tMix.
           Call "C$LogicalShiftRight"  Using tMix (1:), 9.
           Call "C$LogicalXor"         Using h (1:),    tMix (1:).
           Add h                       to c.
           Add b                       to a.
           
      * }

       ToHex.
           Perform Varying iHex From 1 By 1 Until iHex > 4
               Move HexValueChar (iHex)    to HexWorkX
               Call "C$LogicalShiftRight"  Using HexWorkX, 4
               Add 1                       to HexWork9
               Move HexLetter (HexWork9)   to HexCharH (iHex)
               Move HexValueChar (iHex)    to HexWorkX
               Call "C$LogicalAnd"         Using HexWorkX, x"0F"
               Add 1                       to HexWork9
               Move HexLetter (HexWork9)   to HexCharL (iHex)
           End-Perform.