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
1.2.14 written by Dimitri van Heesch,
© 1997-2002