home *** CD-ROM | disk | FTP | other *** search
- /* n2rand.c - NeuralWare Standard Random Number Generator */
- /* Version 1.1 of 6 March 1990 */
-
- /************************************************************************
- * *
- * Random Number Generator for NeuralWare Products *
- * *
- ************************************************************************
- 05-Dec-90 cck
- Modified n2rand.c and n2rand.h for stand-alone operation and
- easy integration with flash code.
- Moved RRand() and GRand() from n2fl_sum.c to n2rand.c
- */
-
- /* Its purpose is to provide a standard random number generator across all */
- /* products that NeuralWare sells and supports. */
-
- /* This code derived from Knuth, The Art of Computer Programming, Vol2, */
- /* Seminumerical Algorithms; Sedgewick, Algorithms; and Press, Flannery, */
- /* Teukolsky, and Vetterling, Numerical Recipes in C */
-
- /* The concept is to use one type of generator, a linear congruential */
- /* generator, to fill an array with random numbers. We then shuffle that */
- /* array, and then take the difference between two of those random numbers */
- /* in the array. That value is returned to the user, and also used to */
- /* replace one of the numbers in the random number array. */
-
- /* NRAND Returns a uniform random deviate between 0 and MAXRAND-1. */
- /* Call NRAND as so: (SL) new_deviate = nrand(); */
-
- /* SRAND Sets seed of random sequence to another part of the sequence. */
- /* Call SRAND as so: SRAND( (SL) mi_random_seed ); */
-
- #include <math.h>
-
- #include "n2rand.h" /* defines MAXRAND & others */
-
- static long rand_array[56]; /* Lookup table of random numbers */
- static long first_gen, second_gen; /* Result for the LCG */
- static int table_index, loop; /* Index into random number table */
- static int first_time_flag = 1; /* First time thru flag -
- initially true */
- static int cursor_1, cursor_2, i; /* Cursors to chose random #'s from
- lookup table of random #'s */
- /* */
- /************************************************************************
- * *
- * set_rand() - Random number seed *
- * *
- ************************************************************************
- */
-
- #ifdef PROTOTYPING
- void set_rand( long seed )
- #else
- void set_rand( seed )
- long seed;
- #endif
- {
- /* Reset first_time_flag on the first call */
- if ( first_time_flag ) {
- /* Now reset first time flag */
- first_time_flag = 0; /* now false */
- }
-
- /* Now test & correct seed value */
- first_gen = MSEED - (seed < 0 ? -seed : seed);
- first_gen %= MAXRAND;
- rand_array[55] = first_gen;
- second_gen = 1;
-
- /* Now initialize the shuffle table */
- /* We use a linear congruential generator to set up initial table */
- for ( table_index = 1; table_index <= 54; table_index++)
- {
- i = (21*table_index) % 55;
- rand_array[i] = second_gen;
- second_gen = first_gen - second_gen;
- if ( second_gen < MZ ) second_gen += MAXRAND;
- first_gen = rand_array[i];
- } /* End of for table_index = 1 to 54 */
-
- /* Now randomize the table */
- for (loop=1; loop<=4; loop++)
- {
- for ( table_index=1; table_index <= 55; table_index++)
- {
- rand_array[table_index] -= rand_array[1 +
- (table_index+30) % 55];
- if ( rand_array[table_index] < MZ ) rand_array[table_index]
- += MAXRAND;
- }
- }
-
- /* Finish up any remaining bits */
-
- cursor_1 = 0; /* init cursors into random # table */
- cursor_2 = 31;
-
-
- } /* End of initialization/setup code (if first_time true or reinit) */
- /* */
- /************************************************************************
- * *
- * nrand() - NeuralWare Random Number Generator *
- * *
- ************************************************************************
- */
-
- long nrand()
- {
- /* Retrieve random number & generate a new replacement value */
- /* Initialize on the first call, if not already initialized by set_rand */
- if ( first_time_flag ) {
- set_rand(0);
- /* Now reset first time flag */
- first_time_flag = 0; /* now false */
- }
-
- if (++cursor_1 == 56) cursor_1 = 1; /* rollover so 1 to 55 */
- if (++cursor_2 == 56) cursor_2 = 1; /* rollover so 1 to 55 */
-
- /* now get diff of 2 random #'s */
- first_gen = rand_array[cursor_1]-rand_array[cursor_2];
-
- /* correct for rollover */
- if ( first_gen < MZ ) first_gen += MAXRAND;
-
- /* replace old random # */
- rand_array[cursor_1] = first_gen;
-
- /* and return random # to user */
- return first_gen;
- }
- /* */
- /************************************************************************
- * *
- * RRand(), GRand - real random number *
- * *
- * RRand - Uniform Distribution *
- * GRand - Gaussian Distribution *
- * *
- ************************************************************************
- */
-
- double RRand( lv, hv )
- double lv, hv; /* low / high limits */
- {
- double rv; /* return value */
-
- rv = nrand() * RANDINV; /* rand() / whatever value is needed */
-
- rv = (hv - lv) * rv + lv; /* range adjusted */
-
- return( rv );
- }
-
- double GRand( lv, hv )
- double lv, hv; /* low / high limits */
- {
- static int k=0; /* k=0 need to caluclate g0 & g1,
- * k=1 g1 already calculated */
- static double g0,g1; /* Gaussian(0,1) random variables */
- double u0,u1; /* uniforms on -1 to 1 */
- double r2; /* radius from (0,0) to (u0,u1) */
- double x,y; /* intermediate calculations */
-
- if( k ) {
- k = 0;
- return( 0.5 * (hv - lv) * g1 + 0.5 * (hv + lv) );
- } else {
- k = 1;
- /* find two U(-1,1)'s that are independent and lie within unit circle
- * using NeuralWare's stanard uniform generator
- */
- u1 = 2.0 * (nrand() * RANDINV) - 1.0;
- y = u1 * u1;
- for(r2=2.0; r2>1.0; ) {
- u0 = u1;
- r2 = y;
- u1 = 2.0 * (nrand() * RANDINV) - 1.0;
- y = u1 * u1;
- r2 += y;
- }
- /* now get two Gaussian(0,1) */
- x = sqrt( ( -2.0 * log(r2) )/ r2 );
- g0 = u0 * x;
- g1 = u1 * x;
- return( 0.5 * (hv - lv) * g0 + 0.5 * (hv + lv) );
- }
- }
- /* */
- /************************************************************************
- * *
- * Test Routine for Random Number Generator *
- * *
- ************************************************************************
- */
- #ifdef TEST_RAN
-
- /* The following code is a simple test harness for the random number */
- /* generator. This was derived from Sedgewick, Algorithms, Addison-Wesley, */
- /* 1984. */
-
- #include "usermath.h"
-
- #define R_MAX 2000 /* This implies up to 2000 values in histogram */
-
- SREAL chi_square( N, r )
- UL N, r;
-
- /*
- This routine calculates the sum of the squares of the frequencies
- of occurence of each random index produced via nrand. The sum is
- then scaled by the expected frequency of occurence, and normalized
- by the size of the sequence.
- */
-
- /*
- N is the total number of random numbers we wish to generate
- r is the range we wish to produce random number in; The numbers
- generated range from 0 thru r-1.
-
- A good fit is indicated by how close this 'Chi-Square' is to the
- expected value, i.e. for 10000 random numbers ranging between 1 &
- 100, a 'good' Chi-square would be around 100 in value
- */
-
- {
- static long f[R_MAX];
- static long i, index;
- static SREAL temp, t1, t2;
-
- /* First clear out the histogram array */
- for (index=0; index<R_MAX; index++) f[index] = 0;
-
- /* Now accumulate a histogram of times a given index is produced */
- for (i=0; i<N; i++) {
-
- #if 1 /* set this 1 to test Neuralware generator */
-
- t1 = nrand();
- t2 = r;
- index = (t1*t2)*RANDINV;
- #endif
-
- #if 0 /* set this 1 to test alternate generator */
- t1 = random();
- t2 = r;
- index = (t1*t2)/2147483647.0;
- #endif
-
- if ( index >= R_MAX || index < 0 ) {
- printf("ERROR - Chi-square, index = %d\n",i);
- index = 0;
- };
- f[index] = f[index] + 1;
- }
-
- /* Now calculate the Chi Square of those frequencies */
- /* We use floating point calculations to see any patterns in low order bits */
- t1 = 0.0;
- t2 = r;
-
- for (i=0; i<=r-1 ; i++)
- t1 = t1 + (f[i]-(N/r))*(f[i]-(N/r));
-
- temp = ((t2*t1)/N);
-
- return temp;
-
- }
-
- #ifdef __ZTC__ /* if Zortech C */
- #include <time.h>
- #endif
-
- main()
- #define SAMPLE_SIZE 1000
- #define RANGE 100
- #define NTRIALS 10
- {
- NINT i; /* loop index */
- SREAL temp[NTRIALS]; /* temporary store */
- SL seed; /* seed for random number generator */
-
- #ifdef __ZTC__ /* if Zortech C */
- time_t start, finish; /* data structures to measure run time of rand funct */
- #endif
-
- /* First reseed random number generator */
- seed = 0;
- set_rand(seed);
-
- /* Second, start the loop for Ntrials of random numbers */
-
- #ifdef __ZTC__ /* if Zortech C */
- time (&start);
- for (i=0; i< NTRIALS; i++) {
- temp[i] = chi_square(SAMPLE_SIZE, RANGE);
- }
- time(&finish);
- #else
- for (i=0; i< NTRIALS; i++) {
- temp[i] = chi_square(SAMPLE_SIZE, RANGE);
- }
- #endif
-
- /* Third, print out the duration per call & CHI square values */
-
- #ifdef __ZTC__ /* if Zortech C */
- printf("time per Random call %2.10f seconds\n",
- (difftime(finish, start)/SAMPLE_SIZE));
- #endif
-
- for (i=0; i< NTRIALS; i++)
- printf("Trial # %d CHI Square = %f\n",i,temp[i]);
-
-
-
- }
- #endif /* ifdef TEST_RAN */
-
-
-