/**
   @file      gmpLCG.c
   @author    Mitch Richling <https://www.mitchr.me/>
   @Copyright Copyright 2005 by Mitch Richling.  All rights reserved.
   @brief     General implementation of an LCG with GMP.@EOL
   @Keywords  none
   @Std       C89

              General implementation of an LCG (Linear Congruential
              Generator) utilizing the simplest of algorithms, but
              making use of GMP to avoid overflow.

              GMP can be a powerful tool allowing the algorithm
              designer to focus on the algorithm in the early phases
              of algorithm design, and avoid the the vulgarities of
              machine arithmetic during this "deep thought" phase of
              development.  The designer is then free, after getting
              the algorithm to work, to focus on efficiency issues.

              Imagine for a moment that we had just discovered the
              LCG, and wanted to explore the algorithm.  Yes, several
              ways exist to implement specialized LCGs with 32-bit
              signed arithmetic; however, GMP allows us to use a
              straight forward algorithm right out of the gate.  We
              could test our new algorithm out without being forced to
              set down and think about how to implement the thing in
              32-bit arithmetic.  When we were done testing, we could
              then work on an optimal 32-bit implementation and use
              our GMP prototype to verify that our new and improved
              32-bit algorithm actually was correct.
*/

#include <stdlib.h>             /* Standard Lib    ISOC  */
#include <stdio.h>              /* I/O lib         ISOC  */
#include <stdarg.h>             /* Variable args   ISOC  */
#include <gmp.h>                /* GNU GMP Library       */

int main (void) {
  int               i;          /* Loop variable                 */
  mpz_t             randNumMPZ; /* For intermediate computations */
  unsigned long int randNumINT; /* For final computation results */

  /* Set the constants for the minimal standard LCG */
  const unsigned int M = 2147483647;
  const unsigned int A = 16807;
  const unsigned int B = 0;
  const unsigned int S = 1;

  /* Set initial seed */
  mpz_init_set_ui(randNumMPZ, S);

  printf( "10 numbers from LCG(%d, %d, %d, %d):\n", M, A, B, S);
  for ( i = 0; i < 10; i++ ) {
    /* Compute: randNumMPZ = (A*randNumMPZ+C)%M */
    mpz_mul_si(randNumMPZ, randNumMPZ, A);
    mpz_add_ui(randNumMPZ, randNumMPZ, B);
    randNumINT = (unsigned long int)mpz_mod_ui(randNumMPZ, randNumMPZ, M);
    printf( "%12lu\n", randNumINT);
  } /* end for */

  return 0;
} /* end func: main */