#ifndef __ISAAC_HPP
#define __ISAAC_HPP
#include <stdlib.h>
/*
C++ TEMPLATE VERSION OF Robert J. Jenkins Jr.'s
ISAAC Random Number Generator.
Ported from vanilla C to to template C++ class
by Quinn Tyler Jackson on 16-23 July 1998.
qjackson@wave.home.com
The function for the expected period of this
random number generator, according to Jenkins is:
f(a,b) = 2**((a+b*(3+2^^a)-1)
(where a is ALPHA and b is bitwidth)
So, for a bitwidth of 32 and an ALPHA of 8,
the expected period of ISAAC is:
2^^(8+32*(3+2^^8)-1) = 2^^8295
Jackson has been able to run implementations
with an ALPHA as high as 16, or
2^^2097263
*/
#ifndef __ISAAC64
typedef unsigned long int UINT32;
const UINT32 GOLDEN_RATIO = UINT32(0x9e3779b9);
typedef UINT32 ISAAC_INT;
#else // __ISAAC64
typedef unsigned __int64 UINT64;
const UINT64 GOLDEN_RATIO = UINT64(0x9e3779b97f4a7c13);
typedef UINT64 ISAAC_INT;
#endif // __ISAAC64
template <int ALPHA = (8), class T = ISAAC_INT>
class QTIsaac
{
// friend int main (void);
public:
typedef unsigned char byte;
struct randctx
{
randctx(void)
{
randrsl = (T*)::malloc(N * sizeof(T));
randmem = (T*)::malloc(N * sizeof(T));
}
~randctx(void)
{
::free((void*)randrsl);
::free((void*)randmem);
}
T randcnt;
T* randrsl;
T* randmem;
T randa;
T randb;
T randc;
};
QTIsaac(T a = 0, T b = 0, T c = 0);
virtual ~QTIsaac(void);
T rand(void);
virtual void randinit(randctx* ctx, bool bUseSeed);
virtual void srand(T a = 0, T b = 0, T c = 0, T* s = NULL);
enum {N = (1<<ALPHA)};
protected:
virtual void isaac(randctx* ctx);
T ind(T* mm, T x);
void rngstep(T mix, T& a, T& b, T*& mm, T*& m, T*& m2, T*& r, T& x, T& y);
virtual void shuffle(T& a, T& b, T& c, T& d, T& e, T& f, T& g, T& h);
private:
randctx m_rc;
};
template<int ALPHA, class T>
QTIsaac<ALPHA,T>::QTIsaac(T a, T b, T c)
{
srand();
}
template<int ALPHA, class T>
QTIsaac<ALPHA,T>::~QTIsaac(void)
{
// DO NOTHING
}
template<int ALPHA, class T>
void QTIsaac<ALPHA,T>::srand(T a, T b, T c, T* s)
{
for(int i = 0; i < N; i++)
{
m_rc.randrsl[i] = s != NULL ? s[i] : 0;
}
m_rc.randa = a;
m_rc.randb = b;
m_rc.randc = c;
randinit(&m_rc, true);
}
template<int ALPHA, class T>
inline T QTIsaac<ALPHA,T>::rand(void)
{
return(!m_rc.randcnt-- ? (isaac(&m_rc), m_rc.randcnt=(N-1), m_rc.randrsl[m_rc.randcnt]) : m_rc.randrsl[m_rc.randcnt]);
}
template<int ALPHA, class T>
void QTIsaac<ALPHA,T>::randinit(randctx* ctx, bool bUseSeed)
{
T a,b,c,d,e,f,g,h;
a = b = c = d = e = f = g = h = (T) GOLDEN_RATIO;
T* m = (ctx->randmem);
T* r = (ctx->randrsl);
if(!bUseSeed)
{
ctx->randa = 0;
ctx->randb = 0;
ctx->randc = 0;
}
// scramble it
for(int i=0; i < 4; ++i)
{
shuffle(a,b,c,d,e,f,g,h);
}
if(bUseSeed)
{
// initialize using the contents of r[] as the seed
for(int i=0; i < N; i+=8)
{
a+=r[i ]; b+=r[i+1]; c+=r[i+2]; d+=r[i+3];
e+=r[i+4]; f+=r[i+5]; g+=r[i+6]; h+=r[i+7];
shuffle(a,b,c,d,e,f,g,h);
m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
}
//do a second pass to make all of the seed affect all of m
for(int i=0; i < N; i += 8)
{
a+=m[i ]; b+=m[i+1]; c+=m[i+2]; d+=m[i+3];
e+=m[i+4]; f+=m[i+5]; g+=m[i+6]; h+=m[i+7];
shuffle(a,b,c,d,e,f,g,h);
m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
}
}
else
{
// fill in mm[] with messy stuff
for(int i=0; i < N; i += 8)
{
shuffle(a,b,c,d,e,f,g,h);
m[i ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
}
}
isaac(ctx); // fill in the first set of results
ctx->randcnt = N; // prepare to use the first set of results
}
template<int ALPHA, class T>
inline T QTIsaac<ALPHA,T>::ind(T* mm, T x)
{
#ifndef __ISAAC64
return (*(T*)((byte*)(mm) + ((x) & ((N-1)<<2))));
#else // __ISAAC64
return (*(T*)((byte*)(mm) + ((x) & ((N-1)<<3))));
#endif // __ISAAC64
}
template<int ALPHA, class T>
inline void QTIsaac<ALPHA,T>::rngstep(T mix, T& a, T& b, T*& mm, T*& m, T*& m2, T*& r, T& x, T& y)
{
x = *m;
a = (a^(mix)) + *(m2++);
*(m++) = y = ind(mm,x) + a + b;
*(r++) = b = ind(mm,y>>ALPHA) + x;
}
template<int ALPHA, class T>
void QTIsaac<ALPHA,T>::shuffle(T& a, T& b, T& c, T& d, T& e, T& f, T& g, T& h)
{
#ifndef __ISAAC64
a^=b<<11; d+=a; b+=c;
b^=c>>2; e+=b; c+=d;
c^=d<<8; f+=c; d+=e;
d^=e>>16; g+=d; e+=f;
e^=f<<10; h+=e; f+=g;
f^=g>>4; a+=f; g+=h;
g^=h<<8; b+=g; h+=a;
h^=a>>9; c+=h; a+=b;
#else // __ISAAC64
a-=e; f^=h>>9; h+=a;
b-=f; g^=a<<9; a+=b;
c-=g; h^=b>>23; b+=c;
d-=h; a^=c<<15; c+=d;
e-=a; b^=d>>14; d+=e;
f-=b; c^=e<<20; e+=f;
g-=c; d^=f>>17; f+=g;
h-=d; e^=g<<14; g+=h;
#endif // __ISAAC64
}
template<int ALPHA, class T>
void QTIsaac<ALPHA,T>::isaac(randctx* ctx)
{
T x,y;
T* mm = ctx->randmem;
T* r = ctx->randrsl;
T a = (ctx->randa);
T b = (ctx->randb + (++ctx->randc));
T* m = mm;
T* m2 = (m+(N/2));
T* mend = m2;
for(; m<mend; )
{
#ifndef __ISAAC64
rngstep((a<<13), a, b, mm, m, m2, r, x, y);
rngstep((a>>6) , a, b, mm, m, m2, r, x, y);
rngstep((a<<2) , a, b, mm, m, m2, r, x, y);
rngstep((a>>16), a, b, mm, m, m2, r, x, y);
#else // __ISAAC64
rngstep(~(a^(a<<21)), a, b, mm, m, m2, r, x, y);
rngstep( a^(a>>5) , a, b, mm, m, m2, r, x, y);
rngstep( a^(a<<12) , a, b, mm, m, m2, r, x, y);
rngstep( a^(a>>33) , a, b, mm, m, m2, r, x, y);
#endif // __ISAAC64
}
m2 = mm;
for(; m2<mend; )
{
#ifndef __ISAAC64
rngstep((a<<13), a, b, mm, m, m2, r, x, y);
rngstep((a>>6) , a, b, mm, m, m2, r, x, y);
rngstep((a<<2) , a, b, mm, m, m2, r, x, y);
rngstep((a>>16), a, b, mm, m, m2, r, x, y);
#else // __ISAAC64
rngstep(~(a^(a<<21)), a, b, mm, m, m2, r, x, y);
rngstep( a^(a>>5) , a, b, mm, m, m2, r, x, y);
rngstep( a^(a<<12) , a, b, mm, m, m2, r, x, y);
rngstep( a^(a>>33) , a, b, mm, m, m2, r, x, y);
#endif // __ISAAC64
}
ctx->randb = b;
ctx->randa = a;
}
#endif // __ISAAC_HPP