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 #include "random.h" 00038 00039 #define MODULUS 2147483647 /* DON'T CHANGE THIS VALUE */ 00040 #define MULTIPLIER 48271 /* DON'T CHANGE THIS VALUE */ 00041 #define CHECK 399268537 /* DON'T CHANGE THIS VALUE */ 00042 #define STREAMS 256 /* # of streams, DON'T CHANGE THIS VALUE */ 00043 #define A256 22925 /* jump multiplier, DON'T CHANGE THIS VALUE */ 00044 #define DEFAULT 123456789 /* initial seed, use 0 < DEFAULT < MODULUS */ 00045 00046 static long seed[STREAMS] = {DEFAULT}; /* current state of each stream */ 00047 static int stream = 0; /* stream index, 0 is the default */ 00048 static int initialized = 0; /* test for stream initialization */ 00049 00050 00051 double Random(void) 00052 /* ---------------------------------------------------------------- 00053 * Random returns a pseudo-random real number uniformly distributed 00054 * between 0.0 and 1.0. 00055 * ---------------------------------------------------------------- 00056 */ 00057 { 00058 const long Q = MODULUS / MULTIPLIER; 00059 const long R = MODULUS % MULTIPLIER; 00060 long t; 00061 00062 t = MULTIPLIER * (seed[stream] % Q) - R * (seed[stream] / Q); 00063 if (t > 0) 00064 seed[stream] = t; 00065 else 00066 seed[stream] = t + MODULUS; 00067 return ((double) seed[stream] / MODULUS); 00068 } 00069 00070 00071 void PlantSeeds(long x) 00072 /* --------------------------------------------------------------------- 00073 * Use this function to set the state of all the random number generator 00074 * streams by "planting" a sequence of states (seeds), one per stream, 00075 * with all states dictated by the state of the default stream. 00076 * The sequence of planted states is separated one from the next by 00077 * 8,367,782 calls to Random(). 00078 * --------------------------------------------------------------------- 00079 */ 00080 { 00081 const long Q = MODULUS / A256; 00082 const long R = MODULUS % A256; 00083 int j; 00084 int s; 00085 00086 initialized = 1; 00087 s = stream; /* remember the current stream */ 00088 SelectStream(0); /* change to stream 0 */ 00089 PutSeed(x); /* set seed[0] */ 00090 stream = s; /* reset the current stream */ 00091 for (j = 1; j < STREAMS; j++) { 00092 x = A256 * (seed[j - 1] % Q) - R * (seed[j - 1] / Q); 00093 if (x > 0) 00094 seed[j] = x; 00095 else 00096 seed[j] = x + MODULUS; 00097 } 00098 } 00099 00100 00101 void PutSeed(long x) 00102 /* --------------------------------------------------------------- 00103 * Use this function to set the state of the current random number 00104 * generator stream according to the following conventions: 00105 * if x > 0 then x is the state (unless too large) 00106 * if x < 0 then the state is obtained from the system clock 00107 * if x = 0 then the state is to be supplied interactively 00108 * --------------------------------------------------------------- 00109 */ 00110 { 00111 char ok = 0; 00112 00113 if (x > 0) 00114 x = x % MODULUS; /* correct if x is too large */ 00115 if (x < 0) 00116 x = ((unsigned long) time((time_t *) NULL)) % MODULUS; 00117 if (x == 0) 00118 while (!ok) { 00119 printf("\nEnter a positive integer seed (9 digits or less) >> "); 00120 scanf("%ld", &x); 00121 ok = (0 < x) && (x < MODULUS); 00122 if (!ok) 00123 printf("\nInput out of range ... try again\n"); 00124 } 00125 seed[stream] = x; 00126 } 00127 00128 00129 void GetSeed(long *x) 00130 /* --------------------------------------------------------------- 00131 * Use this function to get the state of the current random number 00132 * generator stream. 00133 * --------------------------------------------------------------- 00134 */ 00135 { 00136 *x = seed[stream]; 00137 } 00138 00139 00140 void SelectStream(int index) 00141 /* ------------------------------------------------------------------ 00142 * Use this function to set the current random number generator 00143 * stream -- that stream from which the next random number will come. 00144 * ------------------------------------------------------------------ 00145 */ 00146 { 00147 stream = ((unsigned int) index) % STREAMS; 00148 if ((initialized == 0) && (stream != 0)) /* protect against */ 00149 PlantSeeds(DEFAULT); /* un-initialized streams */ 00150 } 00151 00152 00153 void TestRandom(void) 00154 /* ------------------------------------------------------------------ 00155 * Use this (optional) function to test for a correct implementation. 00156 * ------------------------------------------------------------------ 00157 */ 00158 { 00159 long i; 00160 long x; 00161 double u; 00162 char ok = 0; 00163 00164 SelectStream(0); /* select the default stream */ 00165 PutSeed(1); /* and set the state to 1 */ 00166 for(i = 0; i < 10000; i++) 00167 u = Random(); 00168 GetSeed(&x); /* get the new state value */ 00169 ok = (x == CHECK); /* and check for correctness */ 00170 00171 SelectStream(1); /* select stream 1 */ 00172 PlantSeeds(1); /* set the state of all streams */ 00173 GetSeed(&x); /* get the state of stream 1 */ 00174 ok = ok && (x == A256); /* x should be the jump multiplier */ 00175 if (ok) 00176 printf("\n The implementation of rngs.c is correct.\n\n"); 00177 else 00178 printf("\n\a ERROR -- the implementation of rngs.c is not correct.\n\n"); 00179 }
1.4.2