00001 /* ------------------------------------------------------------------------- 00002 * This is an ANSI C library for multi-stream random number generation. 00003 * The use of this library is recommended as a replacement for the ANSI C 00004 * rand() and srand() functions, particularly in simulation applications 00005 * where the statistical 'goodness' of the random number generator is 00006 * important. The library supplies 256 streams of random numbers; use 00007 * SelectStream(s) to switch between streams indexed s = 0,1,...,255. 00008 * 00009 * The streams must be initialized. The recommended way to do this is by 00010 * using the function PlantSeeds(x) with the value of x used to initialize 00011 * the default stream and all other streams initialized automatically with 00012 * values dependent on the value of x. The following convention is used 00013 * to initialize the default stream: 00014 * if x > 0 then x is the state 00015 * if x < 0 then the state is obtained from the system clock 00016 * if x = 0 then the state is to be supplied interactively. 00017 * 00018 * The generator used in this library is a so-called 'Lehmer random number 00019 * generator' which returns a pseudo-random number uniformly distributed 00020 * 0.0 and 1.0. The period is (m - 1) where m = 2,147,483,647 and the 00021 * smallest and largest possible values are (1 / m) and 1 - (1 / m) 00022 * respectively. For more details see: 00023 * 00024 * "Random Number Generators: Good Ones Are Hard To Find" 00025 * Steve Park and Keith Miller 00026 * Communications of the ACM, October 1988 00027 * 00028 * Name : rngs.c (Random Number Generation - Multiple Streams) 00029 * Authors : Steve Park & Dave Geyer 00030 * Language : ANSI C 00031 * Latest Revision : 09-22-98 00032 * ------------------------------------------------------------------------- 00033 */ 00034 00035 #include <stdio.h> 00036 #include <time.h> 00037 00038 #define __RANDOM_CPP 00039 #include "random.h" 00040 00041 #define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */ 00042 #define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */ 00043 #define CHECK 399268537 /* DON'T CHANGE THIS VALUE */ 00044 #define STREAMS 256 /* # of streams, DON'T CHANGE THIS VALUE */ 00045 #define A256 22925 /* jump multiplier, DON'T CHANGE THIS VALUE */ 00046 #define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */ 00047 00048 static long seed[STREAMS] = {DEFAULT}; /* current state of each stream */ 00049 static int stream = 0; /* stream index, 0 is the default */ 00050 static int initialized = 0; /* test for stream initialization */ 00051 00052 00053 double Random(void) 00054 /* ---------------------------------------------------------------- 00055 * Random returns a pseudo-random real number uniformly distributed 00056 * between 0.0 and 1.0. 00057 * ---------------------------------------------------------------- 00058 */ 00059 { 00060 const long Q = MODULUS / MULTIPLIER; 00061 const long R = MODULUS % MULTIPLIER; 00062 long t; 00063 00064 t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q); 00065 if (t > 0) 00066 seed[stream] = t; 00067 else 00068 seed[stream] = t + MODULUS; 00069 return ((double) seed[stream] / MODULUS); 00070 } 00071 00072 00073 void PlantSeeds(long x) 00074 /* --------------------------------------------------------------------- 00075 * Use this function to set the state of all the random number generator 00076 * streams by "planting" a sequence of states (seeds), one per stream, 00077 * with all states dictated by the state of the default stream. 00078 * The sequence of planted states is separated one from the next by 00079 * 8,367,782 calls to Random(). 00080 * --------------------------------------------------------------------- 00081 */ 00082 { 00083 const long Q = MODULUS / A256; 00084 const long R = MODULUS % A256; 00085 int j; 00086 int s; 00087 00088 initialized = 1; 00089 s = stream; /* remember the current stream */ 00090 SelectStream(0); /* change to stream 0 */ 00091 PutSeed(x); /* set seed[0] */ 00092 stream = s; /* reset the current stream */ 00093 for (j = 1; j < STREAMS; j++) { 00094 x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q); 00095 if (x > 0) 00096 seed[j] = x; 00097 else 00098 seed[j] = x + MODULUS; 00099 } 00100 } 00101 00102 00103 int nextInteger( int range,const char *file, int line ) 00104 { 00105 int val = (int)(Random( ) * range); 00106 // printf( "nextInt() called from %s line %d - returning %d\n", file, line, val ); 00107 00108 return val; 00109 00110 } 00111 void PutSeed(long x) 00112 /* --------------------------------------------------------------- 00113 * Use this function to set the state of the current random number 00114 * generator stream according to the following conventions: 00115 * if x > 0 then x is the state (unless too large) 00116 * if x < 0 then the state is obtained from the system clock 00117 * if x = 0 then the state is to be supplied interactively 00118 * --------------------------------------------------------------- 00119 */ 00120 { 00121 char ok = 0; 00122 00123 if (x > 0) 00124 x = x % MODULUS; /* correct if x is too large */ 00125 if (x < 0) 00126 x = ((unsigned long) time((time_t *) NULL)) % MODULUS; 00127 if (x == 0) 00128 while (!ok) { 00129 printf("\nEnter a positive integer seed (9 digits or less) >> "); 00130 scanf("%ld", &x); 00131 ok = (0 < x) && (x < MODULUS); 00132 if (!ok) 00133 printf("\nInput out of range ... try again\n"); 00134 } 00135 seed[stream] = x; 00136 } 00137 00138 00139 void GetSeed(long *x) 00140 /* --------------------------------------------------------------- 00141 * Use this function to get the state of the current random number 00142 * generator stream. 00143 * --------------------------------------------------------------- 00144 */ 00145 { 00146 *x = seed[stream]; 00147 } 00148 00149 00150 void SelectStream(int index) 00151 /* ------------------------------------------------------------------ 00152 * Use this function to set the current random number generator 00153 * stream -- that stream from which the next random number will come. 00154 * ------------------------------------------------------------------ 00155 */ 00156 { 00157 stream = ((unsigned int) index) % STREAMS; 00158 if ((initialized == 0) && (stream != 0)) /* protect against */ 00159 PlantSeeds(DEFAULT); /* un-initialized streams */ 00160 } 00161 00162 00163 void TestRandom(void) 00164 /* ------------------------------------------------------------------ 00165 * Use this (optional) function to test for a correct implementation. 00166 * ------------------------------------------------------------------ 00167 */ 00168 { 00169 long i; 00170 long x; 00171 double u; 00172 char ok = 0; 00173 00174 SelectStream(0); /* select the default stream */ 00175 PutSeed(1); /* and set the state to 1 */ 00176 for(i = 0; i < 10000; i++) 00177 u = Random(); 00178 GetSeed(&x); /* get the new state value */ 00179 ok = (x == CHECK); /* and check for correctness */ 00180 00181 SelectStream(1); /* select stream 1 */ 00182 PlantSeeds(1); /* set the state of all streams */ 00183 GetSeed(&x); /* get the state of stream 1 */ 00184 ok = ok && (x == A256); /* x should be the jump multiplier */ 00185 if (ok) 00186 printf("\n The implementation of rngs.c is correct.\n\n"); 00187 else 00188 printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n"); 00189 }
1.4.2