1 /*
2 ------------------------------------------------------------------------------
3 isaac.c: By Bob Jenkins.  My random number generator, ISAAC.
4 MODIFIED:
5   960327: Creation (addition of randinit, really)
6   970719: use context, not global variables, for internal state
7   980324: make a portable version
8   991209: modified for inclusion with GNU Backgammon by Gary Wong
9   070121: modified for inclusion with flam3 by Erik Reckase
10 ------------------------------------------------------------------------------
11 */
12 
13 #include "isaacs.h"
14 #include "isaac.h"
15 
16 #define ind(mm,x)  ((mm)[(x>>2)&(RANDSIZ-1)])
17 #define rngstep(mix,a,b,mm,m,m2,r,x) \
18 { \
19   x = *m;  \
20   a = ((a^(mix)) + *(m2++)) & 0xffffffff; \
21   *(m++) = y = (ind(mm,x) + a + b) & 0xffffffff; \
22   *(r++) = b = (ind(mm,y>>RANDSIZL) + x) & 0xffffffff; \
23 }
24 
isaac(randctx * ctx)25 void     isaac(randctx *ctx)
26 {
27    register ub4 a,b,x,y,*m,*mm,*m2,*r,*mend;
28    mm=ctx->randmem; r=ctx->randrsl;
29    a = ctx->randa; b = (ctx->randb + (++ctx->randc)) & 0xffffffff;
30    for (m = mm, mend = m2 = m+(RANDSIZ/2); m<mend; )
31    {
32       rngstep( a<<13, a, b, mm, m, m2, r, x);
33       rngstep( a>>6 , a, b, mm, m, m2, r, x);
34       rngstep( a<<2 , a, b, mm, m, m2, r, x);
35       rngstep( a>>16, a, b, mm, m, m2, r, x);
36    }
37    for (m2 = mm; m2<mend; )
38    {
39       rngstep( a<<13, a, b, mm, m, m2, r, x);
40       rngstep( a>>6 , a, b, mm, m, m2, r, x);
41       rngstep( a<<2 , a, b, mm, m, m2, r, x);
42       rngstep( a>>16, a, b, mm, m, m2, r, x);
43    }
44    ctx->randb = b; ctx->randa = a;
45 }
46 
47 
48 #define mix(a,b,c,d,e,f,g,h) \
49 { \
50    a^=b<<11; d+=a; b+=c; \
51    b^=c>>2;  e+=b; c+=d; \
52    c^=d<<8;  f+=c; d+=e; \
53    d^=e>>16; g+=d; e+=f; \
54    e^=f<<10; h+=e; f+=g; \
55    f^=g>>4;  a+=f; g+=h; \
56    g^=h<<8;  b+=g; h+=a; \
57    h^=a>>9;  c+=h; a+=b; \
58 }
59 
60 /* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */
irandinit(randctx * ctx,word flag)61 void irandinit(randctx *ctx, word     flag)
62 {
63    word i;
64    ub4 a,b,c,d,e,f,g,h;
65    ub4 *m,*r;
66    ctx->randa = ctx->randb = ctx->randc = 0;
67    m=ctx->randmem;
68    r=ctx->randrsl;
69    a=b=c=d=e=f=g=h=0x9e3779b9;  /* the golden ratio */
70 
71    for (i=0; i<4; ++i)          /* scramble it */
72    {
73      mix(a,b,c,d,e,f,g,h);
74    }
75 
76    if (flag)
77    {
78      /* initialize using the contents of r[] as the seed */
79      for (i=0; i<RANDSIZ; i+=8)
80      {
81        a+=r[i  ]; b+=r[i+1]; c+=r[i+2]; d+=r[i+3];
82        e+=r[i+4]; f+=r[i+5]; g+=r[i+6]; h+=r[i+7];
83        mix(a,b,c,d,e,f,g,h);
84        m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
85        m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
86      }
87      /* do a second pass to make all of the seed affect all of m */
88      for (i=0; i<RANDSIZ; i+=8)
89      {
90        a+=m[i  ]; b+=m[i+1]; c+=m[i+2]; d+=m[i+3];
91        e+=m[i+4]; f+=m[i+5]; g+=m[i+6]; h+=m[i+7];
92        mix(a,b,c,d,e,f,g,h);
93        m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
94        m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
95      }
96    }
97    else
98    {
99      for (i=0; i<RANDSIZ; i+=8)
100      {
101        /* fill in mm[] with messy stuff */
102        mix(a,b,c,d,e,f,g,h);
103        m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
104        m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
105      }
106    }
107 
108    isaac(ctx);            /* fill in the first set of results */
109    ctx->randcnt=RANDSIZ;  /* prepare to use the first set of results */
110 }
111