FORTRAN77中使用DATA和SAVE语句的意外行为

时间:2018-02-21 17:32:50

标签: fortran julia

我在这篇文章中提到过: " Julia中是否有本地保存的数据(如Fortran' s)?" 我试图将整个fortran77代码重写为Julia。这段代码超过2000行,所以我不能把它放在这里,但我会总结一下我的问题的核心。

在这个旧程序中,广泛使用了NUERICAL RECIPIES的功能。特别是,ran1.f和ran3.f(都是随机生成器函数)。两个函数中的声明行如下:

FUNCTION ran1(idum)
      INTEGER idum,IA,IM,IQ,IR,NTAB,NDIV
      REAL ran1,AM,EPS,RNMX
      PARAMETER (IA=16807,IM=2147483647,AM=1./IM,IQ=127773,IR=2836,
     *NTAB=32,NDIV=1+(IM-1)/NTAB,EPS=1.2e-7,RNMX=1.-EPS)
      INTEGER j,k,iv(NTAB),iy
      SAVE iv,iy
      DATA iv /NTAB*0/, iy /0/

FUNCTION ran3(idum)
    INTEGER idum
    INTEGER MBIG,MSEED,MZ
C   REAL MBIG,MSEED,MZ
    REAL ran3,FAC
    PARAMETER (MBIG=1000000000,MSEED=161803398,MZ=0,FAC=1./MBIG)
C   PARAMETER (MBIG=4000000.,MSEED=1618033.,MZ=0.,FAC=1./MBIG)
    INTEGER i,iff,ii,inext,inextp,k
    INTEGER mj,mk,ma(55) 
C   REAL mj,mk,ma(55) Knuth.
    SAVE iff,inext,inextp,ma
    DATA iff /0/

在上面提到的这篇文章中,我了解了朱莉娅的可变结构,显然""让我模拟SAVE和DATA语句中变量的预期行为。下面,我的可变结构

mutable struct ran1_init     # or simply "type" in older versions
    NTAB :: Int64
    idum :: Int64
    iv :: Array{Int64,1}
    iy :: Int64
    # constructors if necessary
end
# Initialize mutable structure for ran1
ran1_in = ran1_init(32,ISEED,zeros(Int64,32),0)

mutable struct ran3_init     # or simply "type" in older versions
    idum :: Int64
    iff :: Int64
    inext :: Int64
    inextp :: Int64
    ma :: Array{Int64,1}
    # constructors if necessary
end
# Initialize mutable structure for ran3
ran3_in = ran3_init(ISEED,0,0,0,zeros(Int64,55))

fortran CODE使用ran1直到某一点,开始实现ran3(我想这个程序是多年来组装的,并且在某些时候,ran3被实现为生成随机数,而不是ran1)。程序中第一次使用ran3是在这个操作中:

    do while (iii.le.N_emean)
               t0=XA(1,1)+dble(ran3(ISEED))*(XB(1,1)-XA(1,1))
                d=XA(1,2)+dble(ran3(ISEED))*(XB(1,2)-XA(1,2))
               z0=XA(1,3)+dble(ran3(ISEED))*(XB(1,3)-XA(1,3))
                v=XA(1,4)+dble(ran3(ISEED))*(XB(1,4)-XA(1,4))
           iflag=0
stop

(为了表明此事而停止)

朱莉娅:

while (iii <= N_emean)
    for i = 1:4
       randomnumber = ran3(ran3_in)
       XX[i] = XA[1,i] + randomnumber*(XB[1,i]-XA[1,i]);
    end
    t0, d, z0, v = XX;
stop

起初,我认为它工作正常。但后来我在Julia和FORTRAN CODE中看到了以下输出......实验如下:

朱莉娅

println("initial parameters")
        println()
        println("ISEED = ",ran3_in.idum)
        println("iff = ",ran3_in.iff)
        println("inext = ",ran3_in.inext)
        println("inextp = ",ran3_in.inextp)
        while (iii <= N_emean)  

            for i = 1:4
            println()
            println("OUTSIDE: just before entering ran3")
            println("ISEED = ",ran3_in.idum)
            println("iff = ",ran3_in.iff)
            println("inext = ",ran3_in.inext)
            println("inextp = ",ran3_in.inextp)
            println()
            randomnumber = ran3(ran3_in)
            XX[i] = XA[1,i] + randomnumber*(XB[1,i]-XA[1,i]);
            println("OUTSIDE: just exiting ran3")
            println("ISEED = ",ran3_in.idum)
            println("iff = ",ran3_in.iff)
            println("inext = ",ran3_in.inext)
            println("inextp = ",ran3_in.inextp)
            println("random number : ", randomnumber)

                error("JUST PLAYING AROUND")

在Fortran:

write(*,*)"initial parameters"
write(*,*)
write(*,*)"ISEED = ",ISEED
write(*,*)"iff = ",iff
write(*,*)"inext = ",inext
write(*,*)"inextp = ",inextp
    do while (iii.le.N_emean)
        write(*,*)
        write(*,*)"OUTSIDE: just before entering ran3"
        write(*,*)"ISEED = ",ISEED
        write(*,*)"iff = ",iff
        write(*,*)"inext = ",inext
        write(*,*)"inextp = ",inextp
        write(*,*)
        a1ran = dble(ran3(ISEED))
        write(*,*)"OUTSIDE: just exiting ran3"
        write(*,*)"ISEED = ",ISEED
        write(*,*)"iff = ",iff
        write(*,*)"inext = ",inext
        write(*,*)"inextp = ",inextp
        write(*,*)"random number : ",a1ran
    stop

获得: 在Julia代码中

initial parameters

ISEED = 557527639
iff = 0
inext = 0
inextp = 0

OUTSIDE: just before entering ran3
ISEED = 557527639
iff = 0
inext = 0
inextp = 0

INSIDE ran3: just entering ran3
ISEED = 557527639
iff = 0
inext = 0
inextp = 0

INSIDE ran3: just exiting ran3
ISEED = 1
iff = 1
inext = 1
inextp = 32

OUTSIDE: just exiting ran3
ISEED = 1
iff = 1
inext = 1
inextp = 32
random number : 0.253305072

在fortran代码中

initial parameters

 ISEED =    557527639
 iff =            0
 inext =            0
 inextp =            0

 OUTSIDE: just before entering ran3
 ISEED =    557527639
 iff =            0
 inext =            0
 inextp =            0

 INSIDE ran3: just entering ran3
 ISEED =    557527639
 iff =            0
 inext =            0
 inextp =            0

 INSIDE ran3: just exiting ran3
 ISEED =            1
 iff =            1
 inext =            1
 inextp =           32
 OUTSIDE: just exiting ran3
 ISEED =            1
 iff =            0
 inext =            0
 inextp =            0
 random number :   0.25330507755279541     

似乎SAVEed和DATAed BLOCKED变量没有在Fortran中以正确的值退出,而它们在Julia中, 1)发生了什么事? 2)在具有相同命名的DATA和SAVE块的情况下,ran1和ran3之间是否存在问题。 3)不应该是Julia输出预期或更正的输出吗?

我真的需要帮助理解这一点......谢谢

2 个答案:

答案 0 :(得分:2)

Fortran save属性适用于局部变量。因此,它们在功能之外是不可见的。我没有完整的Fortran代码,但对我来说,&#34;外部变量&#34;在Fortran代码中,只是不同的变量,恰好与局部变量具有相同的名称。我建议在Fortran中使用隐式无。

让#34;保存&#34; julia中的变量(或者在C中调用的静态变量),我更喜欢以下方法:

let
      my_saved_variable = 0 # the value corresponds to the Fortran DATA statement 

      global function do_something(inc)
           my_saved_variable += inc
           return my_saved_variable
      end
 end

参数inc被添加到已保存的变量中:

您将获得以下输出:

julia> do_something(2)
2

julia> do_something(5)
7

julia> do_something(10)
17

答案 1 :(得分:2)

这里我解决围绕Fortran代码的误解。我不想尝试详细说明朱莉娅计划的含义 - 我会将其留给其他答案,例如this one

Fortran的重要性是范围。我对此的评论与implicit statement密切相关。

考虑两个程序:

subroutine x
  integer i
end subroutine x

subroutine y
  integer i
end subroutine y

这里有两个范围,每个范围都有一个变量i。这是两个完全不同的变量。它们之间没有任何重叠。

现在,data语句和save语句都没有改变。 save语句,例如

subroutine x
  integer i
  save i
end subroutine

表示该变量具有save属性。这意味着当子例程完成执行时,变量会保留其值(如果没有,变量将变为未定义)。

data语句,例如

subroutine y
  integer i
  data i/4/
end subroutine y

使用特定值显式初始化变量。首次输入子例程y时,变量i的值为4。至关重要的是,data语句还为初始化变量提供了save属性。因此,如果y&#39; s i的值已从4更改,则新值将在下次进入子例程时保留。

在此上下文中,所有内容都包含datasave语句。没有影响范围。