C++11 random number generator

The C++11 random number generator is solely handle by the <random> header file.This header file include many templates and functions which help generate random numbers of different types(integer or floating point values with or without mathematical significance) and under the specification of the user it can also generate random numbers within certain range of value.

Link :C++11 Random header

The random number generator of C++11 consists of two important aspects that make up the random number generator:engine and distribution.

These two are the deciding factors of how the random numbers are generated,the degree of randomness and the range within which the random number is obtained.Note here the degree of randomness is important for every random number generator.It determine the quality of the random number generator,the more is the degree of randomness the better it is as a random number generator.Random number generator having lesser degree of randomness can be predictable and it may not be a good choice.So the degree of randomness is one of the most important property that must be taken into account when choosing a random number generator.

The random number generated by the library as it is may not have a good degree of randomness,what might actually help generate a perfect random number and how to obtain them will be discussed later.

What are engine and distributions is discuss in more detail below.


Engine or basic engine

When we say ‘random number generator engine or ‘basic engine‘ or just ‘engine‘ we denote the source of the random numbers.They can also refer to the mechanism behind which the random number is generated.It is also the most important element of any random number generator.Without ‘engine’ there would be no random number.

There are many types of ‘engine’ provided by the <random> header file :default_random_engine,linear_congruential_engine,mersenne_twister_engine etc. are some of the basic engine.visit the link ( C++ random header ) to view all the engine list.

Note the engine itself is sufficient to generate a sequence of random numbers.A code example is provided below and uses the engine default_random_engine.In the program we simply try to generate 10 random numbers.

#include <iostream>
#include <random> //necessary!

using namespace std;

int main( )
{
default_random_engine dre ; //’engine’ declaration

for( auto i=0 ; i<5 , i++ )
{
cout<< dre( ) << endl ; //get the random number
}

cin.get( );
return 0;
}

Output in Code::Blocks,

16807
282475249
1622650073
984943658
1144108930

Output in Visual Studio ,

3499211612
581869302
3890346734
3586334585
545404204

The output in Code::Blocks and Visual studio are different because the default_random_engine is an implementation-specific type engine.It will give different output in different compiler.And note it is the only implementation-specific engine.Other engines like the linear_congruential_engine,mersenne_twister_engine,etc. are not implementation-specific engine and so it will generate the same random number in different compiler.

Let’s take the engine linear_congruential_engine and try to generate a random number ;this engine actually generate a pseudorandom numbers(a not so random number).You will see that the engine gives the same output in Code::blocks and Visual Studio.

linear_congruential_engine<unsigned int , 16807 , 0 , 2147483> lce ;
for(auto i=0 ; i<5 ; i++ )
{
cout<< lce( ) << endl ;
}

Output in Code::block and Visual Studio,

16807
1154976
582795
365602
723951


Engine adapters

Engine adapters are also engine but they utilize the random numbers generated by the basic engine to produce a new random numbers having different properties from the original random number produce by the basic engine.In engine adapter the basic engine used is known as the base engine.

There are three engine adapters in C++ :discard_block_engine , independent_bits_engine and shuffle_order_engine.For these engine adapters you can choose any of the basic engine as their base engine.A code example is given below.

discard_block_engine< linear_congruential_engine<unsigned int , 16807 , 0 , 2147483> dbe; //base engine is linear_congruential_engine

discard_block_engine< default_random_engine , 1 , 90 > dbe1 ; //bass engine is default_random_engine


Engine with predefined parameters or predefined engine

There are some engines whose parameters are fixed such engines are known as predefined engine.Predefining the parameters will generate random values from the predefined ranges,thus you cannot expand the range from which the random number is obtain.And also predefined engine have the same degree of randomness.

Using predefined engines will always give the same output in all compiler.Engine like minstd_rand0,minstd_rand,mt19937,etc. are some of the predefined engines .A code example is given below which uses the predefined engine ‘mt19937‘.This engine is a type definition of the ‘mersenne_twister_engine‘.

More about predefined engine here :C++11 predefine engine
 
Link :Difference between basic engine and predefined engine

mt19937 mt ; //declaration of ‘mt19937’ engine

for(auto i=0 ; i<5 ; i++)
{
cout<< mt( ) << endl ;
}

Output in Code::blocks,

3499211612
581869302
3890346734
3586334585
545404204

Try running the code in Visual Studio or in any other compiler you will get the same output.


What is ‘seed’ of an engine?

In C <ctsdlib> library the ‘srand‘ function acts as a seed for the ‘rand‘ function.In C++11 engine the concept of ‘seed’ is same as that of the <cstdlib> ‘srand’ function.Seed is nothing but some values (it can be any values) that can alter the state of the engine.

A state of an engine refer to the condition or event that dictate which number should be generated as the random number.Altering the state of the ‘engine’ can help generate random number completely different from the random number which would have been generated in it’s consecutive state or the initial state.

To make the understanding of the ‘seed’ concept easier,let’s take the second code example given in this post (the code that uses ‘linear_congruential_engine‘).If you run the code,say ten times you will get the same output 10 times this is because the initial state of the engine is always the same.So let’s try providing a ‘seed’ to the instance of the linear_congruential_engine and examine the output.Note a seed is usually provided by passing it to the engine constructor.

Link :C++11 class seed_seq (engine seed)

#include <iostream>
#include <random>
#include <ctime>

using namespace std;

int main( )
{
linear_congruential_engine<unsigned int , 16807 , 0 , 2147483> lce( time(NULL) ) ; //The value returned by 'time(NULL)' is passed as the seed

for(auto i=0 ; i<5 ; i++ )
{
cout<< lce( ) << endl ;
}

cin.get( );
return 0;
}

Now try running the program 10 times again.Each time the program is run the output obtained varies,this is because the initial state of the engine has been changed by the ‘seed’,here the ‘seed’ is the value obtained by calling the function ‘time(NULL)’.If one same value is provided as a seed ,the output obtained will be same for that seed value,the ‘time(NULL)’ however generate different values each second,thus the output also changes.

You can provide any function to generate the seed value,the more random is the seed value the more degree is the randomness of the number generated.The <random> header provide a class seed_seq to generate values for seed.

**Note C++11 engine can generate value of only integer type and floating point type.
The integer type supported are:short , int , long , long long their corresponding unsigned are also supported.
 
The floating point type supported are:float , double,long double.

A whole view of ‘engine’ and ‘predefined engines’ list is given below.

C++ random number generator



Distribution

The role of ‘distribution‘ in random number generator is to use the number generated by the ‘engine’ in a more meaningful and purposeful way.The engine simply generate a random number of the compiler’s choice thus rendering a very large values and sometimes very small unrealistic values.This behavior may not be useful to us.

We may require a random values within certain range for implementing in our program and in such case the unorderly unsized generated number becomes futile.In such scenario ‘distributions’ can be very helpful.By using ‘distributions’ we can restrict the range within which the random numbers should be generated.Not only that you will see that there are some distributions that help generate values base on mathematical probability density.Hence,I always like to define ‘distribution‘ as a class template which generate random numbers from your choice of restricted range and types.

There are many types of distributions in <random> header: uniform_int_distribution(a distribution to generate random integer values) ,uniform_real_distribution(a distribution to generate random real numbers), binomial_distribution(a distribution to generate binomial random numbers) , cauchy_distribution(a distribution to generate Cauchy distribution random numbers) ,etc. for all the distributions list visit the link (C++ random header file)

Since distributions are templates, you must pass the type as template argument to specify the type of the random numbers you want to generate .And to specify the range within which the random numbers should be generated passed the two limiting values as the arguments when the distribution objects are declared.Note passing limiting range values as constructor arguments apply only for some distributions;different distribution have different rules.To get the random sequence pass the engine object as an argument to the distribution ‘operator( )‘ function .A small code example is given below which uses the uniform_real_distribution and cauchy_distribution .

#include <iostream>
#include <random>
#include <iomanip>

using namespace std;

int main( )
{
default_random_engine dre ; //Engine

uniform_real_distribution<double> urd(2.456 , 3.102 );  
/**’urd’ generate ‘double’ type random numbers within the range [2.456 , 3.102] **/

for( auto i=0; i<5 ; i++)
{
cout<< urd(dre) << setw( 10 ) ; //Calling ‘urd(dre)’ generate random numbers
}

cout<< “\n\n”

cauchy_distribution<> cd ;  
/**The type is not mentioned the default is ‘double’ type **/

for( auto i=0 ; i<5 ; i++ )
{
cout<< cd(dre) << setw(10) ;  //Calling ‘cd(dre)’ generate random numbers 
}

cin.get( );
return 0;
}

Output in Code::blocks(uses MinGW 6.1 compiler),

2.54097   2.75229   2.59745   2.89455   3.05981
 
-0.587312   -10.6863   2.6071   -1.50403   -0.524788

To read more about each of the distributions please visit the random header file link and under that post you will find links to the discussion of each distributions.




Leave a Reply

Your email address will not be published. Required fields are marked *