Possible sources for random numbers

Two points - firstly, the example is in Fortran, but I think he should stick to any language; secondly, the built-in random number generators are not really random and other generators exist, but we are not interested in using them for what we do.

Most discussions of random seeds confirm that if the program does not sow it at run time, then the seed is generated at compile time. Thus, the same sequence of numbers is generated each time the program starts, which is not suitable for random numbers. One way to overcome this is to plant a random number generator with a system clock.

However, when working in parallel with MPI on a multi-core machine, the approach to the system clock for us poses the same problems. While the sequences changed from run to run, all processors got the same system clock and thus the same random seed and the same sequences.

So, consider the following code example:

PROGRAM clock_test IMPLICIT NONE INCLUDE "mpif.h" INTEGER :: ierr, rank, clock, i, n, method INTEGER, DIMENSION(:), ALLOCATABLE :: seed REAL(KIND=8) :: random INTEGER, PARAMETER :: OLD_METHOD = 0, & NEW_METHOD = 1 CALL MPI_INIT(ierr) CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) CALL RANDOM_SEED(SIZE=n) ALLOCATE(seed(n)) DO method = 0, 1 SELECT CASE (method) CASE (OLD_METHOD) CALL SYSTEM_CLOCK(COUNT=clock) seed = clock + 37 * (/ (i - 1, i = 1, n) /) CALL RANDOM_SEED(put=seed) CALL RANDOM_NUMBER(random) WRITE(*,*) "OLD Rank, dev = ", rank, random CASE (NEW_METHOD) OPEN(89,FILE='/dev/urandom',ACCESS='stream',FORM='UNFORMATTED') READ(89) seed CLOSE(89) CALL RANDOM_SEED(put=seed) CALL RANDOM_NUMBER(random) WRITE(*,*) "NEW Rank, dev = ", rank, random END SELECT CALL MPI_BARRIER(MPI_COMM_WORLD, ierr) END DO CALL MPI_FINALIZE(ierr) END PROGRAM clock_test 

That when launched on my workstation with two cores gives:

 OLD Rank, dev = 0 0.330676306089146 OLD Rank, dev = 1 0.330676306089146 NEW Rank, dev = 0 0.531503215980609 NEW Rank, dev = 1 0.747413828750221 

So, we overcame the clock problem by reading the seed from /dev/urandom instead. Thus, each core gets its own random number.

What other seed approaches exist that will work in a multi-core MPI system and will still be unique on every kernel, from launch to launch?

+7
source share
2 answers

If you look at Random Numbers in Scientific Computing: An Introduction from Katzgrabber (which is an excellent, clear discussion of using PRNG for technical computing), in parallel they suggest using a hash function of time and a PID to generate seed. From section 7.1:

 long seedgen(void) { long s, seed, pid; pid = getpid(); s = time ( &seconds ); /* get CPU seconds since 01/01/1970 */ seed = abs(((s*181)*((pid-83)*359))%104729); return seed; } 

of course in fortran it will be something like

 function seedgen(pid) use iso_fortran_env implicit none integer(kind=int64) :: seedgen integer, intent(IN) :: pid integer :: s call system_clock(s) seedgen = abs( mod((s*181)*((pid-83)*359), 104729) ) end function seedgen 

Sometimes itโ€™s also convenient to be able to pass over this time, rather than calling it from seedgen , so when you test, you can give it fixed values, which then generate a reproducible (== verified) sequence.

+10
source

System time usually returns (or at least easily converts) to an integer type: just add the process rank to the value and use it to seed the random number generator.

0
source

All Articles