KCoreAddons

krandomsequence.cpp
1 /*
2  This file is part of the KDE libraries
3 
4  SPDX-FileCopyrightText: 1999 Sean Harmer <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "krandomsequence.h"
10 #include "krandom.h"
11 
12 class Q_DECL_HIDDEN KRandomSequence::Private
13 {
14 public:
15  enum {SHUFFLE_TABLE_SIZE = 32};
16 
17  void draw(); // Generate the random number
18 
19  int lngSeed1;
20  int lngSeed2;
21  int lngShufflePos;
22  int shuffleArray[SHUFFLE_TABLE_SIZE];
23 };
24 
26 // Construction / Destruction
28 
29 KRandomSequence::KRandomSequence(long lngSeed1) : d(new Private)
30 {
31  // Seed the generator
32  setSeed(lngSeed1);
33 }
34 
35 KRandomSequence::KRandomSequence(int lngSeed1) : d(new Private)
36 {
37  // Seed the generator
38  setSeed(lngSeed1);
39 }
40 
42 {
43  delete d;
44 }
45 
47 {
48  *d = *a.d;
49 }
50 
52 {
53  if (this != &a) {
54  *d = *a.d;
55  }
56  return *this;
57 }
58 
60 // Member Functions
62 void KRandomSequence::setSeed(long lngSeed1)
63 {
64  setSeed(static_cast<int>(lngSeed1));
65 }
66 
67 void KRandomSequence::setSeed(int lngSeed1)
68 {
69  // Convert the positive seed number to a negative one so that the draw()
70  // function can initialise itself the first time it is called. We just have
71  // to make sure that the seed used != 0 as zero perpetuates itself in a
72  // sequence of random numbers.
73  if (lngSeed1 < 0) {
74  d->lngSeed1 = -1;
75  } else if (lngSeed1 == 0) {
76  d->lngSeed1 = -((KRandom::random() & ~1) + 1);
77  } else {
78  d->lngSeed1 = -lngSeed1;
79  }
80 }
81 
82 static const int sMod1 = 2147483563;
83 static const int sMod2 = 2147483399;
84 
85 void KRandomSequence::Private::draw()
86 {
87  static const int sMM1 = sMod1 - 1;
88  static const int sA1 = 40014;
89  static const int sA2 = 40692;
90  static const int sQ1 = 53668;
91  static const int sQ2 = 52774;
92  static const int sR1 = 12211;
93  static const int sR2 = 3791;
94  static const int sDiv = 1 + sMM1 / SHUFFLE_TABLE_SIZE;
95 
96  // Long period (>2 * 10^18) random number generator of L'Ecuyer with
97  // Bayes-Durham shuffle and added safeguards. Returns a uniform random
98  // deviate between 0.0 and 1.0 (exclusive of the endpoint values). Call
99  // with a negative number to initialize; thereafter, do not alter idum
100  // between successive deviates in a sequence. RNMX should approximate
101  // the largest floating point value that is less than 1.
102 
103  int j; // Index for the shuffle table
104  int k;
105 
106  // Initialise
107  if (lngSeed1 <= 0) {
108  lngSeed2 = lngSeed1;
109 
110  // Load the shuffle table after 8 warm-ups
111  for (j = SHUFFLE_TABLE_SIZE + 7; j >= 0; --j) {
112  k = lngSeed1 / sQ1;
113  lngSeed1 = sA1 * (lngSeed1 - k * sQ1) - k * sR1;
114  if (lngSeed1 < 0) {
115  lngSeed1 += sMod1;
116  }
117 
118  if (j < SHUFFLE_TABLE_SIZE) {
119  shuffleArray[j] = lngSeed1;
120  }
121  }
122 
123  lngShufflePos = shuffleArray[0];
124  }
125 
126  // Start here when not initializing
127 
128  // Compute lngSeed1 = ( lngIA1*lngSeed1 ) % lngIM1 without overflows
129  // by Schrage's method
130  k = lngSeed1 / sQ1;
131  lngSeed1 = sA1 * (lngSeed1 - k * sQ1) - k * sR1;
132  if (lngSeed1 < 0) {
133  lngSeed1 += sMod1;
134  }
135 
136  // Compute lngSeed2 = ( lngIA2*lngSeed2 ) % lngIM2 without overflows
137  // by Schrage's method
138  k = lngSeed2 / sQ2;
139  lngSeed2 = sA2 * (lngSeed2 - k * sQ2) - k * sR2;
140  if (lngSeed2 < 0) {
141  lngSeed2 += sMod2;
142  }
143 
144  j = lngShufflePos / sDiv;
145  lngShufflePos = shuffleArray[j] - lngSeed2;
146  shuffleArray[j] = lngSeed1;
147 
148  if (lngShufflePos < 1) {
149  lngShufflePos += sMM1;
150  }
151 }
152 
153 void
155 {
156  d->lngSeed2 -= i;
157  if (d->lngSeed2 < 0) {
158  d->lngShufflePos += sMod2;
159  }
160  d->draw();
161  d->lngSeed1 -= i;
162  if (d->lngSeed1 < 0) {
163  d->lngSeed1 += sMod1;
164  }
165  d->draw();
166 }
167 
168 double
170 {
171  static const double finalAmp = 1.0 / double(sMod1);
172  static const double epsilon = 1.2E-7;
173  static const double maxRand = 1.0 - epsilon;
174  double temp;
175  d->draw();
176  // Return a value that is not one of the endpoints
177  if ((temp = finalAmp * d->lngShufflePos) > maxRand) {
178  // We don't want to return 1.0
179  return maxRand;
180  } else {
181  return temp;
182  }
183 }
184 
185 unsigned long
186 KRandomSequence::getLong(unsigned long max)
187 {
188  return getInt(static_cast<int>(max));
189 }
190 
191 unsigned int
192 KRandomSequence::getInt(unsigned int max)
193 {
194  d->draw();
195 
196  return max ? ((static_cast<unsigned int>(d->lngShufflePos)) % max) : 0;
197 }
198 
199 bool
201 {
202  d->draw();
203 
204  return ((static_cast<unsigned int>(d->lngShufflePos)) & 1);
205 }
double getDouble()
Get the next number from the pseudo-random sequence.
void modulate(int i)
Modulate the random sequence.
KCOREADDONS_EXPORT int random()
Generates a uniform random number.
Definition: krandom.cpp:30
unsigned int getInt(unsigned int max)
Get the next number from the pseudo-random sequence.
virtual ~KRandomSequence()
Standard destructor.
bool getBool()
Get a boolean from the pseudo-random sequence.
void setSeed(int intSeed=0)
Restart the sequence based on lngSeed.
KRandomSequence(int intSeed=0)
Creates a pseudo-random sequence based on the seed lngSeed.
KRandomSequence & operator=(const KRandomSequence &a)
Assignment.
A class to create a pseudo-random sequence.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Jun 6 2020 22:53:01 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.