~ubuntu-branches/ubuntu/gutsy/poco/gutsy

« back to all changes in this revision

Viewing changes to Foundation/src/Random.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Krzysztof Burghardt
  • Date: 2007-04-27 18:33:48 UTC
  • Revision ID: james.westby@ubuntu.com-20070427183348-xgnpct0qd6a2ip34
Tags: upstream-1.2.9
ImportĀ upstreamĀ versionĀ 1.2.9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Random.cpp
 
3
//
 
4
// $Id: //poco/1.2/Foundation/src/Random.cpp#3 $
 
5
//
 
6
// Library: Foundation
 
7
// Package: Crypt
 
8
// Module:  Random
 
9
//
 
10
// Definition of class Random.
 
11
//
 
12
// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
 
13
// and Contributors.
 
14
//
 
15
// Permission is hereby granted, free of charge, to any person or organization
 
16
// obtaining a copy of the software and accompanying documentation covered by
 
17
// this license (the "Software") to use, reproduce, display, distribute,
 
18
// execute, and transmit the Software, and to prepare derivative works of the
 
19
// Software, and to permit third-parties to whom the Software is furnished to
 
20
// do so, all subject to the following:
 
21
// 
 
22
// The copyright notices in the Software and this entire statement, including
 
23
// the above license grant, this restriction and the following disclaimer,
 
24
// must be included in all copies of the Software, in whole or in part, and
 
25
// all derivative works of the Software, unless such copies or derivative
 
26
// works are solely in the form of machine-executable object code generated by
 
27
// a source language processor.
 
28
// 
 
29
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
30
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
31
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 
32
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 
33
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 
34
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 
35
// DEALINGS IN THE SOFTWARE.
 
36
//
 
37
//
 
38
// Based on the FreeBSD random number generator.
 
39
// src/lib/libc/stdlib/random.c,v 1.25 
 
40
//
 
41
// Copyright (c) 1983, 1993
 
42
// The Regents of the University of California.  All rights reserved.
 
43
// Redistribution and use in source and binary forms, with or without
 
44
// modification, are permitted provided that the following conditions
 
45
// are met:
 
46
// 1. Redistributions of source code must retain the above copyright
 
47
//    notice, this list of conditions and the following disclaimer.
 
48
// 2. Redistributions in binary form must reproduce the above copyright
 
49
//    notice, this list of conditions and the following disclaimer in the
 
50
//    documentation and/or other materials provided with the distribution.
 
51
// 4. Neither the name of the University nor the names of its contributors
 
52
//    may be used to endorse or promote products derived from this software
 
53
//    without specific prior written permission.
 
54
//
 
55
// THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 
56
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
57
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
58
// ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 
59
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
60
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
61
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
62
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
63
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
64
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
65
// SUCH DAMAGE.
 
66
//
 
67
 
 
68
 
 
69
#include "Poco/Random.h"
 
70
#include "Poco/RandomStream.h"
 
71
#include "time.h"
 
72
 
 
73
 
 
74
/*
 
75
 * random.c:
 
76
 *
 
77
 * An improved random number generation package.  In addition to the standard
 
78
 * rand()/srand() like interface, this package also has a special state info
 
79
 * interface.  The initstate() routine is called with a seed, an array of
 
80
 * bytes, and a count of how many bytes are being passed in; this array is
 
81
 * then initialized to contain information for random number generation with
 
82
 * that much state information.  Good sizes for the amount of state
 
83
 * information are 32, 64, 128, and 256 bytes.  The state can be switched by
 
84
 * calling the setstate() routine with the same array as was initiallized
 
85
 * with initstate().  By default, the package runs with 128 bytes of state
 
86
 * information and generates far better random numbers than a linear
 
87
 * congruential generator.  If the amount of state information is less than
 
88
 * 32 bytes, a simple linear congruential R.N.G. is used.
 
89
 *
 
90
 * Internally, the state information is treated as an array of uint32_t's; the
 
91
 * zeroeth element of the array is the type of R.N.G. being used (small
 
92
 * integer); the remainder of the array is the state information for the
 
93
 * R.N.G.  Thus, 32 bytes of state information will give 7 ints worth of
 
94
 * state information, which will allow a degree seven polynomial.  (Note:
 
95
 * the zeroeth word of state information also has some other information
 
96
 * stored in it -- see setstate() for details).
 
97
 *
 
98
 * The random number generation technique is a linear feedback shift register
 
99
 * approach, employing trinomials (since there are fewer terms to sum up that
 
100
 * way).  In this approach, the least significant bit of all the numbers in
 
101
 * the state table will act as a linear feedback shift register, and will
 
102
 * have period 2^deg - 1 (where deg is the degree of the polynomial being
 
103
 * used, assuming that the polynomial is irreducible and primitive).  The
 
104
 * higher order bits will have longer periods, since their values are also
 
105
 * influenced by pseudo-random carries out of the lower bits.  The total
 
106
 * period of the generator is approximately deg*(2**deg - 1); thus doubling
 
107
 * the amount of state information has a vast influence on the period of the
 
108
 * generator.  Note: the deg*(2**deg - 1) is an approximation only good for
 
109
 * large deg, when the period of the shift is the dominant factor.
 
110
 * With deg equal to seven, the period is actually much longer than the
 
111
 * 7*(2**7 - 1) predicted by this formula.
 
112
 *
 
113
 * Modified 28 December 1994 by Jacob S. Rosenberg.
 
114
 * The following changes have been made:
 
115
 * All references to the type u_int have been changed to unsigned long.
 
116
 * All references to type int have been changed to type long.  Other
 
117
 * cleanups have been made as well.  A warning for both initstate and
 
118
 * setstate has been inserted to the effect that on Sparc platforms
 
119
 * the 'arg_state' variable must be forced to begin on word boundaries.
 
120
 * This can be easily done by casting a long integer array to char *.
 
121
 * The overall logic has been left STRICTLY alone.  This software was
 
122
 * tested on both a VAX and Sun SpacsStation with exactly the same
 
123
 * results.  The new version and the original give IDENTICAL results.
 
124
 * The new version is somewhat faster than the original.  As the
 
125
 * documentation says:  "By default, the package runs with 128 bytes of
 
126
 * state information and generates far better random numbers than a linear
 
127
 * congruential generator.  If the amount of state information is less than
 
128
 * 32 bytes, a simple linear congruential R.N.G. is used."  For a buffer of
 
129
 * 128 bytes, this new version runs about 19 percent faster and for a 16
 
130
 * byte buffer it is about 5 percent faster.
 
131
 */
 
132
 
 
133
 
 
134
/*
 
135
 * For each of the currently supported random number generators, we have a
 
136
 * break value on the amount of state information (you need at least this
 
137
 * many bytes of state info to support this random number generator), a degree
 
138
 * for the polynomial (actually a trinomial) that the R.N.G. is based on, and
 
139
 * the separation between the two lower order coefficients of the trinomial.
 
140
 */
 
141
#define TYPE_0          0               /* linear congruential */
 
142
#define BREAK_0         8
 
143
#define DEG_0           0
 
144
#define SEP_0           0
 
145
 
 
146
#define TYPE_1          1               /* x**7 + x**3 + 1 */
 
147
#define BREAK_1         32
 
148
#define DEG_1           7
 
149
#define SEP_1           3
 
150
 
 
151
#define TYPE_2          2               /* x**15 + x + 1 */
 
152
#define BREAK_2         64
 
153
#define DEG_2           15
 
154
#define SEP_2           1
 
155
 
 
156
#define TYPE_3          3               /* x**31 + x**3 + 1 */
 
157
#define BREAK_3         128
 
158
#define DEG_3           31
 
159
#define SEP_3           3
 
160
 
 
161
#define TYPE_4          4               /* x**63 + x + 1 */
 
162
#define BREAK_4         256
 
163
#define DEG_4           63
 
164
#define SEP_4           1
 
165
 
 
166
 
 
167
namespace Poco {
 
168
 
 
169
 
 
170
Random::Random(int stateSize)
 
171
{
 
172
        poco_assert (BREAK_0 <= stateSize && stateSize <= BREAK_4);
 
173
 
 
174
        _pBuffer = new char[stateSize];
 
175
        initState((UInt32) time(NULL), _pBuffer, stateSize);
 
176
}
 
177
 
 
178
 
 
179
Random::~Random()
 
180
{
 
181
        delete [] _pBuffer;
 
182
}
 
183
 
 
184
 
 
185
/*
 
186
 * Compute x = (7^5 * x) mod (2^31 - 1)
 
187
 * wihout overflowing 31 bits:
 
188
 *      (2^31 - 1) = 127773 * (7^5) + 2836
 
189
 * From "Random number generators: good ones are hard to find",
 
190
 * Park and Miller, Communications of the ACM, vol. 31, no. 10,
 
191
 * October 1988, p. 1195.
 
192
 */
 
193
inline UInt32 Random::goodRand(Int32 x)
 
194
{
 
195
        Int32 hi, lo;
 
196
 
 
197
        if (x == 0) x = 123459876;
 
198
        hi = x / 127773;
 
199
        lo = x % 127773;
 
200
        x = 16807 * lo - 2836 * hi;
 
201
        if (x < 0) x += 0x7FFFFFFF;
 
202
 
 
203
        return x;
 
204
}
 
205
 
 
206
 
 
207
/*
 
208
 * Initialize the random number generator based on the given seed.  If the
 
209
 * type is the trivial no-state-information type, just remember the seed.
 
210
 * Otherwise, initializes state[] based on the given "seed" via a linear
 
211
 * congruential generator.  Then, the pointers are set to known locations
 
212
 * that are exactly rand_sep places apart.  Lastly, it cycles the state
 
213
 * information a given number of times to get rid of any initial dependencies
 
214
 * introduced by the L.C.R.N.G.  Note that the initialization of randtbl[]
 
215
 * for default usage relies on values produced by this routine.
 
216
 */
 
217
void Random::seed(UInt32 x)
 
218
{
 
219
        int i, lim;
 
220
 
 
221
        _state[0] = x;
 
222
        if (_randType == TYPE_0)
 
223
                lim = NSHUFF;
 
224
        else 
 
225
        {
 
226
                for (i = 1; i < _randDeg; i++)
 
227
                        _state[i] = goodRand(_state[i - 1]);
 
228
                _fptr = &_state[_randSep];
 
229
                _rptr = &_state[0];
 
230
                lim = 10 * _randDeg;
 
231
        }
 
232
        for (i = 0; i < lim; i++)
 
233
                next();
 
234
}
 
235
 
 
236
 
 
237
/*
 
238
 * Many programs choose the seed value in a totally predictable manner.
 
239
 * This often causes problems.  We seed the generator using the much more
 
240
 * secure random(4) interface.  Note that this particular seeding
 
241
 * procedure can generate states which are impossible to reproduce by
 
242
 * calling srandom() with any value, since the succeeding terms in the
 
243
 * state buffer are no longer derived from the LC algorithm applied to
 
244
 * a fixed seed.
 
245
 */
 
246
void Random::seed()
 
247
{
 
248
        std::streamsize len;
 
249
 
 
250
        if (_randType == TYPE_0)
 
251
                len = sizeof _state[0];
 
252
        else
 
253
                len = _randDeg * sizeof _state[0];
 
254
 
 
255
        RandomInputStream rstr;
 
256
        rstr.read((char*) _state, len);
 
257
}
 
258
 
 
259
 
 
260
/*
 
261
 * Initialize the state information in the given array of n bytes for future
 
262
 * random number generation.  Based on the number of bytes we are given, and
 
263
 * the break values for the different R.N.G.'s, we choose the best (largest)
 
264
 * one we can and set things up for it.  srandom() is then called to
 
265
 * initialize the state information.
 
266
 *
 
267
 * Note that on return from srandom(), we set state[-1] to be the type
 
268
 * multiplexed with the current value of the rear pointer; this is so
 
269
 * successive calls to initstate() won't lose this information and will be
 
270
 * able to restart with setstate().
 
271
 *
 
272
 * Note: the first thing we do is save the current state, if any, just like
 
273
 * setstate() so that it doesn't matter when initstate is called.
 
274
 *
 
275
 * Returns a pointer to the old state.
 
276
 *
 
277
 * Note: The Sparc platform requires that arg_state begin on an int
 
278
 * word boundary; otherwise a bus error will occur. Even so, lint will
 
279
 * complain about mis-alignment, but you should disregard these messages.
 
280
 */
 
281
void Random::initState(UInt32 s, char* argState, Int32 n)
 
282
{
 
283
        UInt32* intArgState = (UInt32*) argState;
 
284
 
 
285
        if (n < BREAK_0) 
 
286
        {
 
287
                poco_bugcheck_msg("not enough state");
 
288
                return;
 
289
        }
 
290
        if (n < BREAK_1) 
 
291
        {
 
292
                _randType = TYPE_0;
 
293
                _randDeg  = DEG_0;
 
294
                _randSep  = SEP_0;
 
295
        } 
 
296
        else if (n < BREAK_2) 
 
297
        {
 
298
                _randType = TYPE_1;
 
299
                _randDeg  = DEG_1;
 
300
                _randSep  = SEP_1;
 
301
        } 
 
302
        else if (n < BREAK_3) 
 
303
        {
 
304
                _randType = TYPE_2;
 
305
                _randDeg  = DEG_2;
 
306
                _randSep  = SEP_2;
 
307
        } 
 
308
        else if (n < BREAK_4) 
 
309
        {
 
310
                _randType = TYPE_3;
 
311
                _randDeg  = DEG_3;
 
312
                _randSep  = SEP_3;
 
313
        } 
 
314
        else 
 
315
        {
 
316
                _randType = TYPE_4;
 
317
                _randDeg = DEG_4;
 
318
                _randSep = SEP_4;
 
319
        }
 
320
        _state  = intArgState + 1; /* first location */
 
321
        _endPtr = &_state[_randDeg];    /* must set end_ptr before seed */
 
322
        seed(s);
 
323
        if (_randType == TYPE_0)
 
324
                intArgState[0] = _randType;
 
325
        else
 
326
                intArgState[0] = MAX_TYPES * (int) (_rptr - _state) + _randType;
 
327
}
 
328
 
 
329
 
 
330
/*
 
331
 * Next:
 
332
 *
 
333
 * If we are using the trivial TYPE_0 R.N.G., just do the old linear
 
334
 * congruential bit.  Otherwise, we do our fancy trinomial stuff, which is
 
335
 * the same in all the other cases due to all the global variables that have
 
336
 * been set up.  The basic operation is to add the number at the rear pointer
 
337
 * into the one at the front pointer.  Then both pointers are advanced to
 
338
 * the next location cyclically in the table.  The value returned is the sum
 
339
 * generated, reduced to 31 bits by throwing away the "least random" low bit.
 
340
 *
 
341
 * Note: the code takes advantage of the fact that both the front and
 
342
 * rear pointers can't wrap on the same call by not testing the rear
 
343
 * pointer if the front one has wrapped.
 
344
 *
 
345
 * Returns a 31-bit random number.
 
346
 */
 
347
UInt32 Random::next()
 
348
{
 
349
        UInt32 i;
 
350
        UInt32 *f, *r;
 
351
 
 
352
        if (_randType == TYPE_0) 
 
353
        {
 
354
                i = _state[0];
 
355
                _state[0] = i = goodRand(i) & 0x7FFFFFFF;
 
356
        } 
 
357
        else 
 
358
        {
 
359
                /*
 
360
                 * Use local variables rather than static variables for speed.
 
361
                 */
 
362
                f = _fptr; r = _rptr;
 
363
                *f += *r;
 
364
                i = (*f >> 1) & 0x7FFFFFFF;     /* chucking least random bit */
 
365
                if (++f >= _endPtr) {
 
366
                        f = _state;
 
367
                        ++r;
 
368
                }
 
369
                else if (++r >= _endPtr) {
 
370
                        r = _state;
 
371
                }
 
372
 
 
373
                _fptr = f; _rptr = r;
 
374
        }
 
375
        return i;
 
376
}
 
377
 
 
378
 
 
379
} // namespace Poco