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
===============================================