随机数生成器生成相同的序列,即使它是种子

时间:2016-05-18 16:04:30

标签: random fortran

我对Fortran比较新,我正在尝试理解RANDOM_NUMBERRANDOM_SEED子例程。以下代码不断生成相同的随机数序列,尽管我将生成器播种到程序顶部的DO LOOP之外。

  1 PROGRAM TEST
  2 
  3         IMPLICIT NONE
  4         
  5         INTEGER :: I, OUTPUT
  6         REAL :: R
  7 
  8         CALL RANDOM_SEED()
  9 
 10         DO I=1, 10
 11                 CALL RANDOM_NUMBER(R)
 12                 OUTPUT = I*R
 13                 PRINT *,'Random number ', I, ' = ',  OUTPUT
 14         END DO
 15 
 16 END PROGRAM TEST

这是我运行代码时的输出

 Random number            1  =            0
 Random number            2  =            1
 Random number            3  =            2
 Random number            4  =            2
 Random number            5  =            1
 Random number            6  =            2
 Random number            7  =            0
 Random number            8  =            0
 Random number            9  =            3
 Random number           10  =            3

每次运行代码时都会得到这个确切的序列。我甚至尝试过重新编译,看看生成器是否会在编译时重新编译。

1 个答案:

答案 0 :(得分:1)

我不是专家,但是看some documentation,我认为您需要使用数字调用RANDOM_SEED,否则会将随机数生成器初始化为默认状态。

“默认状态”取决于实现,在某些平台上将是固定值。

如果你需要编写可移植代码,你应该做这样的事情,

 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