Prev Next mztuni.cpp Headings

C++ Marsaglia Zaman Tsang Uniform Random Number Source Code
 
*/
# include <cstddef>    // for size_t
# include <cassert>    // for assert
# include <ctime>      // for std::time and std::time_t
# include <mztuni.hpp> // routines implemented here
//
size_t mztuni_seed(size_t seed)
{    static size_t previous_seed = 0;
     if( seed == 0 )
          return previous_seed;
     //
     if( seed == 1 )
     {    // initialize the random number generator using the clock for a seed
          std::time_t* null_ptr = 0;
          std::time_t seconds   = std::time(null_ptr);
          seed                  = static_cast<size_t>( seconds );
          seed                  = seed % 796594175 + 3;
     }
     mztuni(seed - 1);
     previous_seed = seed;
     //
     return previous_seed;
}
double mztuni(size_t seedm1)
{    assert( seedm1 <= 796594176 );

     // define local mod function
     class mod_class {
     public:
          size_t operator()(size_t i, size_t j)
          {    return i % j; }
     };
     mod_class mod;
     //
     // static data that persists between function calls
     static double u[98], c, cd, cm;
     static size_t ip, jp;
     //
     if( seedm1 > 0 )
     {    size_t i, j, k, l, m;
          size_t stmp = seedm1;
          i    = mod(stmp, 168);
          stmp = stmp / 168;
          j    = mod(stmp, 168) + 1;
          stmp = stmp / 168;
          k    = mod(stmp, 168) + 1;
          stmp = stmp / 168;
          l    = mod(stmp, 168) + 1;
          assert( i != 1 || j != 1 || k != 1 || l != 1 );
          for(size_t ii = 1; ii <=97; ii++)
          {    double s = 0.0;
               double t = 0.5;
               for(size_t jj = 1; jj <= 24; jj++)
               {    m = mod( mod(i * j, 179) * k, 179 );
                    i = j;
                    j = k;
                    k = m;
                    l = mod(53 * l + 1, 169);
                    if( mod(l * m, 64) >= 32) 
                         s = s + t;
                    t = 0.5 * t;
               }
               u[ii] = s;
          }
          // There is a typo in the paper, where the fortran version has
          // CD =  7654321. / 167777216.;
          c  =   362436. / 16777216.;
          cd =  7654321. / 16777216.;
          cm = 16777213. / 16777216.;
          ip = 97;
          jp = 33;
          //
          return 0.0;
     }
     double uni = u[ip] - u[jp];
     if(uni < 0.0)
          uni = uni +  1.0;
     u[ip] = uni;
     //
     ip = ip - 1;
     if(ip == 0)
          ip = 97;
     //
     jp = jp - 1;
     if(jp == 0)
          jp = 97;
     //
     c = c - cd;
     if(c < 0.0)
          c = c + cm;
     //
     uni = uni - c;
     if(uni < 0.0)
          uni = uni + 1.0;
     return uni;
}

Input File: lib/mztuni.cpp