IntroductionIn previous articles, I have looked at how to generate various
random
distributions of one variable, and random collections of
variables. Those articles assumed only a random number generator
that produced random numbers in some fixed range, such as the C
What is TR1?The current version of the C++ standard was ratified in 1998. Since then, there has been a lot of work towards defining a new version of the standard, currently with the working title of C++0x. This revision will add assorted new features to the language itself, but in the meantime, a subset of the proposals have been put into an interim standard, known as TR1. TR1 contains no new language syntax, only new additions to the standard libraries. The additions are a mix of various useful things, including smart pointers, hash tables, regular expressions, and, of course, random number generators. Because there are no changes to the language, TR1 can easily be bolted on to existing compilers. GCC started implementing TR1 with the version 4 series, and the random number generation facilities are included from GCC 4.2. Microsoft also provide beta TR1 support as an extension pack to Visual Studio 2008, although I haven't tried it so I don't know if it includes random number generation. I should also mention that I am far from being an expert on TR1, and I would encourage the Topcoder community to contribute their knowledge and experience in the forums. What I describe below is merely my experience in using the implementation in GCC 4.2. Generators, engines and distributionsOne of the problems with random number generation in C is that
there is only one random source: the TR1 identifies three abstract concepts related to random number
generation: engines, generators and distributions. An
engine is a pseudo-random number generator
with reproducable behaviour. Several types of engines are defined,
including the standard linear congruential generator used by many
implementations of A uniform random number generator is a more abstract concept: it simply has to generate numbers in some range (either integer or floating point) with a uniform distribution. Engines are required to be uniform random number generators, but other source are possible, such as a hardware or operating system random number generator that uses external events as a source of cryptographically secure randomness. Finally, a distribution is the user-friendly front end to the whole infrastructure. It takes randomness from a generator and formats it into your distribution of choice - be it a uniform distribution with a range you specify, or a normal distribution, or something else. Let's dive in with an example: #include <tr1/random> #include <iostream> #include <cstdlib> using namespace std; using namespace std::tr1; int main() { variate_generator<mt19937, normal_distribution<> > r(mt19937(time(NULL)), normal_distribution<>(0.5, 2.0)); for (int i = 0; i < 5; i++) cout << r() << endl; return 0; } Now, what does it all mean? Let's take it one bit at a time.
Firstly, the header file is TR1 provides a number of predefined engine templates, which take
various parameters controlling the pseudo-random generation. However,
it's difficult to remember the magic numbers that make good random
number generation, so it also provides typedefs for various common
instances. One of these is The probability distribution here is the normal distribution. This
is also a template (depending on which floating-point type you would
like to generate), but it defaults to Finally, we put it all to work, outputting five random numbers with a normal distribution. Multiple distributionsThis is fine if we only ever need to generate random numbers from
one distribution, but what if we need more? You could just
copy-and-paste the declaration and then change it. However, you'll
probably notice that unless a second passes between the constructors
being called, the engines will be generated with the same seed, and
hence will produce the same random numbers. A second attempt may be to
construct just one engine, and pass that to the constructors for each
What else can one do in the meantime? Several options spring to mind:
ConclusionsTR1 solves several major short-comings of the aging C random number generator: it gives explicit control over the state of engines, defines portable engines that yield reproducable behaviour between compilers, and provides a number of discrete and continuous non-uniform distributions. However, there are still some quirks and inconveniences, at least under GCC. It appears that the random number interface in C++0x is still in development, and presumably the GCC developers are striving to improve their implementation, so we may soon see a day when random number generation will be both simple and powerful.
|
|