Main Page   Class Hierarchy   Compound List   File List   Compound Members  

mersenne.cpp

00001 /*
00002  *  This program is free software; you can redistribute it and/or modify
00003  *  it under the terms of the GNU General Public License as published by
00004  *  the Free Software Foundation; either version 2 of the License, or
00005  *  (at your option) any later version.
00006  *
00007  *  This program is distributed in the hope that it will be useful,
00008  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00009  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010  *  GNU General Public License for more details.
00011  *
00012  *  You should have received a copy of the GNU General Public License
00013  *  along with this program; if not, write to the Free Software
00014  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00015  *
00016  * This file is extracted from the random generator library provided by Agner Fog
00017  * (http://www.agner.org/random/) and has been modified for Seagull.
00018  * (c) 2002 Agner Fog. GNU General Public License www.gnu.org/copyleft/gpl.html
00019  *
00020  * (c)Copyright 2006 Hewlett-Packard Development Company, LP.
00021  *
00022  */
00023 
00024 #include "randomc.h"
00025 
00026 
00027 void TRandomMersenne::RandomInit(uint32 seed) {
00028   // re-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   // detect computer architecture
00034   union {double f; uint32 i[2];} convert;
00035   convert.f = 1.0;
00036   // Note: Old versions of the Gnu g++ compiler may make an error here,
00037   // compile with the option  -fenum-int-equiv  to fix the problem
00038   if (convert.i[1] == 0x3FF00000) Architecture = LITTLE_ENDIAN1;
00039   else if (convert.i[0] == 0x3FF00000) Architecture = BIG_ENDIAN1;
00040   else Architecture = NONIEEE;}
00041 
00042 uint32 TRandomMersenne::BRandom() {
00043   // generate 32 random bits
00044   uint32 y;
00045 
00046   if (mti >= MERS_N) {
00047     // generate MERS_N words at one time
00048     const uint32 LOWER_MASK = (1LU << MERS_R) - 1;         // lower MERS_R bits
00049     const uint32 UPPER_MASK = 0xFFFFFFFF << MERS_R;        // upper (32 - MERS_R) bits
00050     static const uint32 mag01[2] = {0, MERS_A};
00051 
00052     int kk;
00053     for (kk=0; kk < MERS_N-MERS_M; kk++) {
00054       y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
00055       mt[kk] = mt[kk+MERS_M] ^ (y >> 1) ^ mag01[y & 1];}
00056 
00057     for (; kk < MERS_N-1; kk++) {
00058       y = (mt[kk] & UPPER_MASK) | (mt[kk+1] & LOWER_MASK);
00059       mt[kk] = mt[kk+(MERS_M-MERS_N)] ^ (y >> 1) ^ mag01[y & 1];}
00060 
00061     y = (mt[MERS_N-1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
00062     mt[MERS_N-1] = mt[MERS_M-1] ^ (y >> 1) ^ mag01[y & 1];
00063     mti = 0;}
00064 
00065   y = mt[mti++];
00066 
00067   // Tempering (May be omitted):
00068   y ^=  y >> MERS_U;
00069   y ^= (y << MERS_S) & MERS_B;
00070   y ^= (y << MERS_T) & MERS_C;
00071   y ^=  y >> MERS_L;
00072   return y;}
00073 
00074 
00075 
00076 double TRandomMersenne::Random() {
00077   // output random float number in the interval 0 <= x < 1
00078   union {double f; uint32 i[2];} convert;
00079   uint32 r = BRandom(); // get 32 random bits
00080   // The fastest way to convert random bits to floating point is as follows:
00081   // Set the binary exponent of a floating point number to 1+bias and set
00082   // the mantissa to random bits. This will give a random number in the
00083   // interval [1,2). Then subtract 1.0 to get a random number in the interval
00084   // [0,1). This procedure requires that we know how floating point numbers
00085   // are stored. The storing method is tested in function RandomInit and saved
00086   // in the variable Architecture. The following switch statement can be
00087   // omitted if the architecture is known. (A PC running Windows or Linux uses
00088   // LITTLE_ENDIAN1 architecture):
00089   switch (Architecture) {
00090   case LITTLE_ENDIAN1:
00091     convert.i[0] =  r << 20;
00092     convert.i[1] = (r >> 12) | 0x3FF00000;
00093     return convert.f - 1.0;
00094   case BIG_ENDIAN1:
00095     convert.i[1] =  r << 20;
00096     convert.i[0] = (r >> 12) | 0x3FF00000;
00097     return convert.f - 1.0;
00098   case NONIEEE: default:
00099   ;}
00100   // This somewhat slower method works for all architectures, including
00101   // non-IEEE floating point representation:
00102   return (double)r * (1./((double)(uint32)(-1L)+1.));}
00103 

Generated on Wed Mar 7 14:44:59 2007 for Seagull by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002