Bojan Nikolic: Numerical and Quantitative Methods in C++

[website home] | [BN Algorithms]

Uniform floating point numbers in the interval 0 to 1

See also

Uniformly distributed integer random numbers
How to generate uniformly distributed integers which are needed for generation of floating point distributions

Introduction

This is obviously one of the simplest distributions, defined by:

p(X)dX = dX

One important use of this distribution in changing the control flow of an algorithm in a random way but with a well defined probability. For example, if branch A should be taken with probability p and branch B should be taken with probability 1-p, then this can be implemented by

  1. Drawing a random number X between 0 and 1
  2. If X<p then take branch A, otherwise take B

Generation using boost

Below is a very simple example which uses boost libraries [boost] to generate ten random numbers between 0 and 1:

#include <iostream>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_01.hpp>

int main(void)
{
  boost::minstd_rand intgen;
  boost::uniform_01<boost::minstd_rand> gen(intgen);
  
  const size_t n=10;
  for(size_t i=0; i<n; ++i)
  {
    std::cout<<gen()
	     <<std::endl;
  }
}

Creating a generator of the random numbers takes two steps in this example:

  • First, a uniform integer random number generator is created. This is required since any of the available integer generators can in principle be used to feed the floating point number generator. This integer generator is created in line:

    boost::minstd_rand intgen;
    

    In this case we are using the simple linear congruential generator.

  • Secondly the floating point number generator is created by passing it the integer generator:

    boost::uniform_01<boost::minstd_rand> gen(intgen);
    

    It should be noted that the integer generator is taken by copy, not by reference.

Relationship with the underlying integer generator

Whatever implementation of a floating point generator you chose, it is important to appreciate its relationship with the underlying integer generators which in fact generates all of the “randomness”. If the underlying integer generator is reseeded then this will naturally also effectively reseed the floating point generator too. Additionally if the integer generator has issues such as short cycle length, then so will the floating point generator.

The importance of understanding this relationship is illustrated in the following short program:

#include <iostream>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_01.hpp>

void mkrandom(boost::minstd_rand &intgen)
{
  boost::uniform_01<boost::minstd_rand> gen(intgen);
  
  const size_t n=5;
  for(size_t i=0; i<n; ++i)
  {
    std::cout<<gen()
	     <<std::endl;
  }

}

int main(void)
{
  boost::minstd_rand intgen;
  mkrandom(intgen);
  std::cout<<"Second run:"
	   <<std::endl;
  mkrandom(intgen);
}

The output of this program is:

./uniform01-copy
2.24775e-05
0.0850324
0.601353
0.891611
0.967956
Second run:
2.24775e-05
0.0850324
0.601353
0.891611
0.967956

As you can see above, the function that prints the floating point random numbers takes the integer generator by reference:

void mkrandom(boost::minstd_rand &intgen)
{

Therefore one would expect the integer generator to be advanced by the mkrandom function (by five numbers in this case). However, the floating point generator takes its argument by copy in this line:

boost::uniform_01<boost::minstd_rand> gen(intgen);

The fact that the argument is taken by copy is not clear from the code of this program by itself – you need to consult either the documentation of the library or look at the header file yourself. The consequence of taking the argument by copy is that the generator in the main function is not advanced, and therefore the two calls to mkrandom generate identical sequences of numbers.