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