1/*
2------------------------------------------------------------------------------
3rand.c: By Bob Jenkins.  My random number generator, ISAAC.  Public Domain
4MODIFIED:
5  960327: Creation (addition of randinit, really)
6  970719: use context, not global variables, for internal state
7  980324: make a portable version
8  010626: Note this is public domain
9------------------------------------------------------------------------------
10*/
11#ifndef STANDARD
12#include "standard.h"
13#endif
14#ifndef RAND
15#include "rand.h"
16#endif
17
18
19#define ind(mm,x)  ((mm)[(x>>2)&(RANDSIZ-1)])
20#define rngstep(mix,a,b,mm,m,m2,r,x) \
21{ \
22  x = *m;  \
23  a = ((a^(mix)) + *(m2++)) & 0xffffffff; \
24  *(m++) = y = (ind(mm,x) + a + b) & 0xffffffff; \
25  *(r++) = b = (ind(mm,y>>RANDSIZL) + x) & 0xffffffff; \
26}
27
28void     isaac(ctx)
29randctx *ctx;
30{
31   register ub4 a,b,x,y,*m,*mm,*m2,*r,*mend;
32   mm=ctx->randmem; r=ctx->randrsl;
33   a = ctx->randa; b = (ctx->randb + (++ctx->randc)) & 0xffffffff;
34   for (m = mm, mend = m2 = m+(RANDSIZ/2); m<mend; )
35   {
36      rngstep( a<<13, a, b, mm, m, m2, r, x);
37      rngstep( a>>6 , a, b, mm, m, m2, r, x);
38      rngstep( a<<2 , a, b, mm, m, m2, r, x);
39      rngstep( a>>16, a, b, mm, m, m2, r, x);
40   }
41   for (m2 = mm; m2<mend; )
42   {
43      rngstep( a<<13, a, b, mm, m, m2, r, x);
44      rngstep( a>>6 , a, b, mm, m, m2, r, x);
45      rngstep( a<<2 , a, b, mm, m, m2, r, x);
46      rngstep( a>>16, a, b, mm, m, m2, r, x);
47   }
48   ctx->randb = b; ctx->randa = a;
49}
50
51
52#define mix(a,b,c,d,e,f,g,h) \
53{ \
54   a^=b<<11; d+=a; b+=c; \
55   b^=c>>2;  e+=b; c+=d; \
56   c^=d<<8;  f+=c; d+=e; \
57   d^=e>>16; g+=d; e+=f; \
58   e^=f<<10; h+=e; f+=g; \
59   f^=g>>4;  a+=f; g+=h; \
60   g^=h<<8;  b+=g; h+=a; \
61   h^=a>>9;  c+=h; a+=b; \
62}
63
64/* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */
65void randinit(ctx, flag)
66randctx *ctx;
67word     flag;
68{
69   word i;
70   ub4 a,b,c,d,e,f,g,h;
71   ub4 *m,*r;
72   ctx->randa = ctx->randb = ctx->randc = 0;
73   m=ctx->randmem;
74   r=ctx->randrsl;
75   a=b=c=d=e=f=g=h=0x9e3779b9;  /* the golden ratio */
76
77   for (i=0; i<4; ++i)          /* scramble it */
78   {
79     mix(a,b,c,d,e,f,g,h);
80   }
81
82   if (flag)
83   {
84     /* initialize using the contents of r[] as the seed */
85     for (i=0; i<RANDSIZ; i+=8)
86     {
87       a+=r[i  ]; b+=r[i+1]; c+=r[i+2]; d+=r[i+3];
88       e+=r[i+4]; f+=r[i+5]; g+=r[i+6]; h+=r[i+7];
89       mix(a,b,c,d,e,f,g,h);
90       m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
91       m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
92     }
93     /* do a second pass to make all of the seed affect all of m */
94     for (i=0; i<RANDSIZ; i+=8)
95     {
96       a+=m[i  ]; b+=m[i+1]; c+=m[i+2]; d+=m[i+3];
97       e+=m[i+4]; f+=m[i+5]; g+=m[i+6]; h+=m[i+7];
98       mix(a,b,c,d,e,f,g,h);
99       m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
100       m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
101     }
102   }
103   else
104   {
105     for (i=0; i<RANDSIZ; i+=8)
106     {
107       /* fill in mm[] with messy stuff */
108       mix(a,b,c,d,e,f,g,h);
109       m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
110       m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
111     }
112   }
113
114   isaac(ctx);            /* fill in the first set of results */
115   ctx->randcnt=RANDSIZ;  /* prepare to use the first set of results */
116}
117
118
119#ifdef NEVER
120int main()
121{
122  ub4 i,j;
123  randctx ctx;
124  ctx.randa=ctx.randb=ctx.randc=(ub4)0;
125  for (i=0; i<256; ++i) ctx.randrsl[i]=(ub4)0;
126  randinit(&ctx, TRUE);
127  for (i=0; i<2; ++i)
128  {
129    isaac(&ctx);
130    for (j=0; j<256; ++j)
131    {
132      printf("%.8lx",ctx.randrsl[j]);
133      if ((j&7)==7) printf("\n");
134    }
135  }
136}
137#endif
138