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 #include <string.h> 00024 #include <config.h> 00025 00026 static const int s_nShuffleTableSize = 32; 00027 00028 class KRandomSequence::Private 00029 { 00030 public: 00031 // Generate the random number 00032 void draw(); 00033 00034 long lngSeed1; 00035 long lngSeed2; 00036 long lngShufflePos; 00037 long shuffleArray[s_nShuffleTableSize]; 00038 }; 00039 00041 // Construction / Destruction 00043 00044 KRandomSequence::KRandomSequence( long lngSeed1 ) : d(new Private) 00045 { 00046 // Seed the generator 00047 setSeed( lngSeed1 ); 00048 } 00049 00050 KRandomSequence::~KRandomSequence() 00051 { 00052 delete d; 00053 } 00054 00055 KRandomSequence::KRandomSequence(const KRandomSequence &a) : d(new Private) 00056 { 00057 *d = *a.d; 00058 } 00059 00060 KRandomSequence & KRandomSequence::operator=(const KRandomSequence &a) 00061 { 00062 if ( this != &a ) { 00063 *d = *a.d; 00064 } 00065 return *this; 00066 } 00067 00068 00070 // Member Functions 00072 00073 void KRandomSequence::setSeed( long lngSeed1 ) 00074 { 00075 // Convert the positive seed number to a negative one so that the draw() 00076 // function can intialise itself the first time it is called. We just have 00077 // to make sure that the seed used != 0 as zero perpetuates itself in a 00078 // sequence of random numbers. 00079 if ( lngSeed1 < 0 ) 00080 { 00081 d->lngSeed1 = -1; 00082 } 00083 else if (lngSeed1 == 0) 00084 { 00085 d->lngSeed1 = -((KRandom::random() & ~1)+1); 00086 } 00087 else 00088 { 00089 d->lngSeed1 = -lngSeed1; 00090 } 00091 } 00092 00093 static const long sMod1 = 2147483563; 00094 static const long sMod2 = 2147483399; 00095 00096 void KRandomSequence::Private::draw() 00097 { 00098 static const long sMM1 = sMod1 - 1; 00099 static const long sA1 = 40014; 00100 static const long sA2 = 40692; 00101 static const long sQ1 = 53668; 00102 static const long sQ2 = 52774; 00103 static const long sR1 = 12211; 00104 static const long sR2 = 3791; 00105 static const long sDiv = 1 + sMM1 / s_nShuffleTableSize; 00106 00107 // Long period (>2 * 10^18) random number generator of L'Ecuyer with 00108 // Bayes-Durham shuffle and added safeguards. Returns a uniform random 00109 // deviate between 0.0 and 1.0 (exclusive of the endpoint values). Call 00110 // with a negative number to initialize; thereafter, do not alter idum 00111 // between successive deviates in a sequence. RNMX should approximate 00112 // the largest floating point value that is less than 1. 00113 00114 int j; // Index for the shuffle table 00115 long k; 00116 00117 // Initialise 00118 if ( lngSeed1 <= 0 ) 00119 { 00120 lngSeed2 = lngSeed1; 00121 00122 // Load the shuffle table after 8 warm-ups 00123 for ( j = s_nShuffleTableSize + 7; j >= 0; j-- ) 00124 { 00125 k = lngSeed1 / sQ1; 00126 lngSeed1 = sA1 * ( lngSeed1 - k*sQ1) - k*sR1; 00127 if ( lngSeed1 < 0 ) 00128 { 00129 lngSeed1 += sMod1; 00130 } 00131 00132 if ( j < s_nShuffleTableSize ) 00133 { 00134 shuffleArray[j] = lngSeed1; 00135 } 00136 } 00137 00138 lngShufflePos = shuffleArray[0]; 00139 } 00140 00141 // Start here when not initializing 00142 00143 // Compute lngSeed1 = ( lngIA1*lngSeed1 ) % lngIM1 without overflows 00144 // by Schrage's method 00145 k = lngSeed1 / sQ1; 00146 lngSeed1 = sA1 * ( lngSeed1 - k*sQ1 ) - k*sR1; 00147 if ( lngSeed1 < 0 ) 00148 { 00149 lngSeed1 += sMod1; 00150 } 00151 00152 // Compute lngSeed2 = ( lngIA2*lngSeed2 ) % lngIM2 without overflows 00153 // by Schrage's method 00154 k = lngSeed2 / sQ2; 00155 lngSeed2 = sA2 * ( lngSeed2 - k*sQ2 ) - k*sR2; 00156 if ( lngSeed2 < 0 ) 00157 { 00158 lngSeed2 += sMod2; 00159 } 00160 00161 j = lngShufflePos / sDiv; 00162 lngShufflePos = shuffleArray[j] - lngSeed2; 00163 shuffleArray[j] = lngSeed1; 00164 00165 if ( lngShufflePos < 1 ) 00166 { 00167 lngShufflePos += sMM1; 00168 } 00169 } 00170 00171 void 00172 KRandomSequence::modulate(int i) 00173 { 00174 d->lngSeed2 -= i; 00175 if ( d->lngSeed2 < 0 ) 00176 { 00177 d->lngShufflePos += sMod2; 00178 } 00179 d->draw(); 00180 d->lngSeed1 -= i; 00181 if ( d->lngSeed1 < 0 ) 00182 { 00183 d->lngSeed1 += sMod1; 00184 } 00185 d->draw(); 00186 } 00187 00188 double 00189 KRandomSequence::getDouble() 00190 { 00191 static const double finalAmp = 1.0 / double( sMod1 ); 00192 static const double epsilon = 1.2E-7; 00193 static const double maxRand = 1.0 - epsilon; 00194 double temp; 00195 d->draw(); 00196 // Return a value that is not one of the endpoints 00197 if ( ( temp = finalAmp * d->lngShufflePos ) > maxRand ) 00198 { 00199 // We don't want to return 1.0 00200 return maxRand; 00201 } 00202 else 00203 { 00204 return temp; 00205 } 00206 } 00207 00208 unsigned long 00209 KRandomSequence::getLong(unsigned long max) 00210 { 00211 d->draw(); 00212 00213 return max ? (((unsigned long) d->lngShufflePos) % max) : 0; 00214 } 00215 00216 bool 00217 KRandomSequence::getBool() 00218 { 00219 d->draw(); 00220 00221 return (((unsigned long) d->lngShufflePos) & 1); 00222 }
KDE 4.6 API Reference