Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Compound Members | File Members

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

Generated on Tue Apr 20 12:14:29 2004 for NS2.26SourcesOriginal by doxygen 1.3.3