Eigene Dateien/FlowVis/src/mersenne.cpp

Go to the documentation of this file.
00001 /************************** MERSENNE.CPP ******************** AgF 2007-08-01 *
00002 *  Random Number generator 'Mersenne Twister'                                *
00003 *                                                                            *
00004 *  This random number generator is described in the article by               *
00005 *  M. Matsumoto & T. Nishimura, in:                                          *
00006 *  ACM Transactions on Modeling and Computer Simulation,                     *
00007 *  vol. 8, no. 1, 1998, pp. 3-30.                                            *
00008 *  Details on the initialization scheme can be found at                      *
00009 *  http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html                  *
00010 *                                                                            *
00011 *  Experts consider this an excellent random number generator.               *
00012 *                                                                            *
00013 *  © 2001 - 2007 A. Fog. Published under the GNU General Public License      *
00014 *  (www.gnu.org/copyleft/gpl.html) with the further restriction that it      *
00015 *  cannot be used for gambling applications.                                 *
00016 *****************************************************************************/
00017 
00018 #include "randomc.h"
00019 
00020 void CRandomMersenne::Init0(uint32 seed) {
00021    // Detect computer architecture
00022    union {double f; uint32 i[2];} convert;
00023    convert.f = 1.0;
00024    if (convert.i[1] == 0x3FF00000) Architecture = LITTLE_ENDIAN1;
00025    else if (convert.i[0] == 0x3FF00000) Architecture = BIG_ENDIAN1;
00026    else Architecture = NONIEEE;
00027 
00028    // Seed generator
00029    mt[0]= seed;
00030    for (mti=1; mti < MERS_N; mti++) {
00031       mt[mti] = (1812433253UL * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
00032    }
00033 }
00034 
00035 void CRandomMersenne::RandomInit(uint32 seed) {
00036    // Initialize and seed
00037    Init0(seed);
00038 
00039    // Randomize some more
00040    for (int i = 0; i < 37; i++) BRandom();
00041 }
00042 
00043 
00044 void CRandomMersenne::RandomInitByArray(uint32 seeds[], int length) {
00045    // Seed by more than 32 bits
00046    int i, j, k;
00047 
00048    // Initialize
00049    Init0(19650218);
00050 
00051    if (length <= 0) return;
00052 
00053    // Randomize mt[] using whole seeds[] array
00054    i = 1;  j = 0;
00055    k = (MERS_N > length ? MERS_N : length);
00056    for (; k; k--) {
00057       mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + seeds[j] + j;
00058       i++; j++;
00059       if (i >= MERS_N) {mt[0] = mt[MERS_N-1]; i=1;}
00060       if (j >= length) j=0;}
00061    for (k = MERS_N-1; k; k--) {
00062       mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i;
00063       if (++i >= MERS_N) {mt[0] = mt[MERS_N-1]; i=1;}}
00064    mt[0] = 0x80000000UL;  // MSB is 1; assuring non-zero initial array
00065 
00066    // Randomize some more
00067    mti = 0;
00068    for (int i = 0; i <= MERS_N; i++) BRandom();
00069 }
00070 
00071 
00072 uint32 CRandomMersenne::BRandom() {
00073    // Generate 32 random bits
00074    uint32 y;
00075 
00076    if (mti >= MERS_N) {
00077       // Generate MERS_N words at one time
00078       const uint32 LOWER_MASK = (1LU << MERS_R) - 1;       // Lower MERS_R bits
00079       const uint32 UPPER_MASK = 0xFFFFFFFF << MERS_R;      // Upper (32 - MERS_R) bits
00080       static const uint32 mag01[2] = {0, MERS_A};
00081 
00082       int kk;
00083       for (kk=0; kk < MERS_N-MERS_M; kk++) {    
00084          y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
00085          mt[kk] = mt[kk+MERS_M] ^ (y >> 1) ^ mag01[y & 1];}
00086 
00087       for (; kk < MERS_N-1; kk++) {    
00088          y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
00089          mt[kk] = mt[kk+(MERS_M-MERS_N)] ^ (y >> 1) ^ mag01[y & 1];}      
00090 
00091       y = (mt[MERS_N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
00092       mt[MERS_N-1] = mt[MERS_M-1] ^ (y >> 1) ^ mag01[y & 1];
00093       mti = 0;
00094    }
00095 
00096    y = mt[mti++];
00097 
00098 #if 1
00099    // Tempering (May be omitted):
00100    y ^=  y >> MERS_U;
00101    y ^= (y << MERS_S) & MERS_B;
00102    y ^= (y << MERS_T) & MERS_C;
00103    y ^=  y >> MERS_L;
00104 #endif
00105 
00106    return y;
00107 }
00108 
00109 
00110 double CRandomMersenne::Random() {
00111    // Output random float number in the interval 0 <= x < 1
00112    union {double f; uint32 i[2];} convert;
00113    uint32 r = BRandom();               // Get 32 random bits
00114    // The fastest way to convert random bits to floating point is as follows:
00115    // Set the binary exponent of a floating point number to 1+bias and set
00116    // the mantissa to random bits. This will give a random number in the 
00117    // interval [1,2). Then subtract 1.0 to get a random number in the interval
00118    // [0,1). This procedure requires that we know how floating point numbers
00119    // are stored. The storing method is tested in function RandomInit and saved 
00120    // in the variable Architecture.
00121 
00122    // This shortcut allows the compiler to optimize away the following switch
00123    // statement for the most common architectures:
00124 #if defined(_M_IX86) || defined(_M_X64) || defined(__LITTLE_ENDIAN__)
00125    Architecture = LITTLE_ENDIAN1;
00126 #elif defined(__BIG_ENDIAN__)
00127    Architecture = BIG_ENDIAN1;
00128 #endif
00129 
00130    switch (Architecture) {
00131    case LITTLE_ENDIAN1:
00132       convert.i[0] =  r << 20;
00133       convert.i[1] = (r >> 12) | 0x3FF00000;
00134       return convert.f - 1.0;
00135    case BIG_ENDIAN1:
00136       convert.i[1] =  r << 20;
00137       convert.i[0] = (r >> 12) | 0x3FF00000;
00138       return convert.f - 1.0;
00139    case NONIEEE: default: ;
00140    } 
00141    // This somewhat slower method works for all architectures, including 
00142    // non-IEEE floating point representation:
00143    return (double)r * (1./((double)(uint32)(-1L)+1.));
00144 }
00145 
00146 
00147 int CRandomMersenne::IRandom(int min, int max) {
00148    // Output random integer in the interval min <= x <= max
00149    // Relative error on frequencies < 2^-32
00150    if (max <= min) {
00151       if (max == min) return min; else return 0x80000000;
00152    }
00153    // Multiply interval with random and truncate
00154    int r = int((max - min + 1) * Random()) + min; 
00155    if (r > max) r = max;
00156    return r;
00157 }
00158 
00159 
00160 int CRandomMersenne::IRandomX(int min, int max) {
00161    // Output random integer in the interval min <= x <= max
00162    // Each output value has exactly the same probability.
00163    // This is obtained by rejecting certain bit values so that the number
00164    // of possible bit values is divisible by the interval length
00165    if (max <= min) {
00166       if (max == min) return min; else return 0x80000000;
00167    }
00168 #ifdef  INT64_DEFINED
00169    // 64 bit integers available. Use multiply and shift method
00170    uint32 interval;                    // Length of interval
00171    uint64 longran;                     // Random bits * interval
00172    uint32 iran;                        // Longran / 2^32
00173    uint32 remainder;                   // Longran % 2^32
00174 
00175    interval = uint32(max - min + 1);
00176    if (interval != LastInterval) {
00177       // Interval length has changed. Must calculate rejection limit
00178       // Reject when remainder = 2^32 / interval * interval
00179       // RLimit will be 0 if interval is a power of 2. No rejection then
00180       RLimit = uint32(((uint64)1 << 32) / interval) * interval - 1;
00181       LastInterval = interval;
00182    }
00183    do { // Rejection loop
00184       longran  = (uint64)BRandom() * interval;
00185       iran = (uint32)(longran >> 32);
00186       remainder = (uint32)longran;
00187    } while (remainder > RLimit);
00188    // Convert back to signed and return result
00189    return (int32)iran + min;
00190 
00191 #else
00192    // 64 bit integers not available. Use modulo method
00193    uint32 interval;                    // Length of interval
00194    uint32 bran;                        // Random bits
00195    uint32 iran;                        // bran / interval
00196    uint32 remainder;                   // bran % interval
00197 
00198    interval = uint32(max - min + 1);
00199    if (interval != LastInterval) {
00200       // Interval length has changed. Must calculate rejection limit
00201       // Reject when iran = 2^32 / interval
00202       // We can't make 2^32 so we use 2^32-1 and correct afterwards
00203       RLimit = (uint32)0xFFFFFFFF / interval;
00204       if ((uint32)0xFFFFFFFF % interval == interval - 1) RLimit++;
00205    }
00206    do { // Rejection loop
00207       bran = BRandom();
00208       iran = bran / interval;
00209       remainder = bran % interval;
00210    } while (iran >= RLimit);
00211    // Convert back to signed and return result
00212    return (int32)remainder + min;
00213 
00214 #endif
00215 }

Generated on Mon Jan 21 01:15:15 2008 for FlowVis by  doxygen 1.5.4