home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- * Module: r250.c
- * Description: implements R250 random number generator, from S.
- * Kirkpatrick and E. Stoll, Journal of Computational Physics, 40, p.
- * 517 (1981).
- * Written by: W. L. Maier
- *
- * METHOD...
- * 16 parallel copies of a linear shift register with
- * period 2^250 - 1. FAR longer period than the usual
- * linear congruent generator, and commonly faster as
- * well. (For details see the above paper, and the
- * article in DDJ referenced below.)
- *
- * HISTORY...
- * Sep 92: Number returned by dr250() is in range [0,1) instead
- * of [0,1], so for example a random angle in the
- * interval [0, 2*PI) can be calculated
- * conveniently. (J. R. Van Zandt <jrv@mbunix.mitre.org>)
- * Aug 92: Initialization is optional. Default condition is
- * equivalent to initializing with the seed 12345,
- * so that the sequence of random numbers begins:
- * 1173, 53403, 52352, 35341... (9996 numbers
- * skipped) ...57769, 14511, 46930, 11942, 7978,
- * 56163, 46506, 45768, 21162, 43113... Using ^=
- * operator rather than two separate statements.
- * Initializing with own linear congruent
- * pseudorandom number generator for portability.
- * Function prototypes moved to a header file.
- * Implemented r250n() to generate numbers
- * uniformly distributed in a specific range
- * [0,n), because the common expedient rand()%n is
- * incorrect. (J. R. Van Zandt <jrv@mbunix.mitre.org>)
- * May 91: Published by W. L. Maier, "A Fast Pseudo Random Number
- * Generator", Dr. Dobb's Journal #176.
- ******************************************************************************/
-
- #include <stdlib.h>
- #include "r250.h"
-
- /**** Static variables ****/
- static int r250_index = 0;
- static unsigned int r250_buffer[250] = {
- 15301,57764,10921,56345,19316,43154,54727,49252,32360,49582,
- 26124,25833,34404,11030,26232,13965,16051,63635,55860,5184,
- 15931,39782,16845,11371,38624,10328,9139,1684,48668,59388,
- 13297,1364,56028,15687,63279,27771,5277,44628,31973,46977,
- 16327,23408,36065,52272,33610,61549,58364,3472,21367,56357,
- 56345,54035,7712,55884,39774,10241,50164,47995,1718,46887,
- 47892,6010,29575,54972,30458,21966,54449,10387,4492,644,
- 57031,41607,61820,54588,40849,54052,59875,43128,50370,44691,
- 286,12071,3574,61384,15592,45677,9711,23022,35256,45493,
- 48913,146,9053,5881,36635,43280,53464,8529,34344,64955,
- 38266,12730,101,16208,12607,58921,22036,8221,31337,11984,
- 20290,26734,19552,48,31940,43448,34762,53344,60664,12809,
- 57318,17436,44730,19375,30,17425,14117,5416,23853,55783,
- 57995,32074,26526,2192,11447,11,53446,35152,64610,64883,
- 26899,25357,7667,3577,39414,51161,4,58427,57342,58557,
- 53233,1066,29237,36808,19370,17493,37568,3,61468,38876,
- 17586,64937,21716,56472,58160,44955,55221,63880,1,32200,
- 62066,22911,24090,10438,40783,36364,14999,2489,43284,9898,
- 39612,9245,593,34857,41054,30162,65497,53340,27209,45417,
- 37497,4612,58397,52910,56313,62716,22377,40310,15190,34471,
- 64005,18090,11326,50839,62901,59284,5580,15231,9467,13161,
- 58500,7259,317,50968,2962,23006,32280,6994,18751,5148,
- 52739,49370,51892,18552,52264,54031,2804,17360,1919,19639,
- 2323,9448,43821,11022,45500,31509,49180,35598,38883,19754,
- 987,11521,55494,38056,20664,2629,50986,31009,54043,59743
- };
-
- static unsigned myrand();
- static void mysrand(unsigned newseed);
-
- /**** Function: r250_init
- Description: initializes r250 random number generator. ****/
- void r250_init(int seed)
- {
- /*---------------------------------------------------------------------------*/
- int j, k;
- unsigned int mask;
- unsigned int msb;
- /*---------------------------------------------------------------------------*/
- mysrand(seed);
- r250_index = 0;
- for (j = 0; j < 250; j++) /* Fill the r250 buffer with 15-bit values */
- r250_buffer[j] = myrand();
- for (j = 0; j < 250; j++) /* Set some of the MS bits to 1 */
- if (myrand() > 16384)
- r250_buffer[j] |= 0x8000;
- msb = 0x8000; /* To turn on the diagonal bit */
- mask = 0xffff; /* To turn off the leftmost bits */
- for (j = 0; j < 16; j++)
- {
- k = 11 * j + 3; /* Select a word to operate on */
- r250_buffer[k] &= mask; /* Turn off bits left of the diagonal */
- r250_buffer[k] |= msb; /* Turn on the diagonal bit */
- mask >>= 1;
- msb >>= 1;
- }
- }
-
- /**** Function: r250 Description: returns a random unsigned integer k
- uniformly distributed in the interval 0 <= k < 65536. ****/
- unsigned int r250()
- {
- /*---------------------------------------------------------------------------*/
- register int j;
- register unsigned int new_rand;
- /*---------------------------------------------------------------------------*/
- if (r250_index >= 147)
- j = r250_index - 147; /* Wrap pointer around */
- else
- j = r250_index + 103;
-
- new_rand = r250_buffer[r250_index] ^= r250_buffer[j];
-
- if (r250_index >= 249) /* Increment pointer for next time */
- r250_index = 0;
- else
- r250_index++;
-
- return new_rand;
- }
-
- /**** Function: r250n Description: returns a random unsigned integer k
- uniformly distributed in the interval 0 <= k < n ****/
- unsigned int r250n(unsigned n)
- {
- /*---------------------------------------------------------------------------*/
- register int j;
- register unsigned int new_rand, limit;
- /*---------------------------------------------------------------------------*/
- limit = (65535U/n)*n;
- do
- {new_rand = r250();
- if (r250_index >= 147)
- j = r250_index - 147; /* Wrap pointer around */
- else
- j = r250_index + 103;
-
- new_rand = r250_buffer[r250_index] ^= r250_buffer[j];
-
- if (r250_index >= 249) /* Increment pointer for next time */
- r250_index = 0;
- else
- r250_index++;
- } while(new_rand >= limit);
- return new_rand%n;
- }
-
- /**** Function: dr250
- Description: returns a random double z in range 0 <= z < 1. ****/
- double dr250()
- {
- /*---------------------------------------------------------------------------*/
- register int j;
- register unsigned int new_rand;
- /*---------------------------------------------------------------------------*/
- if (r250_index >= 147)
- j = r250_index - 147; /* Wrap pointer around */
- else
- j = r250_index + 103;
-
- new_rand = r250_buffer[r250_index] ^= r250_buffer[j];
-
- if (r250_index >= 249) /* Increment pointer for next time */
- r250_index = 0;
- else
- r250_index++;
- return new_rand / 65536.; /* Return a number in [0.0 to 1.0) */
- }
-
-
- /*** linear congruent pseudorandom number generator for initialization ***/
-
- static unsigned long seed=1;
-
- /* Return a pseudorandom number in the interval 0 <= n < 32768.
- This produces the following sequence of pseudorandom
- numbers:
- 346, 130, 10982, 1090... (9996 numbers skipped) ...23369,
- 2020, 5703, 12762, 10828, 16252, 28648, 27041, 23444, 6604...
- */
- static unsigned myrand()
- {
- seed = seed*0x015a4e35L + 1;
- return (seed>>16)&0x7fff;
- }
-
- /* Initialize above linear congruent pseudorandom number generator */
- static void mysrand(unsigned newseed)
- { seed = newseed;
- }
-
-