Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Examples

ccisaac.h

Go to the documentation of this file.
00001 #ifndef __ISAAC_HPP
00002 #define __ISAAC_HPP
00003 
00004 /**\file ccisaac.h
00005  * Contains the definition of QTIsaac, a C++ implementaion of Robert J
00006  * Jenkins Jr's ISAAC Random Number Generator, with additions by
00007  * Trent Apted.
00008  */
00009 #include <stdlib.h>
00010 
00011 #include <sys/time.h>
00012 
00013 #ifndef __ISAAC64
00014    typedef unsigned long int UINT32;
00015    const UINT32 GOLDEN_RATIO = UINT32(0x9e3779b9);
00016    typedef UINT32 ISAAC_INT;
00017 #else   // __ISAAC64
00018 typedef unsigned __int64 UINT64;
00019 const UINT64 GOLDEN_RATIO = UINT64(0x9e3779b97f4a7c13);
00020 typedef UINT64 ISAAC_INT;
00021 #endif  // __ISAAC64
00022 
00023 /**
00024  * C++ TEMPLATE VERSION OF Robert J Jenkins Jr's ISAAC Random Number
00025  * Generator. Ported from vanilla C to to template C++ class by Quinn
00026  * Tyler Jackson on 16-23 July 1998. <quinn@qtj.net> \n
00027  *
00028  * The function for the expected period of this random number generator,
00029  * according to Jenkins is: f(a,b) = 2**((a+b*(3+2^^a)-1) \n
00030  * \f$ f(a,b) = 2^{a+b(3+2^a)-1} \f$ \n
00031  * (where a is ALPHA and b is bitwidth) \n
00032  * \n
00033  * So, for a bitwidth of 32 and an ALPHA of 8, the expected period of
00034  * ISAAC is: \f$ 2^{8295} \f$ \n
00035  * \n
00036  * Jackson has been able to run implementations with an ALPHA as high
00037  * as 16, or \f$ 2^{2097263} \f$ \n
00038  * \note Additions by Trent Apted <tapted@it.usyd.edu.au> where indicated
00039  * \note doxygen comments by Trent Apted
00040  * \param ALPHA the 'randomness' of the generator (see above)
00041  * \param T the type used -- should be an unsigned integral type
00042  */
00043 template <int ALPHA = (8), class T = ISAAC_INT>
00044 class QTIsaac {
00045 public:
00046     typedef unsigned char byte;
00047     enum {N = (1<<ALPHA)};
00048 
00049     struct randctx {
00050         randctx() {
00051             randrsl = (T*)::malloc(N * sizeof(T));
00052             randmem = (T*)::malloc(N * sizeof(T));
00053         }
00054         ~randctx(void) {
00055             //::free((void*)randrsl);
00056             //::free((void*)randmem);
00057         }
00058         T randcnt;
00059         T* randrsl;
00060         T* randmem;
00061         T randa;
00062         T randb;
00063         T randc;
00064     };
00065 
00066     QTIsaac();
00067     QTIsaac(T a, T b = 0, T c = 0);
00068     virtual ~QTIsaac(void);
00069 
00070     T rand(void);
00071     /**
00072      * Returns a T between 0 and n-1, inclusive.\n
00073      * This function assures that all returns are evenly
00074      * distributed over the range [0, n-1], regardless of the
00075      * value of n and the range of T.
00076      * \author Trent Apted
00077      * \param n The maximum value + 1 to return
00078      * \return A number from the range [0, n-1] (all evenly distributed)
00079      */
00080     T nrand(T n);
00081     /**
00082      * Returns a double (floating point number) in the range [0.0, 1.0].
00083      * The values will be evenly distributed, but the number of discrete
00084      * values is limited to sizeof(T).
00085      * \author Trent Apted
00086      * \return A number from the range [0.0, 1.0]
00087      */
00088     double drand(void);
00089     virtual void randinit(randctx* ctx, bool bUseSeed);
00090     virtual void srand(T a = 0, T b = 0, T c = 0, T* s = NULL);
00091 
00092     T ls_a, ls_b, ls_c; ///< Last seeds (to query later)
00093 
00094 protected:
00095 
00096     virtual void isaac(randctx* ctx);
00097 
00098     T ind(T* mm, T x);
00099     void rngstep(T mix, T& a, T& b, T*& mm, T*& m, T*& m2, T*& r, T& x, T& y);
00100     virtual void shuffle(T& a, T& b, T& c, T& d, T& e, T& f, T& g, T& h);
00101 
00102 private:
00103 
00104     randctx m_rc;
00105 };
00106 
00107 template<int ALPHA, class T>
00108 QTIsaac<ALPHA,T>::QTIsaac() {
00109     struct timeval t;
00110     gettimeofday(&t, 0);
00111     srand(t.tv_sec, t.tv_usec, t.tv_sec + t.tv_usec);
00112 }
00113 
00114 template<int ALPHA, class T>
00115 QTIsaac<ALPHA,T>::QTIsaac(T a, T b, T c) {
00116     srand(a, b, c);
00117 }
00118 
00119 template<int ALPHA, class T>
00120 QTIsaac<ALPHA,T>::~QTIsaac(void) {
00121     // DO NOTHING
00122 }
00123 
00124 template<int ALPHA, class T>
00125 void QTIsaac<ALPHA,T>::srand(T a, T b, T c, T* s) {
00126     for(int i = 0; i < N; i++) {
00127         m_rc.randrsl[i] = s != NULL ? s[i] : 0;
00128     }
00129 
00130     m_rc.randa = ls_a = a;
00131     m_rc.randb = ls_b = b;
00132     m_rc.randc = ls_c = c;
00133 
00134     randinit(&m_rc, true);
00135 }
00136 
00137 template<int ALPHA, class T>
00138 inline T QTIsaac<ALPHA,T>::rand(void) {
00139     return(!m_rc.randcnt-- ? (isaac(&m_rc), m_rc.randcnt=(N-1), m_rc.randrsl[m_rc.randcnt]) : m_rc.randrsl[m_rc.randcnt]);
00140 }
00141 
00142 template<int ALPHA, class T>
00143 inline double QTIsaac<ALPHA,T>::drand(void) {
00144     return (double)rand() / (T(0) - T(1));
00145 }
00146 
00147 template<int ALPHA, class T>
00148 inline T QTIsaac<ALPHA,T>::nrand(T max) {
00149     T ret;
00150     T csize = (T(0) - T(1)) / max;
00151     do {
00152         ret = rand() / csize;
00153         //ret is (0 -> max)
00154     } while (ret >= max);
00155     return ret;
00156 }
00157 
00158 template<int ALPHA, class T>
00159 void QTIsaac<ALPHA,T>::randinit(randctx* ctx, bool bUseSeed) {
00160     T a,b,c,d,e,f,g,h;
00161     int i;
00162 
00163     a = b = c = d = e = f = g = h = GOLDEN_RATIO;
00164 
00165     T* m = (ctx->randmem);
00166     T* r = (ctx->randrsl);
00167    
00168     if(!bUseSeed) {
00169         ctx->randa = 0;
00170         ctx->randb = 0;
00171         ctx->randc = 0;
00172     }
00173 
00174     // scramble it
00175     for(i=0; i < 4; ++i) {
00176         shuffle(a,b,c,d,e,f,g,h);
00177     }
00178 
00179     if(bUseSeed) {
00180         // initialize using the contents of r[] as the seed
00181 
00182         for(i=0; i < N; i+=8) {
00183             a+=r[i  ]; b+=r[i+1]; c+=r[i+2]; d+=r[i+3];
00184             e+=r[i+4]; f+=r[i+5]; g+=r[i+6]; h+=r[i+7];
00185 
00186             shuffle(a,b,c,d,e,f,g,h);
00187 
00188             m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
00189             m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
00190         }
00191 
00192         //do a second pass to make all of the seed affect all of m
00193 
00194         for(i=0; i < N; i += 8) {
00195             a+=m[i  ]; b+=m[i+1]; c+=m[i+2]; d+=m[i+3];
00196             e+=m[i+4]; f+=m[i+5]; g+=m[i+6]; h+=m[i+7];
00197 
00198             shuffle(a,b,c,d,e,f,g,h);
00199 
00200             m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
00201             m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
00202         }
00203     } else {
00204         // fill in mm[] with messy stuff
00205 
00206         shuffle(a,b,c,d,e,f,g,h);
00207 
00208         m[i  ]=a; m[i+1]=b; m[i+2]=c; m[i+3]=d;
00209         m[i+4]=e; m[i+5]=f; m[i+6]=g; m[i+7]=h;
00210     }
00211 
00212     isaac(ctx);         // fill in the first set of results
00213     ctx->randcnt = N;   // prepare to use the first set of results
00214 }
00215 
00216 template<int ALPHA, class T>
00217 inline T QTIsaac<ALPHA,T>::ind(T* mm, T x) {
00218 #ifndef __ISAAC64
00219     return (*(T*)((byte*)(mm) + ((x) & ((N-1)<<2))));
00220 #else   // __ISAAC64
00221     return (*(T*)((byte*)(mm) + ((x) & ((N-1)<<3))));
00222 #endif  // __ISAAC64
00223 }
00224 
00225 template<int ALPHA, class T>
00226 inline void QTIsaac<ALPHA,T>::rngstep(T mix, T& a, T& b, T*& mm, T*& m, T*& m2, T*& r, T& x, T& y) {
00227     x = *m;
00228     a = (a^(mix)) + *(m2++);
00229     *(m++) = y = ind(mm,x) + a + b;
00230     *(r++) = b = ind(mm,y>>ALPHA) + x;
00231 }
00232 
00233 template<int ALPHA, class T>
00234 void QTIsaac<ALPHA,T>::shuffle(T& a, T& b, T& c, T& d, T& e, T& f, T& g, T& h) {
00235 #ifndef __ISAAC64
00236     a^=b<<11; d+=a; b+=c;
00237     b^=c>>2;  e+=b; c+=d;
00238     c^=d<<8;  f+=c; d+=e;
00239     d^=e>>16; g+=d; e+=f;
00240     e^=f<<10; h+=e; f+=g;
00241     f^=g>>4;  a+=f; g+=h;
00242     g^=h<<8;  b+=g; h+=a;
00243     h^=a>>9;  c+=h; a+=b;
00244 #else // __ISAAC64
00245     a-=e; f^=h>>9;  h+=a;
00246     b-=f; g^=a<<9;  a+=b;
00247     c-=g; h^=b>>23; b+=c;
00248     d-=h; a^=c<<15; c+=d;
00249     e-=a; b^=d>>14; d+=e;
00250     f-=b; c^=e<<20; e+=f;
00251     g-=c; d^=f>>17; f+=g;
00252     h-=d; e^=g<<14; g+=h;
00253 #endif // __ISAAC64
00254 }
00255 
00256 template<int ALPHA, class T>
00257 void QTIsaac<ALPHA,T>::isaac(randctx* ctx) {
00258     T x,y;
00259 
00260     T* mm = ctx->randmem;
00261     T* r  = ctx->randrsl;
00262 
00263     T a = (ctx->randa);
00264     T b = (ctx->randb + (++ctx->randc));
00265 
00266     T* m    = mm;
00267     T* m2   = (m+(N/2));
00268     T* mend = m2;
00269 
00270     for(; m<mend; ) {
00271 #ifndef __ISAAC64
00272         rngstep((a<<13), a, b, mm, m, m2, r, x, y);
00273         rngstep((a>>6) , a, b, mm, m, m2, r, x, y);
00274         rngstep((a<<2) , a, b, mm, m, m2, r, x, y);
00275         rngstep((a>>16), a, b, mm, m, m2, r, x, y);
00276 #else   // __ISAAC64
00277         rngstep(~(a^(a<<21)), a, b, mm, m, m2, r, x, y);
00278         rngstep(  a^(a>>5)  , a, b, mm, m, m2, r, x, y);
00279         rngstep(  a^(a<<12) , a, b, mm, m, m2, r, x, y);
00280         rngstep(  a^(a>>33) , a, b, mm, m, m2, r, x, y);
00281 #endif  // __ISAAC64
00282     }
00283 
00284     m2 = mm;
00285 
00286     for(; m2<mend; ) {
00287 #ifndef __ISAAC64
00288         rngstep((a<<13), a, b, mm, m, m2, r, x, y);
00289         rngstep((a>>6) , a, b, mm, m, m2, r, x, y);
00290         rngstep((a<<2) , a, b, mm, m, m2, r, x, y);
00291         rngstep((a>>16), a, b, mm, m, m2, r, x, y);
00292 #else   // __ISAAC64
00293         rngstep(~(a^(a<<21)), a, b, mm, m, m2, r, x, y);
00294         rngstep(  a^(a>>5)  , a, b, mm, m, m2, r, x, y);
00295         rngstep(  a^(a<<12) , a, b, mm, m, m2, r, x, y);
00296         rngstep(  a^(a>>33) , a, b, mm, m, m2, r, x, y);
00297 #endif  // __ISAAC64
00298     }
00299 
00300     ctx->randb = b;
00301     ctx->randa = a;
00302 }
00303 
00304 #endif // __ISAAC_HPP

Generated on Fri Oct 3 18:41:20 2003 for taptedDevTools by doxygen 1.3.4