ThreeB 1.1
|
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 }