SRAND64(3S)SRAND64(3S)NAME
srand64, drand64, drand64_advance, drand64_get, drand64_getv,
drand64_maxthreads, drand64_set, drand64_setv, drand64_thread - Thread-
safe parallel 64-bit random number generator
SYNOPSIS
Fortran synopsis:
REAL FUNCTION SRAND64 (harvest)
REAL harvest
DOUBLE PRECISION FUNCTION DRAND64 (harvest)
DOUBLE PRECISION harvest
SUBROUTINE DRAND64_ADVANCE (count)
INTEGER*8 count
SUBROUTINE DRAND64_GET (seed, count, thread)
INTEGER*8 seed, count
INTEGER thread
SUBROUTINE DRAND64_GETV (state, count)
INTEGER*8 state(*), count(*)
INTEGER FUNCTION DRAND64_MAXTHREADS ()
SUBROUTINE DRAND64_SET (seed)
INTEGER*8 seed
SUBROUTINE DRAND64_SETV (state, count)
INTEGER*8 state(*), count(*)
INTEGER FUNCTION DRAND64_THREAD (thread)
INTEGER thread
C/C++ synopsis:
#include <scsl.h>
float srand64 (float *harvest);
double drand64 (double *harvest);
void drand64_advance (long long count);
void drand64_get (long long *seed, long long *count, int thread);
void drand64_getv (long long state[], long long count[]);
int drand64_maxthreads (void);
Page 1
SRAND64(3S)SRAND64(3S)
void drand64_set (long long seed);
void drand64_setv (long long state[], long long count[]);
int drand64_thread (int thread);
IMPLEMENTATION
These routines are part of the SCSL Scientific Library and can be loaded
using either the -lscs or the -lscs_mp option. The -lscs_mp option
directs the linker to use the multi-processor version of the library.
When linking to SCSL with -lscs or -lscs_mp, the default integer size is
4 bytes (32 bits). Another version of SCSL is available in which integers
are 8 bytes (64 bits). This version allows the user access to larger
memory sizes and helps when porting legacy Cray codes. It can be loaded
by using the -lscs_i8 option or the -lscs_i8_mp option. A program may
use only one of the two versions; 4-byte integer and 8-byte integer
library calls cannot be mixed.
The C and C++ prototypes shown above are appropriate for the 4-byte
integer version of SCSL. When using the 8-byte integer version, the
variables of type int become long long and the <scsl_i8.h> header file
should be included.
DESCRIPTION
These routines comprise a 64-bit thread-safe parallel random number
generator that is based on the linear congruent sequence
Y(n+1) = (a X(n) + c) mod 2^64.
The parameters a and c are chosen from Knuth, The Art of Computer
Programming , Vol. 2, 3rd edition, pp. 106-108:
a = 6364136223846793005
c = 1
Y(n+1) is then converted to a floating point value in the range [0,1).
The thread safety is ensured by separating the RNG state for each thread.
Thus, each thread generates an independent random sequence starting from
predefined values. Up to drand64_maxthreads() parallel streams of random
numbers can be supported simultaneously.
srand64
This function returns a single precision random number in the range
[0,1); the same value is returned in the argument, if provided.
drand64
This function returns a double precision random number in the range
[0,1); the same value is returned in the argument, if provided.
drand64_advance
Page 2
SRAND64(3S)SRAND64(3S)
This routine advances the internal state table entries for the
calling thread as if srand64() or drand64() had been called count
times.
drand64_get
This routine obtains the starting point of srand64() and drand64(),
as well as the invocation count for the thread specified in the
third argument.
drand64_getv
This routine provides the internal state of srand64() and drand64().
The arguments are arrays of seeds and invocation counts that can be
given as arguments to drand64_setv(). The array arguments must have
at least drand64_maxthreads() elements.
drand64_maxthreads
This function returns the maximum number of random number streams
that can be generated in parallel. The internal state tables used
in drand64_getv() and drand64_setv() have drand64_maxthreads()
entries.
drand64_set
This routine sets the starting point of srand64() and drand64(). By
default the generator is initialized to -1.
drand64_setv
This routine sets the internal state of srand64() and drand64().
The arguments are arrays of seeds and invocation counts, as returned
by drand64_getv, for example. The array arguments must have
drand64_maxthreads() elements.
drand64_thread
After a call this routine, the next invocations of srand64() and
drand64() will have the same effect as if called from the base
thread number specified in the argument to drand64_thread().
This function returns the base thread number that had previously
been generating the random sequence.
EXAMPLES
Below are several usage examples for RAND64 routines.
Example 1: Initialize the internal RNG state table with a single seed
value and generate a random number for each thread.
Fortran 77:
EXTERNAL SRAND64
REAL SRAND64
INTEGER*8 SEED
REAL S1, DUMMY
SEED = 1
Page 3
SRAND64(3S)SRAND64(3S)
CALL DRAND64_SET(SEED)
C Each thread gets a different random number
C$OMP PARALLEL PRIVATE(S1, DUMMY)
S1 = SRAND64(DUMMY)
C$OMP END PARALLEL
C/C++:
#include <scsl.h>
float s1, dummy;
long long seed = 1LL;
drand64_set(seed);
/* Each thread gets a different random number */
#pragma omp parallel private(s1, dummy)
{
s1 = srand64(&dummy);
}
Example 2: After saving the RNG state table, generate 11 random numbers
for each thread. Then restore the state table and use drand64_advance()
to "skip" 10 random numbers. The next random number generated for each
thread should be identical to the 11th value from the original stream.
Fortran 90:
INTEGER(KIND=8), DIMENSION(:), ALLOCATABLE :: STATE, COUNT
EXTERNAL DRAND64_MAXTHREADS, OMP_GET_THREAD_NUM, DRAND64
INTEGER :: I, TABLE_SIZE, DRAND64_MAXTHREADS, OMP_GET_THREAD_NUM
REAL(KIND=8) :: D1, DUMMY, DRAND64
TABLE_SIZE = DRAND64_MAXTHREADS()
ALLOCATE(STATE(TABLE_SIZE))
ALLOCATE(COUNT(TABLE_SIZE))
CALL DRAND64_GETV(STATE, COUNT)
!$OMP PARALLEL PRIVATE(I, D1, DUMMY)
DO I = 1, 11
D1 = DRAND64(DUMMY)
END DO
PRINT *, OMP_GET_THREAD_NUM(), D1
!$OMP END PARALLEL
CALL DRAND64_SETV(STATE, COUNT)
!$OMP PARALLEL PRIVATE(D1, DUMMY)
DRAND64_ADVANCE(10_8)
D1 = DRAND64(DUMMY)
PRINT *, OMP_GET_THREAD_NUM(), D1
!$OMP END PARALLEL
C/C++:
#include <scsl.h>
Page 4
SRAND64(3S)SRAND64(3S)
#include <omp.h>
#include <stdlib.h>
#include <stdio.h>
long long *state, *count;
int i, table_size;
double d1, dummy;
table_size = drand64_maxthreads();
state = (long long *) malloc(table_size * sizeof(long long));
count = (long long *) malloc(table_size * sizeof(long long));
drand64_getv(state, count);
#pragma omp parallel private(i, d1, dummy)
{
for (i = 0; i < 11; i++)
d1 = drand64(&dummy);
printf("%d, %g0, omp_get_thread_num(), d1);
}
drand64_setv(state, count);
#pragma omp parallel private(d1, dummy)
{
drand64_advance(10LL);
d1 = drand64(&dummy);
printf("%d, %g0, omp_get_thread_num(), d1);
}
Example 3: Using only a single thread, generate 10 independent streams
of random numbers.
Fortran 77:
EXTERNAL DRAND64_THREAD, SRAND64
INTEGER DRAND64_THREAD
REAL SRAND64
INTEGER I, J, OLDID
REAL STREAM(1000,10), DUMMY
DO J = 1, 10
OLDID = DRAND64_THREAD(J-1)
DO I = 1, 1000
STREAM(I, J) = SRAND64(DUMMY)
END DO
END DO
C RESTORE ORIGINAL BASE THREAD
OLDID = DRAND64_THREAD(0)
C/C++:
#include <scsl.h>
int i, j, oldid;
float stream[10][1000], dummy;
for (i = 0; i < 10; i++) {
oldid = drand64_thread(i);
Page 5
SRAND64(3S)SRAND64(3S)
for (j = 0; j < 1000; j++)
stream[i][j] = srand64(&dummy);
}
/* restore original base thread */
oldid = drand64_thread(0);
CAUTIONS
Care is required when using drand64_thread() in parallel regions. If
multiple parallel threads possess the same RAND64 base thread number as
assigned with a call to drand64_thread(), then thread safety will be
compromised, with different threads no longer producing independent
random sequences. The statistical randomness of the resulting individual
sequences will also likely be degraded.
SEE ALSOINTRO_SCSL(3S), DRAND48(3C)
Page 6