6 Random Number Generators

The functionalities described in this chapter are declared in pnl/pnl_random.h.

Random number generators should be called through the new rng interface based on the PnlRng object. This interface uses reentrant functions and is suitable for multi-threaded applications.

The older rand interface is kept for compatibility purposes only and should not be used in new code.


Random generatorindex Type Info




KNUTH PNL_RNG_KNUTH pseudo
MRGK3 PNL_RNG_MRGK3 pseudo
MRGK5 PNL_RNG_MRGK5 pseudo
SHUFL PNL_RNG_SHUFL pseudo
L’ECUYER PNL_RNG_L_ECUYER pseudo
TAUSWORTHE PNL_RNG_TAUSWORTHE pseudo
MERSENNE PNL_RNG_MERSENNE pseudo
SQRT PNL_RNG_SQRT quasi
HALTON PNL_RNG_HALTON quasi
FAURE PNL_RNG_FAURE quasi
SOBOL_I4 PNL_RNG_SOBOL_I4 quasi uses 32 bit intergers
SOBOL_I8 PNL_RNG_SOBOL2_I8 quasi uses 64 bit intergers
NIEDERREITER PNL_RNG_NIEDERREITERquasi

Table 2: Indices of the random generators

6.1 The rng interface

It is possible to create several random number generators each with its own state variable so that they can evolve independently in a shared memory environment. These generators are suitable for use in multi-threaded programs.

typedef struct _PnlRng PnlRng; 
struct _PnlRng 
{ 
  PnlObject object; 
  int type; /*!< generator type * 
  void (*Compute)(PnlRng *g, double *sample); /*!< the function to compute the 
                                                next number in the sequence */ 
  int rand_or_quasi; /*!< can be PNL_MC or PNL_QMC */ 
  int dimension; /*!< dimension of the space in which we draw the samples */ 
  int counter; /*!< counter = number of samples already drawn */ 
  int has_gauss; /*!< Is a gaussian deviate available? */ 
  double gauss; /*!< If has_gauss==1, gauss a gaussian sample */ 
  int size_state; /*!< size in bytes of the state variable */ 
  void *state; /*!< state of the random generator */ 
};

Some auxiliary functions internally used (to be used with caution)

The following functions return one sample from the specified distribution.

The following functions take an already existing PnlVect *as first argument and fill each entry of the vector with a sample from the specified distribution. All the entries are independent. The difference between n-samples from a distribution in dimension 1, and one sample from the same distribution in dimension n only matters when using a quasi random number generator.

The following functions take an already existing PnlMat *as first argument and fill each entry of the matrix with a sample from the specified distribution. All the entries are independent. On return, the matrix M is of size samples x dimension. The rows of M are independent and identically distributed. Each row is a sample from the given law in dimension dimension.

Some examples

#include <stdlib.h> 
#include "pnl/pnl_random.h" 
 
int main () 
{ 
  int i, M; 
  PnlRng *rng = pnl_rng_create(PNL_RNG_MERSENNE); 
  PnlVect *v = pnl_vect_new(); 
  M = 10000; 
 
  /* rng must be initialized. When sseed=0, a default 
     value depending on the generator is used */ 
     pnl_rng_sseed(rng, 0); 
 
  for (i=0 ; i<M ; i++) 
  { 
    /* Simulates a normal random vector in R^{10} */ 
    pnl_vect_rng_normal(v, 10, rng); 
    /* Do something with v */ 
  } 
 
  pnl_vect_free(&v); 
  pnl_rng_free(&rng); /* Frees the generator */ 
  exit(0); 
}
#include <stdlib.h> 
#include <time.h> 
#include "pnl/pnl_random.h" 
 
int main () 
{ 
  int i, M; 
  double E; 
  PnlRng *rng = pnl_rng_create(PNL_RNG_MERSENNE); 
  M = 10000; 
 
  /* rng must be initialized. */ 
  pnl_rng_sseed(rng, time (NULL)); 
 
  for (i=0 ; i<M ; i++) 
  { 
    /* Simulates an exponential random variable */ 
    E = pnl_rng_exp(1, rng); 
    /* Do something with E */ 
  } 
 
  pnl_rng_free(&rng); /* Frees the generator */ 
  exit(0); 
}

6.2 The rand interface (deprecated)

Note: For backward compatibility with older versions of the PNL, we still provide the old rand interface to random number generation although we strongly encourage users to use the new rng interface (see section 6.1).

Every generator is identified by an integer valued macro. One must NOT refer to a generator using directly the value of the macro PNL_RNG_XXX because there is no warranty that the order used to store the generators will remain the same in future releases. Instead, one should call generators directly using their macro names.

The initial seeds of all the generators are fixed by the function pnl_rand_init but you can change it by calling pnl_rand_sseed.

Before starting to use random number generators, you must initialize them by calling

Once a generator is chosen, there are several functions available in the library to draw samples according to a given law.

The following functions return one sample from a specified law.

The following functions take an already existing PnlVect * as its first argument and fill each entry of the vector with a sample from the specified law. All the entries are independent. The difference between n-samples from a distribution in dimension 1, and one sample from the same distribution in dimension n only matters when using a Quasi random number generator.

The following functions take an already existing PnlMat * as first argument and fill each entry of the vector with a sample from the specified law. All the entries are in-dependant. On return, the matrix M is of size samples x dimension. The rows of M are independently and identically distributed. Each row is a sample from the given law in dimension dimension.

Because of the use of Quasi random number generators, you may need to draw a set of samples at once because they represent one sample from a multi-dimensional distribution. The following function enables to draw one sample from the dimension-dimensional standard normal distribution and store it so that you can access the elements individually afterwards.