# RANDOM: Pseudo-random Number Generator

## Pseudo-random Number Generator

C User Guide
This package generates pseudo-random numbers using a linear congruential generator. It should generate the same random numbers using any standards compliant Fortran compiler on any architecture so long as the default integer and real kinds are the same.

The seed can optionally be observed or speciﬁed by the user.

### Major version history

2014-04-07 Version 1.0.0
Initial release

### 2.1 Installation

Please see the SPRAL install documentation.

### 2.2 Usage overview

#### 2.2.1 Calling sequences

Access to the package requires inclusion of either spral.h (for the entire SPRAL library) or spral_random.h (for just the relevant routines). i.e.

#include "spral.h"

The following functions are available to the user:

• random_real() generates a real uniformally at random from the interval $\left(-1,1\right)$ or $\left(0,1\right)$.
• random_integer() generates an integer uniformally at random from the interval $\left[1,\dots ,n\right]$.
• random_logical() generates a random boolean value.

#### 2.2.2 Seed initialization

The random number generator’s state is stored in the variable state that is common to all calls. Before its ﬁrst use, state should be initialized by the user to an initial seed value.

For convenience, the preprocessor macro SPRAL_RANDOM_INITIAL_SEED has been deﬁned, and state may be declared and initialized using a statement of the following form:

int state = SPRAL_RANDOM_INITIAL_SEED;

At any time the user may change the seed, for example to restore a previous value. The same sequence of calls following the (re-)initialization of seed to the same value will produce the same pseudo-random values.

### 2.3 Random Generation Subroutines

#### 2.3.1 random_real()

To generate a real uniformly at random from the interval $\left(-1,1\right)$ or $\left(0,1\right)$, the following routine is provided.
double spral_random_real(int *state, bool positive);

The return value is a sample from $Unif\left(0,1\right)$ if positive is true, or from $Unif\left(-1,1\right)$ if it is false.

*state
is the current state of the random number generator. Before the ﬁrst call (only) to a package routine, it must be initialized by the user as described in Section 2.2.2.
positive
controls whether the return value is required to be positive. If positive is true, the sample will be returned from the interval $\left(0,1\right)$. Otherwise, the sample will be returned from the interval $\left(-1,1\right)$.

#### 2.3.2 random_integer()

To generate an integer uniformly at random from the interval $\left[1,n\right]$, the following routine is provided.
int spral_random_integer(int *state, int n);

The return value is a sample from $Unif\left(1,\dots ,n\right)$.

*state
is the current state of the random number generator. Before the ﬁrst call (only) to a package routine, it must be initialized by the user as described in Section 2.2.2.
n
speciﬁes the upper bound of the range to be sampled.

#### 2.3.3 random_logical()

To generate a logical with equal probability of being .true. or .false., the following routine is provided.
bool spral_random_logical(int *state);

The return value has an equal probability of being true or false.

*state
is the current state of the random number generator. Before the ﬁrst call (only) to a package routine, it must be initialized by the user as described in Section 2.2.2.

### 2.4 Method

#### 2.4.1 Pseudo-random number generation

We use a linear congruential generator (LCG) of the following form:

${X}_{n+1}=\left(a{X}_{n}+c\right)\phantom{\rule{1em}{0ex}}modm$

with the following constants

$\begin{array}{rcll}a& =& 1103515245,& \text{}\\ c& =& 12345,& \text{}\\ m& =& {2}^{31}.& \text{}\end{array}$

According to Wikipedia, this is the same as used in glibc.

The LCG is evolved before each sample is taken, and the sample is based on the new value.

The variable state stores the current value of ${X}_{n}$, and the macro SPRAL_RANDOM_INITIAL_SEED speciﬁes the seed ${X}_{0}=486502$.

#### 2.4.2 random_real()

If positive is present with value .true., a sample from $Unif\left(0,1\right)$ is generated as

$\frac{\mathtt{\text{real}}\left({X}_{n}\right)}{\mathtt{\text{real}}\left(m\right)},$

otherwise, a sample from $Unif\left(-1,1\right)$ is generated as

$1-\frac{\mathtt{\text{real}}\left(2{X}_{n}\right)}{\mathtt{\text{real}}\left(m\right)}.$

#### 2.4.3 random_int()

A random sample from the discrete distribution $Unif\left(1,\dots ,n\right)$ is generated as

$\mathtt{\text{int}}\left({X}_{n}\frac{\mathtt{\text{real}}\left(n\right)}{\mathtt{\text{real}}\left(m\right)}\right)+1.$

#### 2.4.4 random_logical()

A random logical value is generated by evaluating the expression

$\left(1\phantom{\rule{1em}{0ex}}.eq.\phantom{\rule{1em}{0ex}}spral\text{_}random\text{_}integer\left(state,2\right)\right).$

### 2.5 Example

The following example code:

/* examples/C/random.c - Example code for SPRAL_RANDOM package */
#include "spral.h"
#include <stdio.h>

#define bool2str(VAL) ( (VAL) ? "true" : "false" )

void main(void) {
int state = SPRAL_RANDOM_INITIAL_SEED;

// Store initial random seed so we can reuse it later
int initial_seed = state;

// Generate some random values
printf("\nSome random values\n");
printf("Sample Unif(-1,1)       = %16.12f\n",
spral_random_real(&state, false));
printf("Sample Unif(0,1)        = %16.12f\n",
spral_random_real(&state, true));
printf("Sample Unif(1, ..., 20) = %16d\n",
spral_random_integer(&state, 20));
printf("Sample B(1,0.5)         = %16s\n",
bool2str(spral_random_logical(&state)));

// Restore initial seed
state = initial_seed;

// Generate the same random values
printf("\nThe same random values again\n");
printf("Sample Unif(-1,1)       = %16.12f\n",
spral_random_real(&state, false));
printf("Sample Unif(0,1)        = %16.12f\n",
spral_random_real(&state, true));
printf("Sample Unif(1, ..., 20) = %16d\n",
spral_random_integer(&state, 20));
printf("Sample B(1,0.5)         = %16s\n",
bool2str(spral_random_logical(&state)));
}
Produces the following output:

Some random values
Sample Unif(-1,1)       =   0.951878630556
Sample Unif(0,1)        =   0.395779648796
Sample Unif(1, ..., 20) =                3
Sample B(1,0.5)         =            false

The same random values again
Sample Unif(-1,1)       =   0.951878630556
Sample Unif(0,1)        =   0.395779648796
Sample Unif(1, ..., 20) =                3
Sample B(1,0.5)         =            false