Random.cpp 12 KB

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