/*- * Copyright 2005 Guram Dukashvili * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ //--------------------------------------------------------------------------- #ifndef RandomizerH #define RandomizerH //--------------------------------------------------------------------------- namespace ksys { //--------------------------------------------------------------------------- /* 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. quinn@qtj.net 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 */ template class QTIsaac { public: enum { N = (1< inline QTIsaac::QTIsaac(T a, T b, T c) { srand(a, b, c); } template inline QTIsaac::~QTIsaac(void) { /* DO NOTHING */ } template #ifndef __BCPLUSPLUS__ inline #endif void QTIsaac::srand(T a, T b, T c, T* s) { for( intptr_t 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 inline T QTIsaac::rand(void) { return ( !m_rc.randcnt-- ? (isaac(&m_rc), m_rc.randcnt = N - 1, m_rc.randrsl[(unsigned) m_rc.randcnt] ) : m_rc.randrsl[(unsigned) m_rc.randcnt] ); } template #ifndef __BCPLUSPLUS__ inline #endif void QTIsaac::randinit(randctx * ctx, bool bUseSeed) { T a,b,c,d,e,f,g,h; a = b = c = d = e = f = g = h = UINT64_C(0x9e3779b97f4a7c13); T * m = (ctx->randmem); T * r = (ctx->randrsl); if( !bUseSeed ){ ctx->randa = 0; ctx->randb = 0; ctx->randc = 0; } intptr_t i; // scramble it for( 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( 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( 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 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 inline T QTIsaac::ind(T * mm, T x) { return *(T *) ( (unsigned char *) mm + unsigned(x & ((N - 1) << 3)) ); } template inline void QTIsaac::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 inline void QTIsaac::shuffle(T& a, T& b, T& c, T& d, T& e, T& f, T& g, T& h) { 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; } template #ifndef __BCPLUSPLUS__ inline #endif void QTIsaac::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>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); } m2 = mm; for(; m2>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); } ctx->randb = b; ctx->randa = a; } //--------------------------------------------------------------------------- class Randomizer : public QTIsaac<> { typedef QTIsaac<> Inherited; private: public: ~Randomizer(); Randomizer(); Randomizer & randomize(); Randomizer & srand(uint64_t a); uint64_t random(uint64_t m = ~UINT64_C(0)); uint64_t random2(uint64_t m = UINT64_C(0)); uint64_t zrandom(); }; //--------------------------------------------------------------------------- inline Randomizer::~Randomizer() { } //--------------------------------------------------------------------------- inline Randomizer::Randomizer() { randomize(); } //--------------------------------------------------------------------------- inline uint64_t Randomizer::random2(uint64_t m) { return rand() & (m - 1); } //--------------------------------------------------------------------------- } //--------------------------------------------------------------------------- #endif