Listing 3 Combination multiplicative random number generator

/*  rand_com[b].c
       subtract two random numbers modulo moduli1-1 and shuffle
    see
       L'Ecuyer, Comm. of the ACM 1988 vol. 31
       Numerical Recipes in C, 2nd edition, pp. 278-86
       shuffling -- Knuth, vol. II
    Copyright (c) 1994, 1995 by Gerald P. Dwyer, Jr.
*/

#include        <time.h>
#include        <stdlib.h>
#include        <float.h>
#include        <assert.h>

#define TESTING

#define TRUE (-1)
#define FALSE 0

void init_rand_comb(long *seed1, long *seed2) ;
long get_init_rand(int) ;
long rand_comb(void);
long genr_rand_diff(void);
long    genr_rand(long a, long x, long modulus, long q, long r) ;

            /* first generator */
#define MOD1         2147483563L  /* modulus */
#define MULT1        40014L       /* multiplier */
            /* modulus=multiplier*quotient+remainder */
#define Q1           53668L       /* quotient =[modulus/multiplier] */
#define R1           12211L       /* remainder */

            /* second generator */
#define MOD2          2147483399L
#define MULT2         40692L
#define Q2            52774L
#define R2            3791L

#define MOD_COMB      (MOD1-1)

#define MIN_VALUE1    1
#define MAX_VALUE1    (MOD1-1)
#define MIN_VALUE2    1
#define MAX_VALUE2    (MOD2-1)
#define MAX_VALUE     ( (MOD1<MOD2) ? MAX_VALUE1 : MAX_VALUE2)
#define EXP_VAL       804307721L

#define GENR1(init_rand)       genr_rand(MULT1, init_rand, MOD1, Q1, R1)
#define GENR2(init_rand)       genr_rand(MULT2, init_rand, MOD2, Q2, R2)

#define IMPOSSIBLE_RAND (-1)
#define STARTUP_RANDS   16   /* throw away initial draws */
#define DIM_RAND        150  /* size of array shuffled */

static long rand1, rand2 ;
static long rand_num = IMPOSSIBLE_RAND ;
static long rands[DIM_RAND];


/* initialize generators with seeds
   fill rands[] with initial values */
void init_rand_comb(long *seed1, long *seed2)
{
   extern long rand1, rand2 ;
   extern long rand_num;
   extern long rands[] ;
   int i ;

   if (*seed1 <= 0 || *seed1 > MAX_VALUE1)
      *seed1 = get_init_rand(MAX_VALUE1);
   if (*seed2 <= 0 || *seed2 > MAX_VALUE2)
      *seed2 = get_init_rand(MAX_VALUE2);

                   /* seed the routine */
   rand1 = *seed1;
   rand2 = *seed2;
   genr_rand_diff() ;

   for (i = 1; i < STARTUP_RANDS; i++)    /* throw some away */
      genr_rand_diff() ;
                /* fill the array of randum number values */
   for (i = 0; i < DIM_RAND; i++)
      rands[i] = genr_rand_diff() ;
                /* initialize rand_num for shuffling */
   rand_num = rands[DIM_RAND-1] ;
}


/* get a long initial seed for generator
   assumes that rand returns a short integer */
long get_init_rand(int max_value)
{
   long seed;

   srand((unsigned int)time(NULL)) ;  /* initialize system generator */
   do {
      seed = ((long)rand())*rand() ;
      seed += ((long)rand())*rand() ;
   } while (seed > max_value);

   assert(seed > 0) ;
   return seed ;
}


/* generate the difference between random numbers
   assumes  0 < rand1     < MOD1
          0 < rand2     < MOD2
   output   1 <= rand_num <= MOD_COMB */
long genr_rand_diff(void)
{
   extern long rand1, rand2;
   long rand_new ;

   rand1 = GENR1(rand1) ;
   rand2 = GENR2(rand2) ;
   rand_new = rand1 - rand2 ;
   if (rand_new <= 0)
      rand_new += MOD_COMB ;

   assert(rand_new >= 1 && rand_new <= MOD_COMB) ;

   return rand_new ;
}


/* generate the next value in sequence from generator
   uses approximate factoring
   residue = (a * x) mod modulus
          = a*x - [(a*x)/modulus]*modulus

   where
      [(a*x)/modulus] = integer less than or equal to (a*x)/modulus
   approximate factoring avoids overflow associated with a*x and
      uses equivalence of above with
   residue = a * (x - q * k) - r * k + (k-k1) * modulus
   where
      modulus = a * q + r
      q  = [modulus/a]
      k  = [x/q]               (=[ax/aq])
      k1 = [a*x/m]
   assumes
      a, m > 0
      0 < init_rand < modulus
      a * a <= modulus
      [a*x/a*q]-[a*x/modulus] <= 1
         (for only one addition of modulus below) */
long   genr_rand(long a, long x, long modulus, long q, long r)
{
   long k, residue ;

   k = x / q ;
   residue = a * (x - q * k) - r * k ;
   if (residue < 0)
      residue += modulus ;

   assert(residue >= 1 && residue <= modulus-1);

   return residue ;
}


/* get a random number from rands[] and replace it*/
long rand_comb(void)
{
   extern long rand_num ;
   extern long rands[] ;
   int i ;
             /* if not initialized, do it now */
   if (rand_num == IMPOSSIBLE_RAND) {
      rand_num = 1 ;
      init_rand_comb(&rand_num, &rand_num) ;
   }

   /* rand_num from previous call determines next rand_num from
      rands[] */
   i = (int) (((double)DIM_RAND*rand_num)/(double)(MAX_VALUE)) ;
   rand_num = rands[i] ;

      /* replace random number used */
   rands[i] = genr_rand_diff();

   return rand_num ;
}

#if  defined(TESTING)
/* Test the generator */
#include  <stdio.h>
void main(void)
{
   long seed1=1, seed2=1 ;
   int i ;

   init_rand_comb(&seed1, &seed2);
   printf("Seeds for random number generator are %ld   %ld\n",
          seed1, seed2) ;
   i = STARTUP_RANDS + DIM_RAND ;
   do {
      rand_comb();
      i++ ;
   } while (i < 9999) ;

   printf("On draw 10000, random number should be %ld\n", EXP_VAL) ;
   printf("On draw %d, random number is    %ld\n", i+1, rand_comb()) ;
}
#endif TESTING
/* End of File */