`random_seed(get)` immediately after `random_seed(put)`: behavior of various compilers

Consider the following piece of code. It gets the current random seed (= seed0), modifies it (=seed1), put the modified seed back, and then get immediately the random seed again (=seed2). As far as I understand, we should have seed1 == seed2 so that the program should print 0, unless seed1 is not a valid seed.

program testrand
implicit none
integer :: n
integer, allocatable :: seed0(:), seed1(:), seed2(:)

! Initialize the seed, and get its size.
call random_seed()
call random_seed(size=n)
allocate (seed0(n), seed1(n), seed2(n))

! Get the current seed.
call random_seed(get=seed0)

! Modify the seed, and put it as the new seed.
seed1 = max(seed0 - 1, 1)   
! In most cases, `seed1` should still be a valid seed, no?
call random_seed(put=seed1)

! Get the new seed.
call random_seed(get=seed2)

! Check whether the new seed is the one we put.
print *, maxval(abs(seed2 - seed1))

end program testrand

The aforementioned speculation seems correct with gfortran, ifort, g95, flang, nvfortran, af95 (Absoft), and sunf95 (Oracle). However, with nagfor (NAG Fortran Compiler Release 7.0(Yurakucho) Build 7036), the printed number is never 0 on my machine (Ubuntu 20.04).

If we do not modify seed0 but set seed1=seed0, then all the compilers will print 0 as expected.

Did I overlook something about random_seed?

1 Like

It seems you missed two things. Suspected bugs should be reported to the vendor. You also need to consult the Fortran standard. From 18-007r1, page 407,

Computation of the seed from the argument PUT is performed in a
processor-dependent manner. The value assigned to GET need not be
the same as the value of PUT in an immediately preceding reference
to RANDOM_SEED. For example, following execution of the statements

       CALL RANDOM_SEED (PUT=SEED1)
       CALL RANDOM_SEED (GET=SEED2)

SEED2 need not equal SEED1.

There is some additional information in the standard.

4 Likes

Thanks, @kargl. I see. So, when receiving a seed from random_seed(put), the compiler may translate it into another one that has a different value but the same effect as a seed.

Totally unrelated, but this reminds me of the following remark made by Johann Wolfgang von Goethe about mathematicians.

(Mathematicians are like Frenchmen: whatever you say to them they translate into their own language and forthwith it is something entirely different.)

It is clear now. Thanks.

1 Like

Yes. It is likely permitted such that a vendor can defend against a poorly chosen seed. In gfortran, a user-specified seed is scrambled before actually seeding the prng.

/* Since a XOR cipher is symmetric, we need only one routine, and we
   can use it both for encryption and decryption.  */

static void
scramble_seed (uint64_t *dest, const uint64_t *src)
  {
     for (size_t i = 0; i < SZU64; i++)
        dest[i] = src[i] ^ xor_keys[i];
  }
3 Likes