ThreeB 1.1
mersenne.cpp
Go to the documentation of this file.
00001 /**************************   mersenne.cpp   **********************************
00002 * Author:        Agner Fog
00003 * Date created:  2001
00004 * Last modified: 2008-11-16
00005 * Project:       randomc.h
00006 * Platform:      Any C++
00007 * Description:
00008 * Random Number generator of type 'Mersenne Twister'
00009 *
00010 * This random number generator is described in the article by
00011 * M. Matsumoto & T. Nishimura, in:
00012 * ACM Transactions on Modeling and Computer Simulation,
00013 * vol. 8, no. 1, 1998, pp. 3-30.
00014 * Details on the initialization scheme can be found at
00015 * http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html
00016 *
00017 * Further documentation:
00018 * The file ran-instructions.pdf contains further documentation and 
00019 * instructions.
00020 *
00021 * Copyright 2001-2008 by Agner Fog. 
00022 * GNU General Public License http://www.gnu.org/licenses/gpl.html
00023 *******************************************************************************/
00024 
00025 #include "randomc.h"
00026 
00027 void CRandomMersenne::Init0(int seed) {
00028    // Seed generator
00029    const uint32_t factor = 1812433253UL;
00030    mt[0]= seed;
00031    for (mti=1; mti < MERS_N; mti++) {
00032       mt[mti] = (factor * (mt[mti-1] ^ (mt[mti-1] >> 30)) + mti);
00033    }
00034 }
00035 
00036 void CRandomMersenne::RandomInit(int seed) {
00037    // Initialize and seed
00038    Init0(seed);
00039 
00040    // Randomize some more
00041    for (int i = 0; i < 37; i++) BRandom();
00042 }
00043 
00044 
00045 void CRandomMersenne::RandomInitByArray(int const seeds[], int NumSeeds) {
00046    // Seed by more than 32 bits
00047    int i, j, k;
00048 
00049    // Initialize
00050    Init0(19650218);
00051 
00052    if (NumSeeds <= 0) return;
00053 
00054    // Randomize mt[] using whole seeds[] array
00055    i = 1;  j = 0;
00056    k = (MERS_N > NumSeeds ? MERS_N : NumSeeds);
00057    for (; k; k--) {
00058       mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + (uint32_t)seeds[j] + j;
00059       i++; j++;
00060       if (i >= MERS_N) {mt[0] = mt[MERS_N-1]; i=1;}
00061       if (j >= NumSeeds) j=0;}
00062    for (k = MERS_N-1; k; k--) {
00063       mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941UL)) - i;
00064       if (++i >= MERS_N) {mt[0] = mt[MERS_N-1]; i=1;}}
00065    mt[0] = 0x80000000UL;  // MSB is 1; assuring non-zero initial array
00066 
00067    // Randomize some more
00068    mti = 0;
00069    for (int i = 0; i <= MERS_N; i++) BRandom();
00070 }
00071 
00072 
00073 uint32_t CRandomMersenne::BRandom() {
00074    // Generate 32 random bits
00075    uint32_t y;
00076 
00077    if (mti >= MERS_N) {
00078       // Generate MERS_N words at one time
00079       const uint32_t LOWER_MASK = (1LU << MERS_R) - 1;       // Lower MERS_R bits
00080       const uint32_t UPPER_MASK = 0xFFFFFFFF << MERS_R;      // Upper (32 - MERS_R) bits
00081       static const uint32_t mag01[2] = {0, MERS_A};
00082 
00083       int kk;
00084       for (kk=0; kk < MERS_N-MERS_M; kk++) {    
00085          y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
00086          mt[kk] = mt[kk+MERS_M] ^ (y >> 1) ^ mag01[y & 1];}
00087 
00088       for (; kk < MERS_N-1; kk++) {    
00089          y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
00090          mt[kk] = mt[kk+(MERS_M-MERS_N)] ^ (y >> 1) ^ mag01[y & 1];}      
00091 
00092       y = (mt[MERS_N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
00093       mt[MERS_N-1] = mt[MERS_M-1] ^ (y >> 1) ^ mag01[y & 1];
00094       mti = 0;
00095    }
00096    y = mt[mti++];
00097 
00098    // Tempering (May be omitted):
00099    y ^=  y >> MERS_U;
00100    y ^= (y << MERS_S) & MERS_B;
00101    y ^= (y << MERS_T) & MERS_C;
00102    y ^=  y >> MERS_L;
00103 
00104    return y;
00105 }
00106 
00107 
00108 double CRandomMersenne::Random() {
00109    // Output random float number in the interval 0 <= x < 1
00110    // Multiply by 2^(-32)
00111    return (double)BRandom() * (1./(65536.*65536.));
00112 }
00113 
00114 
00115 int CRandomMersenne::IRandom(int min, int max) {
00116    // Output random integer in the interval min <= x <= max
00117    // Relative error on frequencies < 2^-32
00118    if (max <= min) {
00119       if (max == min) return min; else return 0x80000000;
00120    }
00121    // Multiply interval with random and truncate
00122    int r = int((double)(uint32_t)(max - min + 1) * Random() + min); 
00123    if (r > max) r = max;
00124    return r;
00125 }
00126 
00127 
00128 int CRandomMersenne::IRandomX(int min, int max) {
00129    // Output random integer in the interval min <= x <= max
00130    // Each output value has exactly the same probability.
00131    // This is obtained by rejecting certain bit values so that the number
00132    // of possible bit values is divisible by the interval length
00133    if (max <= min) {
00134       if (max == min) return min; else return 0x80000000;
00135    }
00136 #ifdef  INT64_SUPPORTED
00137    // 64 bit integers available. Use multiply and shift method
00138    uint32_t interval;                    // Length of interval
00139    uint64_t longran;                     // Random bits * interval
00140    uint32_t iran;                        // Longran / 2^32
00141    uint32_t remainder;                   // Longran % 2^32
00142 
00143    interval = uint32_t(max - min + 1);
00144    if (interval != LastInterval) {
00145       // Interval length has changed. Must calculate rejection limit
00146       // Reject when remainder >= 2^32 / interval * interval
00147       // RLimit will be 0 if interval is a power of 2. No rejection then
00148       RLimit = uint32_t(((uint64_t)1 << 32) / interval) * interval - 1;
00149       LastInterval = interval;
00150    }
00151    do { // Rejection loop
00152       longran  = (uint64_t)BRandom() * interval;
00153       iran = (uint32_t)(longran >> 32);
00154       remainder = (uint32_t)longran;
00155    } while (remainder > RLimit);
00156    // Convert back to signed and return result
00157    return (int32_t)iran + min;
00158 
00159 #else
00160    // 64 bit integers not available. Use modulo method
00161    uint32_t interval;                    // Length of interval
00162    uint32_t bran;                        // Random bits
00163    uint32_t iran;                        // bran / interval
00164    uint32_t remainder;                   // bran % interval
00165 
00166    interval = uint32_t(max - min + 1);
00167    if (interval != LastInterval) {
00168       // Interval length has changed. Must calculate rejection limit
00169       // Reject when iran = 2^32 / interval
00170       // We can't make 2^32 so we use 2^32-1 and correct afterwards
00171       RLimit = (uint32_t)0xFFFFFFFF / interval;
00172       if ((uint32_t)0xFFFFFFFF % interval == interval - 1) RLimit++;
00173    }
00174    do { // Rejection loop
00175       bran = BRandom();
00176       iran = bran / interval;
00177       remainder = bran % interval;
00178    } while (iran >= RLimit);
00179    // Convert back to signed and return result
00180    return (int32_t)remainder + min;
00181 
00182 #endif
00183 }