mirror of
https://github.com/caperren/school_archives.git
synced 2025-11-09 13:41:13 +00:00
180 lines
7.2 KiB
C
180 lines
7.2 KiB
C
/* -------------------------------------------------------------------------
|
|
* This is an ANSI C library for multi-stream random number generation.
|
|
* The use of this library is recommended as a replacement for the ANSI C
|
|
* rand() and srand() functions, particularly in simulation applications
|
|
* where the statistical 'goodness' of the random number generator is
|
|
* important. The library supplies 256 streams of random numbers; use
|
|
* SelectStream(s) to switch between streams indexed s = 0,1,...,255.
|
|
*
|
|
* The streams must be initialized. The recommended way to do this is by
|
|
* using the function PlantSeeds(x) with the value of x used to initialize
|
|
* the default stream and all other streams initialized automatically with
|
|
* values dependent on the value of x. The following convention is used
|
|
* to initialize the default stream:
|
|
* if x > 0 then x is the state
|
|
* if x < 0 then the state is obtained from the system clock
|
|
* if x = 0 then the state is to be supplied interactively.
|
|
*
|
|
* The generator used in this library is a so-called 'Lehmer random number
|
|
* generator' which returns a pseudo-random number uniformly distributed
|
|
* 0.0 and 1.0. The period is (m - 1) where m = 2,147,483,647 and the
|
|
* smallest and largest possible values are (1 / m) and 1 - (1 / m)
|
|
* respectively. For more details see:
|
|
*
|
|
* "Random Number Generators: Good Ones Are Hard To Find"
|
|
* Steve Park and Keith Miller
|
|
* Communications of the ACM, October 1988
|
|
*
|
|
* Name : rngs.c (Random Number Generation - Multiple Streams)
|
|
* Authors : Steve Park & Dave Geyer
|
|
* Language : ANSI C
|
|
* Latest Revision : 09-22-98
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include "rngs.h"
|
|
|
|
#define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */
|
|
#define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */
|
|
#define CHECK 399268537 /* DON'T CHANGE THIS VALUE */
|
|
#define STREAMS 256 /* # of streams, DON'T CHANGE THIS VALUE */
|
|
#define A256 22925 /* jump multiplier, DON'T CHANGE THIS VALUE */
|
|
#define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */
|
|
|
|
static long seed[STREAMS] = {DEFAULT}; /* current state of each stream */
|
|
static int stream = 0; /* stream index, 0 is the default */
|
|
static int initialized = 0; /* test for stream initialization */
|
|
|
|
|
|
double Random(void)
|
|
/* ----------------------------------------------------------------
|
|
* Random returns a pseudo-random real number uniformly distributed
|
|
* between 0.0 and 1.0.
|
|
* ----------------------------------------------------------------
|
|
*/
|
|
{
|
|
const long Q = MODULUS / MULTIPLIER;
|
|
const long R = MODULUS % MULTIPLIER;
|
|
long t;
|
|
|
|
t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q);
|
|
if (t > 0)
|
|
seed[stream] = t;
|
|
else
|
|
seed[stream] = t + MODULUS;
|
|
return ((double) seed[stream] / MODULUS);
|
|
}
|
|
|
|
|
|
void PlantSeeds(long x)
|
|
/* ---------------------------------------------------------------------
|
|
* Use this function to set the state of all the random number generator
|
|
* streams by "planting" a sequence of states (seeds), one per stream,
|
|
* with all states dictated by the state of the default stream.
|
|
* The sequence of planted states is separated one from the next by
|
|
* 8,367,782 calls to Random().
|
|
* ---------------------------------------------------------------------
|
|
*/
|
|
{
|
|
const long Q = MODULUS / A256;
|
|
const long R = MODULUS % A256;
|
|
int j;
|
|
int s;
|
|
|
|
initialized = 1;
|
|
s = stream; /* remember the current stream */
|
|
SelectStream(0); /* change to stream 0 */
|
|
PutSeed(x); /* set seed[0] */
|
|
stream = s; /* reset the current stream */
|
|
for (j = 1; j < STREAMS; j++) {
|
|
x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q);
|
|
if (x > 0)
|
|
seed[j] = x;
|
|
else
|
|
seed[j] = x + MODULUS;
|
|
}
|
|
}
|
|
|
|
|
|
void PutSeed(long x)
|
|
/* ---------------------------------------------------------------
|
|
* Use this function to set the state of the current random number
|
|
* generator stream according to the following conventions:
|
|
* if x > 0 then x is the state (unless too large)
|
|
* if x < 0 then the state is obtained from the system clock
|
|
* if x = 0 then the state is to be supplied interactively
|
|
* ---------------------------------------------------------------
|
|
*/
|
|
{
|
|
char ok = 0;
|
|
|
|
if (x > 0)
|
|
x = x % MODULUS; /* correct if x is too large */
|
|
if (x < 0)
|
|
x = ((unsigned long) time((time_t *) NULL)) % MODULUS;
|
|
if (x == 0)
|
|
while (!ok) {
|
|
printf("\nEnter a positive integer seed (9 digits or less) >> ");
|
|
scanf("%ld", &x);
|
|
ok = (0 < x) && (x < MODULUS);
|
|
if (!ok)
|
|
printf("\nInput out of range ... try again\n");
|
|
}
|
|
seed[stream] = x;
|
|
}
|
|
|
|
|
|
void GetSeed(long *x)
|
|
/* ---------------------------------------------------------------
|
|
* Use this function to get the state of the current random number
|
|
* generator stream.
|
|
* ---------------------------------------------------------------
|
|
*/
|
|
{
|
|
*x = seed[stream];
|
|
}
|
|
|
|
|
|
void SelectStream(int index)
|
|
/* ------------------------------------------------------------------
|
|
* Use this function to set the current random number generator
|
|
* stream -- that stream from which the next random number will come.
|
|
* ------------------------------------------------------------------
|
|
*/
|
|
{
|
|
stream = ((unsigned int) index) % STREAMS;
|
|
if ((initialized == 0) && (stream != 0)) /* protect against */
|
|
PlantSeeds(DEFAULT); /* un-initialized streams */
|
|
}
|
|
|
|
|
|
void TestRandom(void)
|
|
/* ------------------------------------------------------------------
|
|
* Use this (optional) function to test for a correct implementation.
|
|
* ------------------------------------------------------------------
|
|
*/
|
|
{
|
|
long i;
|
|
long x;
|
|
/*double u;*/ /* used to be uncommented */
|
|
char ok = 0;
|
|
|
|
SelectStream(0); /* select the default stream */
|
|
PutSeed(1); /* and set the state to 1 */
|
|
for(i = 0; i < 10000; i++)
|
|
Random(); /* used to have u = Random() */
|
|
GetSeed(&x); /* get the new state value */
|
|
ok = (x == CHECK); /* and check for correctness */
|
|
|
|
SelectStream(1); /* select stream 1 */
|
|
PlantSeeds(1); /* set the state of all streams */
|
|
GetSeed(&x); /* get the state of stream 1 */
|
|
ok = ok && (x == A256); /* x should be the jump multiplier */
|
|
if (ok)
|
|
printf("\n The implementation of rngs.c is correct.\n\n");
|
|
else
|
|
printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n");
|
|
}
|