rng.cc

Go to the documentation of this file.
00001 /* -*-  Mode:C++; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
00002 /*
00003  *  File: RngStream.cc for multiple streams of Random Numbers 
00004  *  Copyright (C) 2001  Pierre L'Ecuyer (lecuyer@iro.umontreal.ca)
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00019  *  02110-1301 USA
00020  *
00021  *  Linking this random number generator statically or dynamically with
00022  *  other modules is making a combined work based on this random number
00023  *  generator.  Thus, the terms and conditions of the GNU General Public
00024  *  License cover the whole combination.
00025  *
00026  *  In addition, as a special exception, the copyright holders of this
00027  *  random number generator give you permission to combine this random
00028  *  number generator program with free software programs or libraries
00029  *  that are released under the GNU LGPL and with code included in the
00030  *  standard release of ns-2 under the Apache 2.0 license or under
00031  *  otherwise-compatible licenses with advertising requirements (or
00032  *  modified versions of such code, with unchanged license).  You may
00033  *  copy and distribute such a system following the terms of the GNU GPL
00034  *  for this random number generator and the licenses of the other code
00035  *  concerned, provided  that you include the source code of that other
00036  *  code when and as the GNU GPL requires distribution of source code.
00037  *
00038  *  Note that people who make modified versions of this random number
00039  *  generator are not obligated to grant this special exception for
00040  *  their modified versions; it is their choice whether to do so.
00041  *  The GNU General Public License gives permission to release a
00042  *  modified  version without this exception; this exception also makes
00043  *  it possible to release a modified version which carries forward
00044  *  this exception.
00045  *
00046  *  //Incorporated into rng.cc and modified to maintain backward
00047  *  //compatibility with ns-2.1b8.  Users can use their current scripts
00048  *  //unmodified with the new RNG.  To get the same results as with the
00049  *  //previous RNG, define OLD_RNG when compiling (e.g.,
00050  *  //make -D OLD_RNG).
00051  *  // - Michele Weigle, University of North Carolina
00052  *  // (mcweigle@cs.unc.edu)  October 10, 2001
00053  */
00054 
00055 #ifndef lint
00056 static const char rcsid[] =
00057 "@(#) $Header: /nfs/jade/vint/CVSROOT/ns-2/tools/rng.cc,v 1.30 2005/07/30 22:34:46 tomh Exp $ (LBL)";
00058 #endif
00059 
00060 /* new random number generator */
00061 
00062 #ifndef WIN32
00063 #include <sys/time.h>           // for gettimeofday
00064 #include <unistd.h>
00065 #endif
00066 
00067 #include <stdio.h>
00068 #ifndef OLD_RNG
00069 #include <string.h>
00070 #endif /* !OLD_RNG */
00071 #include "rng.h"
00072 
00073 #ifdef OLD_RNG
00074 /*
00075  * RNGImplementation
00076  */
00077 
00078 /*
00079  * Generate a periodic sequence of pseudo-random numbers with
00080  * a period of 2^31 - 2.  The generator is the "minimal standard"
00081  * multiplicative linear congruential generator of Park, S.K. and
00082  * Miller, K.W., "Random Number Generators: Good Ones are Hard to Find,"
00083  * CACM 31:10, Oct. 88, pp. 1192-1201.
00084  *
00085  * The algorithm implemented is:  Sn = (a*s) mod m.
00086  *   The modulus m can be approximately factored as: m = a*q + r,
00087  *   where q = m div a and r = m mod a.
00088  *
00089  * Then Sn = g(s) + m*d(s)
00090  *   where g(s) = a(s mod q) - r(s div q)
00091  *   and d(s) = (s div q) - ((a*s) div m)
00092  *
00093  * Observations:
00094  *   - d(s) is either 0 or 1.
00095  *   - both terms of g(s) are in 0, 1, 2, . . ., m - 1.
00096  *   - |g(s)| <= m - 1.
00097  *   - if g(s) > 0, d(s) = 0, else d(s) = 1.
00098  *   - s mod q = s - k*q, where k = s div q.
00099  *
00100  * Thus Sn = a(s - k*q) - r*k,
00101  *   if (Sn <= 0), then Sn += m.
00102  *
00103  * To test an implementation for A = 16807, M = 2^31-1, you should
00104  *   get the following sequences for the given starting seeds:
00105  *
00106  *   s0, s1,    s2,        s3,          . . . , s10000,     . . . , s551246 
00107  *    1, 16807, 282475249, 1622650073,  . . . , 1043618065, . . . , 1003 
00108  *    1973272912, 1207871363, 531082850, 967423018
00109  *
00110  * It is important to check for s10000 and s551246 with s0=1, to guard 
00111  * against overflow.
00112 */
00113 
00114 /*
00115  * The sparc assembly code [no longer here] is based on Carta, D.G., "Two Fast
00116  * Implementations of the 'Minimal Standard' Random Number
00117  * Generator," CACM 33:1, Jan. 90, pp. 87-88.
00118  *
00119  * ASSUME that "the product of two [signed 32-bit] integers (a, sn)
00120  *        will occupy two [32-bit] registers (p, q)."
00121  * Thus: a*s = (2^31)p + q
00122  *
00123  * From the observation that: x = y mod z is but
00124  *   x = z * the fraction part of (y/z),
00125  * Let: sn = m * Frac(as/m)
00126  *
00127  * For m = 2^31 - 1,
00128  *   sn = (2^31 - 1) * Frac[as/(2^31 -1)]
00129  *      = (2^31 - 1) * Frac[as(2^-31 + 2^-2(31) + 2^-3(31) + . . .)]
00130  *      = (2^31 - 1) * Frac{[(2^31)p + q] [2^-31 + 2^-2(31) + 2^-3(31) + . . 
00131 .]}
00132  *      = (2^31 - 1) * Frac[p+(p+q)2^-31+(p+q)2^-2(31)+(p+q)3^(-31)+ . . .]
00133  *
00134  * if p+q < 2^31:
00135  *   sn = (2^31 - 1) * Frac[p + a fraction + a fraction + a fraction + . . .]
00136  *      = (2^31 - 1) * [(p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .]
00137  *      = p + q
00138  *
00139  * otherwise:
00140  *   sn = (2^31 - 1) * Frac[p + 1.frac . . .]
00141  *      = (2^31 - 1) * (-1 + 1.frac . . .)
00142  *      = (2^31 - 1) * [-1 + (p+q)2^-31 + (p+q)2^-2(31) + (p+q)3^(-31) + . . .]
00143  *      = p + q - 2^31 + 1
00144  */
00145  
00146 
00147 #define A   16807L      /* multiplier, 7**5 */
00148 #define M   2147483647L /* modulus, 2**31 - 1; both used in random */
00149 #define INVERSE_M ((double)4.656612875e-10) /* (1.0/(double)M) */
00150 
00151 long
00152 RNGImplementation::next()
00153 {
00154     long L, H;
00155     L = A * (seed_ & 0xffff);
00156     H = A * (seed_ >> 16);
00157     
00158     seed_ = ((H & 0x7fff) << 16) + L;
00159     seed_ -= 0x7fffffff;
00160     seed_ += H >> 15;
00161     
00162     if (seed_ <= 0) {
00163         seed_ += 0x7fffffff;
00164     }
00165     return(seed_);
00166 }
00167 
00168 double
00169 RNGImplementation::next_double()
00170 {
00171     long i = next();
00172     return i * INVERSE_M;
00173 }
00174 #endif /* OLD_RNG */
00175 
00176 /*
00177  * RNG implements a nice front-end around RNGImplementation
00178  */
00179 #ifndef stand_alone
00180 static class RNGClass : public TclClass {
00181 public:
00182     RNGClass() : TclClass("RNG") {}
00183     TclObject* create(int, const char*const*) {
00184         return(new RNG());
00185     }
00186 } class_rng;
00187 #endif /* stand_alone */
00188 
00189 /* default RNG */
00190 
00191 RNG* RNG::default_ = NULL;
00192 
00193 double
00194 RNG::normal(double avg, double std)
00195 {
00196     static int parity = 0;
00197     static double nextresult;
00198     double sam1, sam2, rad;
00199    
00200     if (std == 0) return avg;
00201     if (parity == 0) {
00202         sam1 = 2*uniform() - 1;
00203         sam2 = 2*uniform() - 1;
00204         while ((rad = sam1*sam1 + sam2*sam2) >= 1) {
00205             sam1 = 2*uniform() - 1;
00206             sam2 = 2*uniform() - 1;
00207         }
00208         rad = sqrt((-2*log(rad))/rad);
00209         nextresult = sam2 * rad;
00210         parity = 1;
00211         return (sam1 * rad * std + avg);
00212     }
00213     else {
00214         parity = 0;
00215         return (nextresult * std + avg);
00216     }
00217 }
00218 
00219 #ifndef stand_alone
00220 int
00221 RNG::command(int argc, const char*const* argv)
00222 {
00223     Tcl& tcl = Tcl::instance();
00224 
00225     if (argc == 3) {
00226         if (strcmp(argv[1], "testint") == 0) {
00227             int n = atoi(argv[2]);
00228             tcl.resultf("%d", uniform(n));
00229             return (TCL_OK);
00230         }
00231         if (strcmp(argv[1], "testdouble") == 0) {
00232             double d = atof(argv[2]);
00233             tcl.resultf("%6e", uniform(d));
00234             return (TCL_OK);
00235         }
00236         if (strcmp(argv[1], "seed") == 0) {
00237             int s = atoi(argv[2]);
00238             // NEEDSWORK: should be a way to set seed to PRDEF_SEED_SOURCE
00239             if (s) {
00240                 if (s <= 0 || (unsigned int)s >= MAXINT) {
00241                     tcl.resultf("Setting random number seed to known bad value.");
00242                     return TCL_ERROR;
00243                 };
00244                 set_seed(RAW_SEED_SOURCE, s);
00245             } else set_seed(HEURISTIC_SEED_SOURCE, 0);
00246             return(TCL_OK);
00247         }
00248     } else if (argc == 2) {
00249         if (strcmp(argv[1], "next-random") == 0) {
00250             tcl.resultf("%u", uniform_positive_int());
00251             return(TCL_OK);
00252         }
00253         if (strcmp(argv[1], "seed") == 0) {
00254 #ifdef OLD_RNG
00255             tcl.resultf("%u", stream_.seed());
00256 #else
00257             tcl.resultf("%u", seed());
00258 #endif /* OLD_RNG */
00259             return(TCL_OK);
00260         }
00261 #ifndef OLD_RNG
00262         if (strcmp (argv[1], "next-substream") == 0) {
00263             reset_next_substream();
00264             return (TCL_OK);
00265         }
00266         if (strcmp (argv[1], "all-seeds") == 0) {
00267             unsigned long seeds[6];
00268             get_state (seeds);
00269             tcl.resultf ("%lu %lu %lu %lu %lu %lu",
00270                      seeds[0], seeds[1], seeds[2], 
00271                      seeds[3], seeds[4], seeds[5]);
00272             return (TCL_OK);
00273         }
00274         if (strcmp (argv[1], "reset-start-substream") == 0) {
00275             reset_start_substream();
00276             return (TCL_OK);
00277         }
00278 #endif /* !OLD_RNG */
00279         if (strcmp(argv[1], "default") == 0) {
00280             default_ = this;
00281             return(TCL_OK);
00282         }
00283         //#if 0
00284         if (strcmp(argv[1], "test") == 0) {
00285             RNGTest test; test.verbose_mil();
00286             //if (test())
00287             //  tcl.resultf("RNG test failed");
00288             //else
00289             //  tcl.resultf("RNG test passed");
00290             return(TCL_OK);
00291         }
00292         //#endif
00293     } else if (argc == 4) {
00294         if (strcmp(argv[1], "seed") == 0) {
00295             int s = atoi(argv[3]);
00296             if (strcmp(argv[2], "raw") == 0) {
00297                 set_seed(RNG::RAW_SEED_SOURCE, s);
00298             } else if (strcmp(argv[2], "predef") == 0) {
00299                 set_seed(RNG::PREDEF_SEED_SOURCE, s);
00300                 // s is the index in predefined seed array
00301                 // 0 <= s < 64
00302             } else if (strcmp(argv[2], "heuristic") == 0) {
00303                 set_seed(RNG::HEURISTIC_SEED_SOURCE, 0);
00304             }
00305             return(TCL_OK);
00306         }
00307         if (strcmp(argv[1], "normal") == 0) {
00308             double avg = strtod(argv[2], NULL);
00309             double std = strtod(argv[3], NULL);
00310             tcl.resultf("%g", normal(avg, std));
00311             return (TCL_OK);
00312         }
00313         if (strcmp(argv[1], "lognormal") == 0) {
00314             double avg = strtod(argv[2], NULL);
00315             double std = strtod(argv[3], NULL);
00316             tcl.resultf("%g", lognormal(avg, std));
00317             return (TCL_OK);
00318         }
00319     }
00320     return(TclObject::command(argc, argv));
00321 }
00322 #endif /* stand_alone */
00323 
00324 void
00325 RNG::set_seed(RNGSources source, int seed)
00326 {
00327     /* The following predefined seeds are evenly spaced around
00328      * the 2^31 cycle.  Each is approximately 33,000,000 elements
00329      * apart.
00330      */
00331 #define N_SEEDS_ 64
00332     static long predef_seeds[N_SEEDS_] = {
00333         1973272912L,  188312339L, 1072664641L,  694388766L,
00334         2009044369L,  934100682L, 1972392646L, 1936856304L,
00335         1598189534L, 1822174485L, 1871883252L,  558746720L,
00336         605846893L, 1384311643L, 2081634991L, 1644999263L,
00337         773370613L,  358485174L, 1996632795L, 1000004583L,
00338         1769370802L, 1895218768L,  186872697L, 1859168769L,
00339         349544396L, 1996610406L,  222735214L, 1334983095L,
00340         144443207L,  720236707L,  762772169L,  437720306L,
00341         939612284L,  425414105L, 1998078925L,  981631283L,
00342         1024155645L,  822780843L,  701857417L,  960703545L,
00343         2101442385L, 2125204119L, 2041095833L,   89865291L,
00344         898723423L, 1859531344L,  764283187L, 1349341884L,
00345         678622600L,  778794064L, 1319566104L, 1277478588L,
00346         538474442L,  683102175L,  999157082L,  985046914L,
00347         722594620L, 1695858027L, 1700738670L, 1995749838L,
00348         1147024708L,  346983590L,  565528207L,  513791680L
00349     };
00350     static long heuristic_sequence = 0;
00351 
00352     switch (source) {
00353     case RAW_SEED_SOURCE:
00354         if (seed <= 0 || (unsigned int)seed >= MAXINT)    // Wei Ye
00355             abort();
00356         // use it as it is
00357         break;
00358     case PREDEF_SEED_SOURCE:
00359         if (seed < 0 || seed >= N_SEEDS_)
00360             abort();
00361         seed = predef_seeds[seed];
00362         break;
00363     case HEURISTIC_SEED_SOURCE:
00364         timeval tv;
00365         gettimeofday(&tv, 0);
00366         heuristic_sequence++;   // Always make sure we're different than last time.
00367         seed = (tv.tv_sec ^ tv.tv_usec ^ (heuristic_sequence << 8)) & 0x7fffffff;
00368         break;
00369     };
00370     // set it
00371     // NEEDSWORK: should we throw out known bad seeds?
00372     // (are there any?)
00373     if (seed < 0)
00374         seed = -seed;
00375 #ifdef OLD_RNG
00376     stream_.set_seed(seed);
00377 #else
00378     set_seed(seed);
00379 #endif /* OLD_RNG */
00380 
00381     // Toss away the first few values of heuristic seed.
00382     // In practice this makes sequential heuristic seeds
00383     // generate different first values.
00384     //
00385     // How many values to throw away should be the subject
00386     // of careful analysis.  Until then, I just throw away
00387     // ``a bunch''.  --johnh
00388     if (source == HEURISTIC_SEED_SOURCE) {
00389         int i;
00390         for (i = 0; i < 128; i++) {
00391 #ifdef OLD_RNG          
00392             stream_.next();
00393 #else
00394             next();
00395 #endif /* OLD_RNG */
00396         };
00397     };
00398 }
00399 
00400 
00401 /*
00402  * RNGTest:
00403  * Make sure the RNG makes known values.
00404  * Optionally, print out some stuff.
00405  *
00406  * gcc rng.cc -Drng_stand_alone -o rng_test -lm
00407  *
00408  * Simple test program:
00409  */
00410 #ifdef rng_stand_alone
00411 int main() { RNGTest test; test.verbose(); }
00412 #endif /* rng_stand_alone */
00413 
00414 #ifdef rng_test
00415 RNGTest::RNGTest()
00416 {
00417       RNG rng(RNG::RAW_SEED_SOURCE, 1L);
00418 
00419       int i; 
00420       long r;
00421       for (i = 0; i < 10000; i++) 
00422       r = rng.uniform_positive_int();
00423 
00424 #ifdef OLD_RNG
00425       if (r != 1043618065L) {
00426           fprintf (stderr, "r (%lu) != 1043618065L\n", r);
00427           exit(-1);
00428       }
00429 #else
00430       if (r != 1179983147L) {
00431           fprintf (stderr, "r (%lu) != 1179983147L\n", r);
00432           exit(-1);
00433       }
00434 #endif /* OLD_RNG */
00435 
00436       for (i = 10000; i < 551246; i++)
00437           r = rng.uniform_positive_int();
00438 
00439 #ifdef OLD_RNG
00440       if (r != 1003L) {
00441           fprintf (stderr, "r (%lu) != 1003L\n", r);
00442           exit(-1);
00443       }
00444 #else
00445       if (r != 817829295L) {
00446           fprintf (stderr, "r (%lu) != 817829295L\n", r);
00447           exit(-1);
00448       }
00449 #endif /* OLD_RNG */
00450 
00451 }
00452 
00453 void
00454 RNGTest::first_n(RNG::RNGSources source, long seed, int n)
00455 {
00456     RNG rng(source, seed);
00457 
00458     for (int i = 0; i < n; i++) {
00459         long r = rng.uniform_positive_int();
00460         printf("%10lu ", r);
00461     };
00462     printf("\n");
00463 }
00464 
00465 void
00466 RNGTest::first_n_mil(RNG::RNGSources source, long seed, int n, FILE *outfile)
00467 {
00468     RNG rng(source, seed);
00469     // print the first 1000 no, then every millionth upto n millions
00470     long m = n * 1000000;
00471     for (int i = 0; i < m; i++) {
00472         long r = rng.uniform_positive_int();
00473         if (i < 100 || (i % 1000000 == 0))
00474             fprintf(outfile, "%10lu ", r);
00475     };
00476     fprintf(outfile, "\n");
00477 }
00478 
00479 void 
00480 RNGTest::verbose_mil()
00481 {
00482     FILE *outfile = NULL;
00483     outfile = fopen("temp.rands", "w");
00484     
00485     if (outfile == NULL)
00486         fprintf(stderr, "Cannot create temp.rands\n");
00487 
00488     fprintf (outfile, "default: ");
00489     first_n_mil(RNG::RAW_SEED_SOURCE, 188312339, 5, outfile);
00490     int i = 1;
00491     fprintf (outfile, "predef source %2u: ", i);
00492     first_n_mil(RNG::PREDEF_SEED_SOURCE, i, 5, outfile);
00493     
00494 }
00495 
00496 void
00497 RNGTest::verbose()
00498 {
00499     printf ("default: ");
00500     first_n(RNG::RAW_SEED_SOURCE, 1L, 5);
00501 
00502     int i;
00503     for (i = 0; i < 64; i++) {
00504         printf ("predef source %2u: ", i);
00505         first_n(RNG::PREDEF_SEED_SOURCE, i, 5);
00506     };
00507 
00508     printf("heuristic seeds should be different from each other and on each run.\n");
00509     for (i = 0; i < 64; i++) {
00510         printf ("heuristic source %2u: ", i);
00511         first_n(RNG::HEURISTIC_SEED_SOURCE, i, 5);
00512     };
00513 }
00514 
00515 #endif /* rng_test */
00516 
00517 #ifndef OLD_RNG
00518 using namespace std; 
00519 namespace 
00520 { 
00521     const double m1 = 4294967087.0; 
00522     const double m2 = 4294944443.0; 
00523     const double norm = 1.0 / (m1 + 1.0); 
00524     const double a12 = 1403580.0; 
00525     const double a13n = 810728.0; 
00526     const double a21 = 527612.0; 
00527     const double a23n = 1370589.0; 
00528     const double two17 = 131072.0; 
00529     const double two53 = 9007199254740992.0; 
00530     const double fact = 5.9604644775390625e-8; /* 1 / 2^24 */ 
00531 
00532     // The following are the transition matrices of the two MRG 
00533     // components (in matrix form), raised to the powers -1, 1, 
00534     // 2^76, and 2^127, resp. 
00535 
00536     const double InvA1[3][3] = { // Inverse of A1p0 
00537         { 184888585.0, 0.0, 1945170933.0 }, 
00538         { 1.0, 0.0, 0.0 }, 
00539         { 0.0, 1.0, 0.0 } 
00540     }; 
00541 
00542     const double InvA2[3][3] = { // Inverse of A2p0 
00543         { 0.0, 360363334.0, 4225571728.0 }, 
00544         { 1.0, 0.0, 0.0 }, 
00545         { 0.0, 1.0, 0.0 } 
00546     }; 
00547 
00548     const double A1p0[3][3] = { 
00549         { 0.0, 1.0, 0.0 }, 
00550         { 0.0, 0.0, 1.0 }, 
00551         { -810728.0, 1403580.0, 0.0 } 
00552     }; 
00553 
00554     const double A2p0[3][3] = { 
00555         { 0.0, 1.0, 0.0 }, 
00556         { 0.0, 0.0, 1.0 }, 
00557         { -1370589.0, 0.0, 527612.0 } 
00558     }; 
00559 
00560     const double A1p76[3][3] = { 
00561         { 82758667.0, 1871391091.0, 4127413238.0 }, 
00562         { 3672831523.0, 69195019.0, 1871391091.0 }, 
00563         { 3672091415.0, 3528743235.0, 69195019.0 } 
00564     }; 
00565 
00566     const double A2p76[3][3] = { 
00567         { 1511326704.0, 3759209742.0, 1610795712.0 }, 
00568         { 4292754251.0, 1511326704.0, 3889917532.0 }, 
00569         { 3859662829.0, 4292754251.0, 3708466080.0 } 
00570     }; 
00571 
00572     const double A1p127[3][3] = { 
00573         { 2427906178.0, 3580155704.0, 949770784.0 }, 
00574         { 226153695.0, 1230515664.0, 3580155704.0 }, 
00575         { 1988835001.0, 986791581.0, 1230515664.0 } 
00576     }; 
00577 
00578     const double A2p127[3][3] = { 
00579         { 1464411153.0, 277697599.0, 1610723613.0 }, 
00580         { 32183930.0, 1464411153.0, 1022607788.0 }, 
00581         { 2824425944.0, 32183930.0, 2093834863.0 } 
00582     }; 
00583 
00584     //------------------------------------------------------------------- 
00585     // Return (a*s + c) MOD m; a, s, c and m must be < 2^35 
00586     // 
00587 
00588     double MultModM (double a, double s, double c, double m) 
00589     { 
00590         double v; 
00591         long a1; 
00592         v=a*s+c; 
00593 
00594         if (v >= two53 || v <= -two53) { 
00595             a1 = static_cast<long> (a / two17); a -= a1 * two17; 
00596             v =a1*s; 
00597             a1 = static_cast<long> (v / m); v -= a1 * m; 
00598             v = v * two17 + a * s + c; 
00599         } 
00600         a1 = static_cast<long> (v / m); 
00601         /* in case v < 0)*/ 
00602         if ((v -= a1 * m) < 0.0) return v += m; else return v; 
00603     } 
00604 
00605     //------------------------------------------------------------------- 
00606     // Compute the vector v = A*s MOD m. Assume that -m < s[i] < m. 
00607     // Works also when v = s. 
00608     // 
00609     void MatVecModM (const double A[3][3], const double s[3], double v[3], 
00610              double m) 
00611     { 
00612         int i; 
00613         double x[3]; // Necessary if v = s 
00614         for (i = 0; i < 3; ++i) { 
00615             x[i] = MultModM (A[i][0], s[0], 0.0, m); 
00616             x[i] = MultModM (A[i][1], s[1], x[i], m); 
00617             x[i] = MultModM (A[i][2], s[2], x[i], m); 
00618         } 
00619         for (i = 0; i < 3; ++i) 
00620             v[i] = x[i]; 
00621     } 
00622 
00623     //------------------------------------------------------------------- 
00624     // Compute the matrix C = A*B MOD m. Assume that -m < s[i] < m. 
00625     // Note: works also if A = C or B = C or A = B = C. 
00626     // 
00627     void MatMatModM (const double A[3][3], const double B[3][3], 
00628              double C[3][3], double m) 
00629     { 
00630         int i, j; 
00631         double V[3], W[3][3]; 
00632         for (i = 0; i < 3; ++i) { 
00633             for (j = 0; j < 3; ++j) 
00634                 V[j] = B[j][i]; 
00635             MatVecModM (A, V, V, m); 
00636             for (j = 0; j < 3; ++j) 
00637 
00638                 W[j][i] = V[j]; 
00639         } 
00640         for (i = 0; i < 3; ++i) 
00641             for (j = 0; j < 3; ++j) 
00642                 C[i][j] = W[i][j]; 
00643     } 
00644 
00645     //------------------------------------------------------------------- 
00646     // Compute the matrix B = (A^(2^e) Mod m); works also if A = B. 
00647     // 
00648     void MatTwoPowModM (const double A[3][3], double B[3][3], double m, 
00649                 long e) 
00650     { 
00651         int i, j; 
00652         /* initialize: B = A */ 
00653         if (A != B) { 
00654             for (i = 0; i < 3; ++i) 
00655                 for (j = 0; j < 3; ++j) 
00656                     B[i][j] = A[i][j]; 
00657         } 
00658         /* Compute B = A^(2^e) mod m */ 
00659         for (i = 0; i < e; i++) 
00660             MatMatModM (B, B, B, m); 
00661     } 
00662 
00663     //------------------------------------------------------------------- 
00664     // Compute the matrix B = (A^n Mod m); works even if A = B. 
00665     // 
00666     void MatPowModM (const double A[3][3], double B[3][3], double m, 
00667              long n) 
00668     { 
00669         int i, j; 
00670         double W[3][3]; 
00671         /* initialize: W = A; B = I */ 
00672         for (i = 0; i < 3; ++i) 
00673             for (j = 0; j < 3; ++j) { 
00674                 W[i][j] = A[i][j]; 
00675                 B[i][j] = 0.0; 
00676             } 
00677         for (j = 0; j < 3; ++j) 
00678             B[j][j] = 1.0; 
00679         /* Compute B = A^n mod m using the binary decomposition of n */
00680         while (n > 0) { 
00681             if (n % 2) MatMatModM (W, B, B, m); 
00682             MatMatModM (W, W, W, m); 
00683 
00684             n/=2; 
00685         } 
00686     } 
00687 
00688     //-------------------------------------------------------------------- 
00689     // Check that the seeds are legitimate values. Returns 0 if legal 
00690     // seeds, -1 otherwise. 
00691     // 
00692     int CheckSeed (const unsigned long seed[6]) 
00693     { 
00694         int i; 
00695         for (i = 0; i < 3; ++i) { 
00696             if (seed[i] >= m1) { 
00697                 fprintf (stderr, "****************************************\n\n");
00698                 fprintf (stderr, "ERROR: Seed[%d] >= 4294967087, Seed is not set.", i);
00699                 fprintf (stderr, "\n\n****************************************\n\n");
00700                 return (-1); 
00701             } 
00702         } 
00703         for (i = 3; i < 6; ++i) { 
00704             if (seed[i] >= m2) { 
00705                 fprintf (stderr, "****************************************\n\n");
00706                 fprintf (stderr, "ERROR: Seed[%d] >= 429444443, Seed is not set.", i);
00707                 fprintf (stderr, "\n\n****************************************\n\n");
00708                 return (-1); 
00709             } 
00710         } 
00711         if (seed[0] == 0 && seed[1] == 0 && seed[2] == 0) { 
00712             fprintf (stderr, "****************************************\n\n");
00713             fprintf (stderr, "ERROR: First 3 seeds = 0.\n\n");
00714             fprintf (stderr, "****************************************\n\n");
00715             return (-1); 
00716         } 
00717         if (seed[3] == 0 && seed[4] == 0 && seed[5] == 0) { 
00718             fprintf (stderr, "****************************************\n\n");
00719             fprintf (stderr, "ERROR: Last 3 seeds = 0.\n\n");
00720             fprintf (stderr, "****************************************\n\n");
00721             return (-1); 
00722         } 
00723         return 0; 
00724     } 
00725 } // end of anonymous namespace 
00726 
00727 //------------------------------------------------------------------------- 
00728 // Generate the next random number. 
00729 // 
00730 double RNG::U01 () 
00731 { 
00732     long k; 
00733     double p1, p2, u; 
00734     /* Component 1 */ 
00735     p1 = a12 * Cg_[1] - a13n * Cg_[0]; 
00736     k = static_cast<long> (p1 / m1); 
00737     p1 -= k * m1; 
00738     if (p1 < 0.0) p1 += m1; 
00739     Cg_[0] = Cg_[1]; Cg_[1] = Cg_[2]; Cg_[2] = p1; 
00740     /* Component 2 */ 
00741     p2 = a21 * Cg_[5] - a23n * Cg_[3]; 
00742     k = static_cast<long> (p2 / m2); 
00743     p2 -= k * m2; 
00744     if (p2 < 0.0) p2 += m2; 
00745     Cg_[3] = Cg_[4]; Cg_[4] = Cg_[5]; Cg_[5] = p2; 
00746     /* Combination */ 
00747     u = ((p1 > p2) ? (p1 - p2) * norm : (p1 - p2 + m1) * norm); 
00748     return (anti_ == false) ? u : (1 - u); 
00749 } 
00750 
00751 //------------------------------------------------------------------------- 
00752 // Generate the next random number with extended (53 bits) precision. 
00753 // 
00754 double RNG::U01d () 
00755 { 
00756     double u; 
00757     u = U01(); 
00758     if (anti_) { 
00759         // Don't forget that U01() returns 1 - u in 
00760         // the antithetic case 
00761         u += (U01() - 1.0) * fact; 
00762         return (u < 0.0) ? u + 1.0 : u; 
00763     } else { 
00764         u += U01() * fact; 
00765         return (u < 1.0) ? u : (u - 1.0); 
00766     } 
00767 } 
00768 
00769 //************************************************************************* 
00770 // Public members of the class start here 
00771 //------------------------------------------------------------------------- 
00772 
00773 /*
00774  * Functions for backward compatibility:
00775  *
00776  *   RNG (long seed)
00777  *   void set_seed (long seed)
00778  *   long seed()
00779  *   long next()
00780  *   double next_double()
00781  */
00782 RNG::RNG (long seed) 
00783 {
00784     set_seed (seed);
00785     init();
00786 }
00787 
00788 void RNG::init()
00789 {
00790     anti_ = false; 
00791     inc_prec_ = false; 
00792 
00793     /* Information on a stream. The arrays {Cg_, Bg_, Ig_} contain the
00794        current state of the stream, the starting state of the current
00795        SubStream, and the starting state of the stream. This stream
00796        generates antithetic variates if anti_ = true. It also generates
00797        numbers with extended precision (53 bits if machine follows IEEE
00798        754 standard) if inc_prec_ = true. next_seed_ will be the seed of
00799        the next declared RngStream. */
00800 
00801     for (int i = 0; i < 6; ++i) { 
00802         Bg_[i] = Cg_[i] = Ig_[i] = next_seed_[i]; 
00803     } 
00804     MatVecModM (A1p127, next_seed_, next_seed_, m1); 
00805     MatVecModM (A2p127, &next_seed_[3], &next_seed_[3], m2); 
00806 }
00807 
00808 void RNG::set_seed (long seed) 
00809 {
00810     if (seed == 0) {
00811         set_seed (HEURISTIC_SEED_SOURCE, seed);
00812     }
00813     else {
00814         unsigned long seed_vec[6] = {0, 0, 0, 0, 0, 0};
00815         for (int i=0; i<6; i++) {
00816             seed_vec[i] = (unsigned long) seed;
00817         }
00818         set_package_seed (seed_vec);
00819         init();
00820     }
00821 }
00822 
00823 long RNG::seed() 
00824 {
00825     unsigned long seed[6];
00826     get_state(seed);
00827     return ((long) seed[0]);
00828 }
00829 
00830 long RNG::next()
00831 {
00832     return (rand_int(0, MAXINT));
00833 }
00834 
00835 double RNG::next_double()
00836 {
00837     return (rand_u01());
00838 }
00839 /* End of backward compatibility functions */
00840 
00841 // The default seed of the package; will be the seed of the first 
00842 // declared RNG, unless set_package_seed is called. 
00843 // 
00844 double RNG::next_seed_[6] = 
00845 { 
00846     12345.0, 12345.0, 12345.0, 12345.0, 12345.0, 12345.0 
00847 }; 
00848 
00849 //------------------------------------------------------------------------- 
00850 // constructor 
00851 // 
00852 RNG::RNG (const char *s) 
00853 { 
00854     if (strlen (s) > 99) {
00855         strncpy (name_, s, 99);
00856         name_[100] = 0;
00857     }
00858     else 
00859         strcpy (name_, s);
00860 
00861     init();
00862 }
00863 
00864 
00865 //------------------------------------------------------------------------- 
00866 // Reset Stream to beginning of Stream. 
00867 // 
00868 void RNG::reset_start_stream () 
00869 { 
00870     for (int i = 0; i < 6; ++i) 
00871         Cg_[i] = Bg_[i] = Ig_[i]; 
00872 } 
00873 
00874 //------------------------------------------------------------------------- 
00875 // Reset Stream to beginning of SubStream. 
00876 // 
00877 void RNG::reset_start_substream () 
00878 { 
00879     for (int i = 0; i < 6; ++i) 
00880         Cg_[i] = Bg_[i]; 
00881 } 
00882 
00883 //------------------------------------------------------------------------- 
00884 // Reset Stream to NextSubStream. 
00885 // 
00886 void RNG::reset_next_substream () 
00887 { 
00888     MatVecModM(A1p76, Bg_, Bg_, m1); 
00889     MatVecModM(A2p76, &Bg_[3], &Bg_[3], m2); 
00890     for (int i = 0; i < 6; ++i) 
00891         Cg_[i] = Bg_[i]; 
00892 } 
00893 
00894 //------------------------------------------------------------------------- 
00895 void RNG::set_package_seed (const unsigned long seed[6]) 
00896 { 
00897     if (CheckSeed (seed)) 
00898         abort();
00899     for (int i = 0; i < 6; ++i) 
00900         next_seed_[i] = seed[i]; 
00901 } 
00902 
00903 //------------------------------------------------------------------------- 
00904 void RNG::set_seed (const unsigned long seed[6]) 
00905 { 
00906     if (CheckSeed (seed)) 
00907         abort();
00908     for (int i = 0; i < 6; ++i) 
00909         Cg_[i] = Bg_[i] = Ig_[i] = seed[i]; 
00910 } 
00911 
00912 //------------------------------------------------------------------------- 
00913 // if e > 0, let n = 2^e + c; 
00914 // if e < 0, let n = -2^(-e) + c; 
00915 // if e = 0, let n = c. 
00916 // Jump n steps forward if n > 0, backwards if n < 0. 
00917 // 
00918 void RNG::advance_state (long e, long c) 
00919 { 
00920     double B1[3][3], C1[3][3], B2[3][3], C2[3][3]; 
00921     if (e > 0) { 
00922         MatTwoPowModM (A1p0, B1, m1, e); 
00923         MatTwoPowModM (A2p0, B2, m2, e); 
00924     } else if (e < 0) { 
00925         MatTwoPowModM (InvA1, B1, m1, -e); 
00926         MatTwoPowModM (InvA2, B2, m2, -e); 
00927     } 
00928     if (c >= 0) { 
00929         MatPowModM (A1p0, C1, m1, c); 
00930         MatPowModM (A2p0, C2, m2, c); 
00931     } else { 
00932         MatPowModM (InvA1, C1, m1, -c); 
00933         MatPowModM (InvA2, C2, m2, -c); 
00934     } 
00935     if (e) { 
00936         MatMatModM (B1, C1, C1, m1); 
00937         MatMatModM (B2, C2, C2, m2); 
00938     } 
00939     MatVecModM (C1, Cg_, Cg_, m1); 
00940     MatVecModM (C2, &Cg_[3], &Cg_[3], m2); 
00941 } 
00942 
00943 //------------------------------------------------------------------------- 
00944 void RNG::get_state (unsigned long seed[6]) const 
00945 { 
00946     for (int i = 0; i < 6; ++i) 
00947         seed[i] = static_cast<unsigned long> (Cg_[i]); 
00948 } 
00949 
00950 //------------------------------------------------------------------------- 
00951 void RNG::write_state () const 
00952 { 
00953     printf ("The current state of the Rngstream %s:\n", name_);
00954     printf (" Cg_ = { ");
00955     for(int i=0;i<5;i++) { 
00956         printf ("%lu, ", (unsigned long) Cg_[i]);
00957     } 
00958     printf ("%lu }\n\n", (unsigned long) Cg_[5]);
00959 } 
00960 
00961 //------------------------------------------------------------------------- 
00962 void RNG::write_state_full () const 
00963 { 
00964     int i; 
00965     printf ("The RNG %s:\n", name_);
00966     printf (" anti_ = %s", (anti_ ? "true" : "false")); 
00967     printf (" inc_prec_ = %s\n", (inc_prec_ ? "true" : "false")); 
00968 
00969     printf (" Ig_ = { ");
00970     for (i = 0; i < 5; i++) { 
00971         printf ("%lu, ", (unsigned long) Ig_[i]);
00972     } 
00973     printf ("%lu }\n", (unsigned long) Ig_[5]);
00974 
00975     printf (" Bg_ = { ");
00976     for (i = 0; i < 5; i++) { 
00977         printf ("%lu, ", (unsigned long) Bg_[i]);
00978     } 
00979     printf ("%lu }\n", (unsigned long) Bg_[5]);
00980 
00981     printf (" Cg_ = { ");
00982     for (i = 0; i < 5; i++) { 
00983         printf ("%lu, ", (unsigned long) Cg_[i]);
00984     } 
00985     printf ("%lu }\n\n", (unsigned long) Cg_[5]);
00986 } 
00987 
00988 //------------------------------------------------------------------------- 
00989 void RNG::increased_precis (bool incp) 
00990 { 
00991     inc_prec_ = incp; 
00992 } 
00993 
00994 //------------------------------------------------------------------------- 
00995 void RNG::set_antithetic (bool a) 
00996 { 
00997     anti_ = a; 
00998 } 
00999 
01000 //------------------------------------------------------------------------- 
01001 // Generate the next random number. 
01002 // 
01003 double RNG::rand_u01 () 
01004 { 
01005     if (inc_prec_) 
01006         return U01d(); 
01007     else 
01008         return U01(); 
01009 } 
01010 
01011 //------------------------------------------------------------------------- 
01012 // Generate the next random integer. 
01013 // 
01014 long RNG::rand_int (long low, long high) 
01015 { 
01016     //  return (long) low + (long) (((double) (high-low) * drn) + 0.5);
01017     return ((long) (low + (unsigned long) (((unsigned long) 
01018                         (high-low+1)) * rand_u01())));
01019 }; 
01020 #endif /* !OLD_RNG */

Generated on Tue Mar 6 16:47:50 2007 for ns2 Network Simulator 2.29 by  doxygen 1.4.6