From 00f78dd646cbdd382c69c8a6b8953652a1cafd4b Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Mon, 14 Dec 2015 22:37:56 +0000 Subject: [PATCH] Add missing files from last commit git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6273 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- lib/init_random_seed.c | 76 ++++++++++++++++++++++++++++++++++++++++ lib/init_random_seed.f90 | 55 +++++++++++++++++++++++++++++ lib/init_random_seed.h | 20 +++++++++++ 3 files changed, 151 insertions(+) create mode 100644 lib/init_random_seed.c create mode 100644 lib/init_random_seed.f90 create mode 100644 lib/init_random_seed.h diff --git a/lib/init_random_seed.c b/lib/init_random_seed.c new file mode 100644 index 000000000..75ee932b6 --- /dev/null +++ b/lib/init_random_seed.c @@ -0,0 +1,76 @@ +#include "init_random_seed.h" + +#include +#include +#include +#include +#include +#include + +/* basic PRNG to use for improving the basic seed selection */ +static unsigned lcg (uint64_t seed) +{ + if (0 ==seed) + { + seed = UINT64_C(104729); + } + else + { + seed %= UINT64_C(4294967296); + } + seed = (seed * UINT64_C(279470273)) % UINT64_C(4294967291); + return seed % UINT64_MAX; +} + +/* Generate a good PRNG seed value */ +void init_random_seed(void) +{ + unsigned seed = 0u; + int have_seed = 0; + + // try /dev/urandom for an initial seed + int random_source; + if (0 == (random_source = open ("/dev/urandom", O_RDONLY))) + { + size_t random_data_length = 0; + have_seed = -1; + while (random_data_length < sizeof seed) + { + ssize_t result = read (random_source, &seed + random_data_length, (sizeof seed) - random_data_length); + if (result < 0) + { + // error, unable to read /dev/random + have_seed = 0; + } + random_data_length += result; + } + close (random_source); + } + if (!have_seed) + { + // fallback to XOR:ing the time and pid + seed = time (NULL) ^ getpid (); + seed = lcg (seed); + } + srand (seed); +} + +#ifdef TEST +#include + +int main (int argc, char * argv[]) +{ + init_random_seed (); + int i, j; + int r[10][4]; + for (i = 0; i < 10; ++i) + { + for (j = 0; j < 4; ++j) + { + printf ("%10d ", rand ()); + } + printf ("\n"); + } + return 0; +} +#endif diff --git a/lib/init_random_seed.f90 b/lib/init_random_seed.f90 new file mode 100644 index 000000000..7d85f9ddb --- /dev/null +++ b/lib/init_random_seed.f90 @@ -0,0 +1,55 @@ +! +! Generate a seed for the RANDOM_NUMBER PRNG that is guaranteed to be +! unique even if many processes are started simultaneously +! +subroutine init_random_seed() + use iso_fortran_env, only: int64 + implicit none + integer, allocatable :: seed(:) + integer :: i, n, un, istat, dt(8), pid + integer(int64) :: t + + call random_seed(size = n) + allocate(seed(n)) + ! First try if the OS provides a random number generator + open(newunit=un, file="/dev/urandom", access="stream", & + form="unformatted", action="read", status="old", iostat=istat) + if (istat == 0) then + read(un) seed + close(un) + else + ! Fallback to XOR:ing the current time and pid. The PID is + ! useful in case one launches multiple instances of the same + ! program in parallel. + call system_clock(t) + if (t == 0) then + call date_and_time(values=dt) + t = (dt(1) - 1970) * 365_int64 * 24 * 60 * 60 * 1000 & + + dt(2) * 31_int64 * 24 * 60 * 60 * 1000 & + + dt(3) * 24_int64 * 60 * 60 * 1000 & + + dt(5) * 60 * 60 * 1000 & + + dt(6) * 60 * 1000 + dt(7) * 1000 & + + dt(8) + end if + pid = getpid() + t = ieor(t, int(pid, kind(t))) + do i = 1, n + seed(i) = lcg(t) + end do + end if + call random_seed(put=seed) +contains + ! This simple PRNG might not be good enough for real work, but is + ! sufficient for seeding a better PRNG. + function lcg(s) + integer :: lcg + integer(int64) :: s + if (s == 0) then + s = 104729 + else + s = mod(s, 4294967296_int64) + end if + s = mod(s * 279470273_int64, 4294967291_int64) + lcg = int(mod(s, int(huge(0), int64)), kind(0)) + end function lcg +end subroutine init_random_seed diff --git a/lib/init_random_seed.h b/lib/init_random_seed.h new file mode 100644 index 000000000..aa9500514 --- /dev/null +++ b/lib/init_random_seed.h @@ -0,0 +1,20 @@ +#ifndef INIT_RANDOM_SEED_H__ +#define INIT_RANDOM_SEED_H__ + +#ifdef __cplusplus +exten "C" { +#endif + + /* + * Generate a seed for the RANDOM_NUMBER PRNG that is guaranteed to + * be unique even if many processes are started simultaneously + * + * Not suitable for multi-threaded requirements + */ + void init_random_seed (void); + +#ifdef __cplusplus +} +#endif + +#endif