X3J16/93-0145 WG21/N0352 Mats Henricson Ellemtel Telecommunication Systems Laboratories E-mail: mats.henricson@eua.ericsson.se ==================================================================== Proposal for Standardization of Random Number Generators in C++ 1. Background ------------- In the C-standard there is a function in stdlib.h defined as: int rand(void); It returns a pseudo random integer in the interval 0 to RAND_MAX, which is at least 32767. With this generator you can build just about any other random distribution, but it is rather laborious. You also have the problem that such an approach might give you distributions that may not be well distributed. By just picking some values out of a well distributed series, you form a new series that may not be well distributed. A class has many advantages to a function as a random number generator. In fact, some of the first classes ever made in C++ was a few random number generators you can find in the task library made by Bjarne in 80-82 (unless I have understood it all wrong). These classes are still used by some programmers, so it should be desirable to be as close to their design as possible. However, their age (10++ years) shows in the design. Among other things they use public data. They also have a rather mixed identity as random number generators. That is why I am proposing X3J16/WG21 a new set of random number generators. 2. rand01double, pseudo-random doubles in [0,1) ----------------------------------------------- The idea is to have a class generating pseudo-random doubles in the interval [0,1) (from (including) double(0) up to, (but excluding) double(1)). The interface for this class would be: class rand01double // Generates doubles in the interval [0,1) { public: rand01double( long int seed ); // Described in 5.6 rand01double(); // Described in 5.5 void reset(); // Described in 5.8 void set( long int seed ); // Described in 5.7 double operator()() { return draw(); } // Syntactic sugar double draw(); // Get a random number private: // All below is implementation defined // Drop me a mail if you want an implementation of // this class: mats.henricson@eua.ericsson.se }; An example program is included in chapter 6. 3. rand01float, pseudo-random floats in [0,1) --------------------------------------------- The interface for this class would be: class rand01float // Generates floats in the interval [0,1) { public: rand01float( long int seed ); // Described in 5.6 rand01float(); // Described in 5.5 void reset(); // Described in 5.8 void set( long int seed ); // Described in 5.7 float operator()() { return draw(); } // Syntactic sugar float draw(); // Get a random number private: // All below is implementation defined // Drop me a mail if you want an implementation of // this class: mats.henricson@eua.ericsson.se }; An example program is included in chapter 6. 4. randlong, pseudo-random long int in [0, LONG_MAX] ---------------------------------------------------- For programmers that want pseudo-random integers, there is a class that is very similar to the rand01double and rand01float classes. The interface is as follows: class randlong // Generates long int in the interval [0, LONG_MAX] { public: randlong( long int seed ); // Described in 5.6 randlong(); // Described in 5.5 void reset(); // Described in 5.8 void set( long int seed ); // Described in 5.7 long int operator()() { return draw(); } // Syntactic sugar long int draw(); // Get a random number private: // All below is implementation defined // Drop me a mail if you want an implementation of // this class: mats.henricson@eua.ericsson.se }; This class can be seen as a replacement for the rand() function in the C-standard. An example program is included in chapter 6. 5. Explanation -------------- 5.1 Statistics The distribution of the generated pseudo-random numbers must be statistically sound in all implementations. 5.2 Preconditions The only preconditions are that specific implementations might refuse certain seeds since they might not be statistically sound. The non-default constructor as well as the set() function can therefore throw the exception xrandbadseed: class xrandbadseed { public: xrandbadseed( long int seed ) : mySeed( seed ) {}; long int theseed() const { return mySeed; } private: long int mySeed; }; It is implementation defined which seeds are illegal. 5.3 Postconditions None. 5.4 Copy constructor, operator= and destructor Specific implementations might need to implement the copy constructor, assignment operator and destructor. At copy and assignment, the state of the assigned/copied from object is copied, i.e. both objects will after assignment/copy generate identical pseudo-random series. 5.5 The default constructor If the default constructor is called, it is implementation defined which seed will be used. It is also implementation defined if the same seed will be used at different calls to the default constructor. Example: rand01double anArray[2]; // Default constructor called double d0 = anArray[0](); double d1 = anArray[1](); // It is implementation defined if d0 == d1 5.6 The non-default constructor By using this constructor, taking a long int as seed, you explicitly set the seed used for generating pseudo-random numbers. The pseudo-random numbers that a generator will generate after it is newly created, is denoted: a[m][1]...a[m][n] m == 1, n >= 0 This definition is used below. 5.7 The set() function If set() is called for a generator with a long int as argument, it means that it will now generate the series: a[m+1][1]...a[m+1][n] 5.8 The reset() function If reset() is called for a generator, it means that it will now re-generate the same series as was previously generated, i.e.: a[m][1]...a[m][n] 6. Examples (not part of the proposal) -------------------------------------- This is a short example program for the rand01double, rand01float and randlong classes. // --------------------------------------------------------------------- #include #include #include "rand01double.hh" #include "rand01float.hh" #include "randlong.hh" template class randtest { public: randtest(); void test( char* classname, int loop ); }; template randtest::randtest() { // Empty } template void randtest::test( char* classname, int loop ) { int i; cout << endl << "Now testing " << classname << " class" << endl; T g1( 1234567890 ); U x1 = g1(); U x2 = g1(); g1.reset(); if( (x1 != g1()) || (x2 != g1()) ) { cout << "ERROR!!" << endl; exit(1); } T g2(g1); for(i = 0; i < loop; i++) { if( g1() != g2() ) { cout << "ERROR!!" << endl; exit(1); } } T g3( 123456789 ); g2 = g3; for(i = 0; i < loop; i++) { if( g2() != g3() ) { cout << "ERROR!!" << endl; exit(1); } } cout << "Trying arrays of " << classname << endl; T gArray[2]; gArray[0].set( 1234567890 ); // gArray[1].set( 1234567890 ); cout << gArray[0]() << endl; cout << gArray[1]() << endl; } int main() { randtest< rand01double, double > dtest; dtest.test( "rand01double", 1000 ); randtest< rand01float, float > ftest; ftest.test( "rand01float", 1000 ); randtest< randlong, long int > ltest; ltest.test( "randlong", 1000 ); // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX cout << endl << "set() and reset() examples" << endl; rand01double array[2]; // array[0] and array[1] can be different double d0 = array[0](); double d1 = array[1](); if( d0 == d1 ) { cout << "This is just pure coincidence" << endl; } array[0].reset(); array[1].reset(); // They are probably still different if( (d0 != array[0]()) || (d1 != array[1]()) ) { cout << "Error!" << endl; exit(1); } array[0].set( 12345 ); array[1].set( 67890 ); // They are now explicitly different if( array[0]() == array[1]() ) { cout << "This is just pure coincidence" << endl; } array[0].set( 1234567890 ); array[1].set( 1234567890 ); // They are now explicitly equivalent if( array[0]() != array[1]() ) { cout << "Error!" << endl; exit(1); } array[0].reset(); array[1].reset(); // Still equivalent if( array[0]() != array[1]() ) { cout << "Error!" << endl; exit(1); } return (0); } // --------------------------------------------------------------------- Mats Henricson =============================================== Mats Henricson Ellemtel Telecommunication Systems Laboratories Box 1505 125 25 Alvsjo (Stockholm) Sweden ----------------------------------------------- E-mail: mats.henricson@eua.ericsson.se Phone: + 46 8 727 40 85 ===============================================