【问题标题】:Random number generator in PGI Fortran not so randomPGI Fortran 中的随机数生成器不是那么随机
【发布时间】:2016-01-14 19:21:23
【问题描述】:

下面的代码只是生成一个简单的三元组随机数:

program testrand

integer, parameter :: nz = 160, nf = 160, nlt = 90

real :: tmpidx(3)
integer :: idxarr(3), idx1, idx2, idx3, seed_size, ticks
integer, allocatable :: seed(:)

call random_seed(size=seed_size)
allocate(seed(seed_size))

call system_clock(count=ticks)
seed = ticks+37*(/(i-1, i=1,seed_size)/)
call random_seed(put=seed)

deallocate(seed)

call random_number(tmpidx)
idxarr = tmpidx * (/nz, nf, nlt/)
idx1 = max(1,idxarr(1))
idx2 = max(1,idxarr(2))
idx3 = max(1,idxarr(3))
print *,idx1, idx2, idx3

end program

我用 gfortran 编译并运行了几次,我得到:

> gfortran testrand.f90
> ./a.out
          74          98          86
> ./a.out
         113           3          10
> ./a.out
          44         104          27

看起来很随意。现在我用 PGI Fortran 编译并运行了几次:

> pgf90 testrand.f90
> ./a.out
            1            1            1
> ./a.out
            1            1            1
> ./a.out
            1            1            1

当然,没有办法完全确定,但我怀疑这不是随机的。 :) 有人知道这里发生了什么吗?有人知道使用 PGI Fortran 获取随机数的正确方法吗?

【问题讨论】:

    标签: random fortran fortran90 gfortran pgi


    【解决方案1】:

    不知何故,PGI 没有像在 GNU 编译器中那样实现system_clock。不知道为什么,最近在做和你类似的事情时发现的。

    要了解我在说什么,只需在调用system_clock 后打印ticks。很有可能你总是得到0 使用 PGI 和使用 GNU 编译器的不同数字。为了解决您的问题,您可以调整下面的代码。它是代码的略微修改版本,您可以在 GNU fortran web site 获得代码

    program testrand
    use iso_fortran_env, only: int64
    
        integer, parameter :: nz = 160, nf = 160, nlt = 90
        real :: tmpidx(3)
        integer :: idxarr(3), idx1, idx2, idx3, seed_size, ticks
        integer, allocatable :: seed(:)
    
        call random_seed(size=seed_size)
        allocate(seed(seed_size))
    
        ! call system_clock(count=ticks)
        ! seed = ticks+37*(/(i-1, i=1,seed_size)/)
        ! call random_seed(put=seed)
        ! 
        ! deallocate(seed)
    
        call init_random_seed()
    
        call random_number(tmpidx)
        idxarr = tmpidx * (/nz, nf, nlt/)
        idx1 = max(1,idxarr(1))
        idx2 = max(1,idxarr(2))
        idx3 = max(1,idxarr(3))
        print *,idx1, idx2, idx3
    
    contains
        !
        subroutine init_random_seed()
            implicit none
            integer, allocatable :: seed(:)
            integer :: i, n, istat, dt(8), pid
            integer(int64) :: t
    
            integer, parameter :: un=703
    
            call random_seed(size = n)
            allocate(seed(n))
            ! First try if the OS provides a random number generator
            open(unit=un, file="/dev/urandom", access="stream", &
                form="unformatted", action="read", status="old", iostat=istat)
            if (istat == 0) then
                read(un) seed
                close(un)
            else
                ! 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)
            !print*, "optimal seed = ", seed
        end subroutine init_random_seed
        !
        function lcg(s)
            integer :: lcg
            integer(int64), intent(in out) :: 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), 8)), kind(0))
        end function lcg
        !
        !this option is especially used for pgf90 to provide a getpid() function
        !> @brief Returns the process ID of the current process
        !! @todo write the actual code, for now returns a fixed value
        !<
        function getpid()result(pid)
            integer pid
            pid = 53 !just a prime number, no special meaning
        end function getpid
    end program
    

    【讨论】:

    • 确认!我已经看到了,希望避免它!尽管如此 date_and_time() 似乎工作得更好。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-01
    • 1970-01-01
    • 2017-09-27
    相关资源
    最近更新 更多