【问题标题】:Random number generator produces same sequence even though it's seeded随机数生成器产生相同的序列,即使它是播种的
【发布时间】:2016-05-18 16:04:30
【问题描述】:

我对 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

我每次运行代码时都会得到这个确切的序列。我什至尝试重新编译以查看生成器是否会在编译时重新设置种子。

【问题讨论】:

  • 快速谷歌搜索返回:如果调用 RANDOM_SEED 时不带参数,它会被初始化为默认状态。如果您没有在参数中提供任何内容,您似乎每次都会得到相同的随机数序列。
  • 是的,我也看过那篇文章,但后来我进一步阅读(例如在英特尔论坛上),如果你在没有参数的情况下调用 random_seed,计算机将获取日期/时间以用作默认为种子。我对此的解释是,如果在没有参数的情况下调用 RANDOM_SEED,计算机将自动播种
  • 如前所述,行为取决于您的编译器。请添加详细信息。无论您使用的哪个编译器都选择使用可重复序列,这是“显而易见的”,但知道哪个编译器这样做将使其他读者受益。
  • another question(cmets 和答案)中可以看到依赖于编译器的性质。
  • 你的意思是让这些行号表明你正在使用固定格式的源代码,还是仅仅作为外部评论?如果它打算作为固定形式,那么您的缩进就会被破坏。如果不是,则它不是可复制运行的。 [这两个问题都不是非常重要的问题,而是未来需要考虑的问题。]

标签: random fortran


【解决方案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

【讨论】:

    猜你喜欢
    • 2015-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多