A fresh, nondeterministic seed, in [1, huge(int64)].
Folds the clock at its finest resolution together with a process-wide call counter, so two
calls differ even when the clock has not ticked between them, and so do two calls racing on
different threads -- the counter is incremented by an !$omp atomic capture, so no increment
is lost and no two callers see the same count. (In a build without OpenMP that directive is a
comment and the guarantee lapses; see the counter's declaration.) This is the
one procedure in the module that is not a pure function, and the one that is deliberately
not reproducible: a program that wants a reproducible run stores the value it got and passes
that back next time.
Two calls can only collide if their mixer outputs differ in nothing but the bit the range restriction clears -- one specific partner per call out of 2**64, which no run will meet.
Not cryptographic, and not a substitute for one: the clock is guessable and the counter is small. For anything an adversary must not predict, take the seed from a CSPRNG instead.
a nondeterministic seed in [1, huge(int64)]
function pf_random_seed() result(s) integer(int64) :: s !! a nondeterministic seed in `[1, huge(int64)]` integer(int64) :: counted, ticks, rate, ceiling_ ! Fetch-and-add, which is exactly what this needs -- `atomic capture` is the precise ! construct for it and is lock-free, where the named critical region this replaced ! serialised every caller through a lock for a single integer update. See the counter's ! own declaration for what holds when OpenMP is absent. !$omp atomic capture seed_call_counter = seed_call_counter + 1_int64 counted = seed_call_counter !$omp end atomic call system_clock(count=ticks, count_rate=rate, count_max=ceiling_) s = mix64(ieor(mix64(ieor(ticks, rate)), counted)) s = ibclr(s, 63) ! into [0, huge]; the mixer is otherwise a bijection if (s == 0_int64) s = 1_int64 end function pf_random_seed