KDECore
krandomsequence.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of the KDE libraries 00003 Copyright (c) 1999 Sean Harmer <sh@astro.keele.ac.uk> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "krandomsequence.h" 00022 #include "krandom.h" 00023 00024 static const int s_nShuffleTableSize = 32; 00025 00026 class KRandomSequence::Private 00027 { 00028 public: 00029 // Generate the random number 00030 void draw(); 00031 00032 long lngSeed1; 00033 long lngSeed2; 00034 long lngShufflePos; 00035 long shuffleArray[s_nShuffleTableSize]; 00036 }; 00037 00039 // Construction / Destruction 00041 00042 KRandomSequence::KRandomSequence( long lngSeed1 ) : d(new Private) 00043 { 00044 // Seed the generator 00045 setSeed( lngSeed1 ); 00046 } 00047 00048 KRandomSequence::~KRandomSequence() 00049 { 00050 delete d; 00051 } 00052 00053 KRandomSequence::KRandomSequence(const KRandomSequence &a) : d(new Private) 00054 { 00055 *d = *a.d; 00056 } 00057 00058 KRandomSequence & KRandomSequence::operator=(const KRandomSequence &a) 00059 { 00060 if ( this != &a ) { 00061 *d = *a.d; 00062 } 00063 return *this; 00064 } 00065 00066 00068 // Member Functions 00070 00071 void KRandomSequence::setSeed( long lngSeed1 ) 00072 { 00073 // Convert the positive seed number to a negative one so that the draw() 00074 // function can intialise itself the first time it is called. We just have 00075 // to make sure that the seed used != 0 as zero perpetuates itself in a 00076 // sequence of random numbers. 00077 if ( lngSeed1 < 0 ) 00078 { 00079 d->lngSeed1 = -1; 00080 } 00081 else if (lngSeed1 == 0) 00082 { 00083 d->lngSeed1 = -((KRandom::random() & ~1)+1); 00084 } 00085 else 00086 { 00087 d->lngSeed1 = -lngSeed1; 00088 } 00089 } 00090 00091 static const long sMod1 = 2147483563; 00092 static const long sMod2 = 2147483399; 00093 00094 void KRandomSequence::Private::draw() 00095 { 00096 static const long sMM1 = sMod1 - 1; 00097 static const long sA1 = 40014; 00098 static const long sA2 = 40692; 00099 static const long sQ1 = 53668; 00100 static const long sQ2 = 52774; 00101 static const long sR1 = 12211; 00102 static const long sR2 = 3791; 00103 static const long sDiv = 1 + sMM1 / s_nShuffleTableSize; 00104 00105 // Long period (>2 * 10^18) random number generator of L'Ecuyer with 00106 // Bayes-Durham shuffle and added safeguards. Returns a uniform random 00107 // deviate between 0.0 and 1.0 (exclusive of the endpoint values). Call 00108 // with a negative number to initialize; thereafter, do not alter idum 00109 // between successive deviates in a sequence. RNMX should approximate 00110 // the largest floating point value that is less than 1. 00111 00112 int j; // Index for the shuffle table 00113 long k; 00114 00115 // Initialise 00116 if ( lngSeed1 <= 0 ) 00117 { 00118 lngSeed2 = lngSeed1; 00119 00120 // Load the shuffle table after 8 warm-ups 00121 for ( j = s_nShuffleTableSize + 7; j >= 0; --j ) 00122 { 00123 k = lngSeed1 / sQ1; 00124 lngSeed1 = sA1 * ( lngSeed1 - k*sQ1) - k*sR1; 00125 if ( lngSeed1 < 0 ) 00126 { 00127 lngSeed1 += sMod1; 00128 } 00129 00130 if ( j < s_nShuffleTableSize ) 00131 { 00132 shuffleArray[j] = lngSeed1; 00133 } 00134 } 00135 00136 lngShufflePos = shuffleArray[0]; 00137 } 00138 00139 // Start here when not initializing 00140 00141 // Compute lngSeed1 = ( lngIA1*lngSeed1 ) % lngIM1 without overflows 00142 // by Schrage's method 00143 k = lngSeed1 / sQ1; 00144 lngSeed1 = sA1 * ( lngSeed1 - k*sQ1 ) - k*sR1; 00145 if ( lngSeed1 < 0 ) 00146 { 00147 lngSeed1 += sMod1; 00148 } 00149 00150 // Compute lngSeed2 = ( lngIA2*lngSeed2 ) % lngIM2 without overflows 00151 // by Schrage's method 00152 k = lngSeed2 / sQ2; 00153 lngSeed2 = sA2 * ( lngSeed2 - k*sQ2 ) - k*sR2; 00154 if ( lngSeed2 < 0 ) 00155 { 00156 lngSeed2 += sMod2; 00157 } 00158 00159 j = lngShufflePos / sDiv; 00160 lngShufflePos = shuffleArray[j] - lngSeed2; 00161 shuffleArray[j] = lngSeed1; 00162 00163 if ( lngShufflePos < 1 ) 00164 { 00165 lngShufflePos += sMM1; 00166 } 00167 } 00168 00169 void 00170 KRandomSequence::modulate(int i) 00171 { 00172 d->lngSeed2 -= i; 00173 if ( d->lngSeed2 < 0 ) 00174 { 00175 d->lngShufflePos += sMod2; 00176 } 00177 d->draw(); 00178 d->lngSeed1 -= i; 00179 if ( d->lngSeed1 < 0 ) 00180 { 00181 d->lngSeed1 += sMod1; 00182 } 00183 d->draw(); 00184 } 00185 00186 double 00187 KRandomSequence::getDouble() 00188 { 00189 static const double finalAmp = 1.0 / double( sMod1 ); 00190 static const double epsilon = 1.2E-7; 00191 static const double maxRand = 1.0 - epsilon; 00192 double temp; 00193 d->draw(); 00194 // Return a value that is not one of the endpoints 00195 if ( ( temp = finalAmp * d->lngShufflePos ) > maxRand ) 00196 { 00197 // We don't want to return 1.0 00198 return maxRand; 00199 } 00200 else 00201 { 00202 return temp; 00203 } 00204 } 00205 00206 unsigned long 00207 KRandomSequence::getLong(unsigned long max) 00208 { 00209 d->draw(); 00210 00211 return max ? (((unsigned long) d->lngShufflePos) % max) : 0; 00212 } 00213 00214 bool 00215 KRandomSequence::getBool() 00216 { 00217 d->draw(); 00218 00219 return (((unsigned long) d->lngShufflePos) & 1); 00220 }
KDE 4.7 API Reference