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