# spral_random - Pseudo-random number generator¶

## Purpose¶

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 specified by the user. Otherwise a default seed of 486502 is used.

### Version history¶

2016-09-08 Version 1.1.0
2014-04-07 Version 1.0.0
Initial release

## Routines¶

### Random Number Generation¶

function random_real(state[, positive])

Return a real uniformly at random from the interval $$(-1,1)$$ (positive =.true.) or $$(0,1)$$ (positive =.false.).

Parameters: state [random_state,inout] :: current state of RNG. positive [logical,in,default=.false.] :: if .true., sample from $$(0,1)$$; otherwise, sample from $$(-1,1)$$. random_real [real] :: Sampled value.
function random_integer(state, n)

Return an integer uniformly at random from the interval $$[1,n]$$.

Parameters: state [random_state,inout] :: current state of the RNG. n [integer(kind),in] :: largest value in range to be sampled. kind may be either default or long integer (return type will match). random_integer [integer(kind)] :: Sampled value.
function random_logical(state)

Return a logical with equal probability of being .true. or .false..

Parameters: state [random_state,inout] :: current state of the RNG. random_logical [logical] :: Sampled value.

### Get/Set Random Seed¶

function random_get_seed(state)

Return the current random seed stored in state.

The stream of random numbers generated after this call can be reproduced through the same sequence of calls after seed has been passed to random_set_seed().

Parameters: state [random_state,in] :: state variable to extract state from random_get_seed :: current random seed
subroutine random_set_seed(state, seed)

Set the random seed stored in the state variable

Parameters: state [random_state,inout] :: state variable to set seed for. seed [integer,in] :: new seed.

## Data Types¶

type random_state

State of the random number generator. Compontents are not available to the user, but may be examined and altered through calls to random_get_seed() and random_set_seed() respectively.

## Example¶

The following code:

! examples/Fortran/random.f90 - Example code for SPRAL_RANDOM package
program random_example
use spral_random
implicit none

integer, parameter :: long = selected_int_kind(18)

type(random_state) :: state
integer :: seed

! Store initial random seed so we can reuse it later
seed = random_get_seed(state)

! Generate some random values
write(*,"(a)") "Some random values"
write(*,"(a,f16.12)") "Sample Unif(-1,1)               = ", &
random_real(state)
write(*,"(a,f16.12)") "Sample Unif(0,1)                = ", &
random_real(state, positive=.true.)
write(*,"(a,i16)") "Sample Unif(1, ..., 20)         = ", &
random_integer(state, 20)
write(*,"(a,i16)") "Sample Unif(1, ..., 20*huge(0)) = ", &
random_integer(state, 20_long*huge(0))
write(*,"(a,l16)") "Sample B(1,0.5)                 = ", &
random_logical(state)

! Restore initial seed
call random_set_seed(state, seed)

! Generate the same random values
write(*,"(/a)") "The same random values again"
write(*,"(a,f16.12)") "Sample Unif(-1,1)               = ", &
random_real(state)
write(*,"(a,f16.12)") "Sample Unif(0,1)                = ", &
random_real(state, positive=.true.)
write(*,"(a,i16)") "Sample Unif(1, ..., 20)         = ", &
random_integer(state, 20)
write(*,"(a,i16)") "Sample Unif(1, ..., 20*huge(0)) = ", &
random_integer(state, 20_long*huge(0))
write(*,"(a,l16)") "Sample B(1,0.5)                 = ", &
random_logical(state)

end program random_example

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 Unif(1, ..., 20*huge(0)) =      33572664025
Sample B(1,0.5)                 =                F

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

## Method¶

We use a linear congruential generator of the following form:

$X_{n+1} = (aX_n + c)\quad \mathrm{mod}\; m$

with the following constants

$\begin{split}a = 1103515245, \\ c = 12345, \\ m = 2^{31}.\end{split}$

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 routines random_get_seed() and random_set_seed() allow the user to get and set the current value of $$X_n$$. The default seed is $$X_0 = 486502$$.

### In random_real()¶

Samples from $$\mathrm{Unif}(0,1)$$ are generated as

$\frac{\mathrm{real}(X_n)}{\mathrm{real}(m)},$

and samples from $$\mathrm{Unif}(-1,1)$$ are generated as

$1−\frac{\mathrm{real}(2X_n)}{\mathrm{real}(m)}.$

### In random_integer()¶

Samples from $$\mathrm{Unif}(1,\ldots,n)$$ are generated as

$\mathrm{int}\left(X_n\frac{\mathrm{real}(n)}{\mathrm{real}(m)}\right) + 1$

### In random_logical()¶

Returns the value of the Fortran expression

(1 .eq. random_integer(state,2))