在Fortran模块中生成随机数 [英] generating random numbers in a Fortran Module

查看:200
本文介绍了在Fortran模块中生成随机数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在我面临的问题是,在一个模块中,使用种子生成随机数用于函数循环,但每次调用该函数时,都会使用相同的随机数(因为种子显然是相同的),但是它假设它必须继续这个系列,或者至少它在调用之间必须是不同的。一种解决方案可能是主程序为模块提供了一个新的种子,但我认为这可能是另一个优雅的解决方案。
我使用 Mersenne Twister 生成器,由许多人建议。



新增



我的模块中的函数(它是一个函数包)基本上使用由种子生成的随机数进行Metropolis测试,出于某种原因,如果我放入

  module mymod 
使用mtmod
调用sgrnd(4357)!< - 此行导致编译错误
包含
myfunc(args)
隐式无
//声明等
!call sgrnd(4357)< - 如果我把这个调用放在这里compilator说ok,
!但是每次调用这个函数时重新开始随机数序列:(
....
!下面的部分在循环中
if(prob< grnd() )然后
!grnd()是随机数生成的
返回
else继续测试到循环结束
结束myfunc

但是如果我把那个fu放了在包含主程序(使用mtmod)中调用sgrnd(4357),然后调用myfunc,现在所有的东西都编译并运行得很好。为了清楚起见,我不想在主程序中使用这个长函数,它有70行代码,但似乎我没有逃脱。请注意,种子曾经被调用过。这些模拟现在具有物理意义,但是支付了这个价格。

解决方案

为了恢复我的观点,我不得不寻找我自己的答案,在这里(尝试一小时后)

主程序是

$ pre> ($,*)x + writerandnum()
write(*,*)x + writerandnum()
write(*,*)x + writerandnum()
结束程序callrtmod

这里是我的模块

 模块mymod 
隐式无
!------------- mt变量-------------
!默认种子
整数,参数:: defaultsd = 4357
!周期参数
整数,参数:: N = 624,N1 = N + 1

!状态向量的数组
整数,保存,维(0:N-1):: mt
整数,保存:: mti = N1
!-------- ------------------------------

包含
函数writerandnum
隐式none
real(8):: writerandnum

writerandnum = grnd()
!如果您愿意,也可以在这里执行Metropolis测试
end function writerandnum


!初始化子程序
子程序sgrnd(种子)
隐式无

整数,意图(in):: seed

mt(0)= iand(seed,-1)
do mti = 1,N-1
mt(mti)= iand(69069 * mt(mti-1), - 1 )
enddo

返回
结束子程序sgrnd
!--------------------------------- ------------------------------------------
!函数grnd在这里
!------------------------------------------- --------------------------------


子程序mtsavef(fname,forma )

字符(*),intent(in):: fname
字符,intent(in):: forma

选择大小写(forma)
case('u','U')
open(unit = 10,file = trim(fname),status ='UNKNOWN',form ='UNFORMATTED',&
position ='APPEND ')
write(10)mti
write(10)mt

case default
open(unit = 10,file = trim(fname),status =' UNKNOWN',form ='FORMATTED',&
position ='APPEND')
write(10,*)mti
write(10,*)mt

结束选择
关闭(10)

返回
结束子程序mtsavef

子程序mtsaveu(unum,forma)

整数,意图(in):: unum
字符,意图(in):: forma

选择案例(forma)
案例('u','U')
写入(unum)mti
写入(unum)mt

案例默认
写入(unum,*)mti
写入(unum,*)mt

结束选择

返回
结束子程序mtsaveu

子程序mtgetf(fname,forma)

字符(*),intent(in):: fname
字符,intent(in):: forma

select case(forma)
case('u','U')
open(unit = 10,file = trim(fname),status ='OLD',form ='UNFORMATTED')
read(10)mti
read(10)mt

case default
open(unit = 10,file = trim(fname), status ='OLD',form ='FORMATTED')
read( 10,*)mti
read(10,*)mt

结束选择
关闭(10)

返回
结束子程序mtgetf

子程序mtgetu(unum,forma)

整数,意图(in):: unum
字符,意图(in):: forma

选择案例(forma)
案例('u','U')
读取(unum)mti
读取(unum)mt

案例默认
读取(unum,*)mti
读取(unum,*)mt

结束选择

返回
结束子程序mtgetu


!======================================= ========

!随机数字发生器
! real(8)函数grnd()
函数grnd!agregue yo
隐式整数(a-z)
real(8)grnd!agregue yo
!周期参数
整数,参数:: M = 397,MATA = -1727483681
!常量向量a
整数,参数:: LMASK = 2147483647
!最低有效位r
整数,参数:: UMASK = -LMASK - 1
!最重要的w-r位
!回火参数
整数,参数:: TMASKB = -1658038656,TMASKC = -272236544

尺寸mag01(0:1)
数据mag01 / 0,MATA /
保存mag01
! mag01(x)= x * MATA for x = 0,1

TSHFTU(y)= ishft(y,-11)
TSHFTS(y)= ishft(y,7)
TSHFTT(y)= ishft(y,15)
TSHFTL(y)= ishft(y,-18)

if(mti.ge.N)then
!一次生成N个单词
if(mti.eq.N + 1)then
!如果sgrnd()没有被调用,
调用sgrnd(defaultsd)
!使用默认的初始种子
endif

do kk = 0,NM-1
y = ior(iand(mt(kk),UMASK),iand(mt(kk + 1),LMASK))
mt(kk)= ieor(ieor(mt(kk + M),ishft(y,-1)),mag01(iand(y,1)))
enddo
do kk = NM,N-2
y = ior(iand(mt(kk),UMASK),iand(mt(kk + 1),LMASK))
mt(kk)= ieor(ieor(mt(kk +(MN)),ishft(y,-1)),mag01(iand(y,1)))
enddo
y = ior(iand(mt(N-1 ),iand(mt(0),LMASK))
mt(N-1)= ieor(ieor(mt(M-1),ishft(y,-1)),mag01(iand y,1)))
mti = 0
endif

y = mt(mti)
mti = mti + 1
y = ieor(y,TSHFTU (y))
y = ieor(y,iand(TSHFTS(y),TMASKB))
y = ieor(y,iand(TSHFTT(y),TMASKC))
y = ieor(y ,TSHFTL(y))

if(y .lt。0)then
grnd =(dble(y)+ 2.0d0 ** 32)/(2.0d0 ** 32-1.0 d0)
else
grnd = dble(y)/(2.0d0 ** 32-1.0d0)
endif

返回
结束函数grnd


结束模块mymod

测试我的解决方案并投票给我; [当然,正如你所看到的,我修改了mt.f90代码以方便地包含在我的模块中,因此我可以将主程序与randon数字分开因此我可以在主节目旁边做Metropolis测试。主程序只是想知道是否接受了审判。我的解决方案确实为主程序提供了更多的清晰性。

Now I am facing the problem that in a module, with a seed I am generating random numbers to be used in a loop of a function but each time I call that function, the same random numbers are generated (because the seed is obviously the same) but it's supposed that it must continue the series or at least it must be different between calls. One solution could be that the main program gives a new seed to be used in the module but I think it there could be another elegant solution. I am using Mersenne Twister generator by suggestion of many people.

Added

My function in my module (it is a package of functions) escentially makes such a Metropolis test using random numbers generated by a seed, for some reason compilation complains if I put

    module mymod
    uses mtmod
    call sgrnd(4357)!<-- this line causes compilation error
    contains
    myfunc(args)
    implicit none
    // declarations etc
    !call sgrnd(4357) <-- if I put this call here compilator says ok,
    !but re-start random number series each time this function is called :(
    ....
    !the following part is inside a loop
    if (prob < grnd()) then
    !grnd() is random number generated
    return
    else continue testing to the end of the loop cycle
    end myfunc

But if I put that function in the contains of the main program (using mtmod too) and call sgrnd(4357) before contains section and the calls to myfunc, now everything compile and run nicely. For clarity, I didn't want to put that long function in the main program, it has 70 lines of code, but it seems I have no escape. Notice that so, the seed is once called. The simulations have now physical meanings but with that price payed.

解决方案

In order to recover my points taken, I was obliged to find my own answer, here it is (after one hour of tries)

main program is

    program callrtmod
    use mymod
    implicit none
    real::x
    x=1.0
    write(*,*) x+writerandnum()
    write(*,*) x+writerandnum()
    write(*,*) x+writerandnum()
    end program callrtmod

here's my module

    module mymod
    implicit none
    !-------------mt variables-------------
    ! Default seed
        integer, parameter :: defaultsd = 4357
    ! Period parameters
        integer, parameter :: N = 624, N1 = N + 1

    ! the array for the state vector
        integer, save, dimension(0:N-1) :: mt
        integer, save                   :: mti = N1
    !--------------------------------------

    contains
    function writerandnum
    implicit none
    real(8)::writerandnum

    writerandnum = grnd()
            !if you please, you could perform a Metropolis test here too
    end function writerandnum


    !Initialization subroutine
      subroutine sgrnd(seed)
        implicit none

        integer, intent(in) :: seed

        mt(0) = iand(seed,-1)
        do mti=1,N-1
          mt(mti) = iand(69069 * mt(mti-1),-1)
        enddo
    !
        return
      end subroutine sgrnd
    !---------------------------------------------------------------------------
    !the function grnd was here
    !---------------------------------------------------------------------------


      subroutine mtsavef( fname, forma )

        character(*), intent(in) :: fname
        character, intent(in)    :: forma

        select case (forma)
          case('u','U')
          open(unit=10,file=trim(fname),status='UNKNOWN',form='UNFORMATTED', &
            position='APPEND')
          write(10)mti
          write(10)mt

          case default
          open(unit=10,file=trim(fname),status='UNKNOWN',form='FORMATTED', &
            position='APPEND')
          write(10,*)mti
          write(10,*)mt

        end select
        close(10)

        return
      end subroutine mtsavef

      subroutine mtsaveu( unum, forma )

        integer, intent(in)    :: unum
        character, intent(in)  :: forma

        select case (forma)
          case('u','U')
          write(unum)mti
          write(unum)mt

          case default
          write(unum,*)mti
          write(unum,*)mt

          end select

        return
      end subroutine mtsaveu

      subroutine mtgetf( fname, forma )

        character(*), intent(in) :: fname
        character, intent(in)    :: forma

        select case (forma)
          case('u','U')
          open(unit=10,file=trim(fname),status='OLD',form='UNFORMATTED')
          read(10)mti
          read(10)mt

          case default
          open(unit=10,file=trim(fname),status='OLD',form='FORMATTED')
          read(10,*)mti
          read(10,*)mt

        end select
        close(10)

        return
      end subroutine mtgetf

      subroutine mtgetu( unum, forma )

        integer, intent(in)    :: unum
        character, intent(in)  :: forma

        select case (forma)
          case('u','U')
          read(unum)mti
          read(unum)mt

          case default
          read(unum,*)mti
          read(unum,*)mt

          end select

        return
      end subroutine mtgetu


    !===============================================

    !Random number generator
    !  real(8) function grnd()
      function grnd !agregue yo
        implicit integer(a-z)
        real(8) grnd    !agregue yo
    ! Period parameters
        integer, parameter :: M = 397, MATA  = -1727483681
    !                                    constant vector a
        integer, parameter :: LMASK =  2147483647
    !                                    least significant r bits
        integer, parameter :: UMASK = -LMASK - 1
    !                                    most significant w-r bits
    ! Tempering parameters
        integer, parameter :: TMASKB= -1658038656, TMASKC= -272236544

        dimension mag01(0:1)
        data mag01/0, MATA/
        save mag01
    !                        mag01(x) = x * MATA for x=0,1

        TSHFTU(y)=ishft(y,-11)
        TSHFTS(y)=ishft(y,7)
        TSHFTT(y)=ishft(y,15)
        TSHFTL(y)=ishft(y,-18)

        if(mti.ge.N) then
    !                       generate N words at one time
          if(mti.eq.N+1) then
    !                            if sgrnd() has not been called,
        call sgrnd( defaultsd )
    !                              a default initial seed is used
          endif

          do kk=0,N-M-1
          y=ior(iand(mt(kk),UMASK),iand(mt(kk+1),LMASK))
          mt(kk)=ieor(ieor(mt(kk+M),ishft(y,-1)),mag01(iand(y,1)))
          enddo
          do kk=N-M,N-2
          y=ior(iand(mt(kk),UMASK),iand(mt(kk+1),LMASK))
          mt(kk)=ieor(ieor(mt(kk+(M-N)),ishft(y,-1)),mag01(iand(y,1)))
          enddo
          y=ior(iand(mt(N-1),UMASK),iand(mt(0),LMASK))
          mt(N-1)=ieor(ieor(mt(M-1),ishft(y,-1)),mag01(iand(y,1)))
          mti = 0
        endif

        y=mt(mti)
        mti = mti + 1 
        y=ieor(y,TSHFTU(y))
        y=ieor(y,iand(TSHFTS(y),TMASKB))
        y=ieor(y,iand(TSHFTT(y),TMASKC))
        y=ieor(y,TSHFTL(y))

        if(y .lt. 0) then
          grnd=(dble(y)+2.0d0**32)/(2.0d0**32-1.0d0)
        else
          grnd=dble(y)/(2.0d0**32-1.0d0)
        endif

        return
      end function grnd


    end module mymod

test my solution and vote me up ;) [of course, as you see, I modified mt.f90 code to be included conveniently in my module, so I can keep separately the main program from the randon numbers generation part, so I can do a Metropolis test aside the main program. The main program just wants to know if a trial was accepted or not. My solution does give more clarity to the main progam]

这篇关于在Fortran模块中生成随机数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆