Fortran通过子例程的多次调用修改输入参数吗?

3

我有一个子程序,在if-then-goto循环中多次调用。这个子程序有两个输入参数:

1.是一个常数

2.是一个确定大小的数组(即200X1),其元素在子程序被调用之前会在do循环中发生变化。

问题在于,子程序无法理解这种变化,并且每次调用它时都返回相同的结果(即第一次调用时的结果)。似乎所有在子程序内计算的变量的值都被保存下来,不会随着输入参数2的变化而改变。我的代码有问题吗?我是否不知道Fortran中的错误?我的代码如下:

      PROGRAM calcul.f


      REAL aa(100000),dd(100000),mm(100000),yy(100000),hh(100000),mn(100000),ss(100000),ml(100000),m0(100000)
      INTEGER N,snv
      DOUBLE PRECISION m0(100000),excerpt(1000),k1(100000),sqsum,s2,vk1,mk1,sdk1,v

      filelength=610
      W=200

      OPEN (1,file='filename.dat')
      DO i=1,filelength
      READ (1,*) aa(i),dd(i),mm(i),yy(i),hh(i),mn(i),ss(i),ml(i),m0(i)
      END D0
      CLOSE (1)

   10 FORMAT(g12.6)
   11 FORMAT(I5,1x,g12.6)
       c1=1
       c2=W
       snv=0

   14   IF ((c2.LT.filelength).AND.(c1.LT.(filelength-(W-1)))) THEN

        DO i=c1,c2
        excerpt(i)=m0(i)
        END DO

        CALL calk1(W,excerpt)

        OPEN (3,file='meank1.dat')
        READ (3,*) N,mk1
        OPEN (2,file='resultsk1.dat')
        DO i=1,N
        READ (2,*) k1(i)
        END DO

        sqsum=0.0d0
        DO i=1,N
        sqsum=dble(sqsum+((k1(i)-mk1)**2))
        s2=sqsum
        END DO
        vk1=(s2)/N
        sdk1=dsqrt(vk1) 

        OPEN (4,file='resultsv.dat')
        v=dble(sdk1/mk1)
        snv=snv+1
        WRITE (4,11) snv,v
        CLOSE (2)
        CLOSE (3)       
        mk1=0.0d0
        vk1=0.0d0
        sdk1=0.0d0
        v=0.0d0
        c1=c1+1
        c2=c2+1
        GOTO 14
        END IF
        CLOSE (4)
        END 

我的子程序是:

      SUBROUTINE calk1(winlength,sm)

      DOUBLE PRECISION sm(100000),sumk1,sum,s,x,x2,k1,sk1,mk1
      INTEGER snk1  

      OPEN (2,file='resultsk1.dat')
 10   FORMAT (g12.6)
      start=1
      w=winlength
      c3=6
      snk1=0
      sumk1=0.0d0
      sk1=0.0d0

  13  IF (c3.LE.w) THEN
      l1=1
      l2=c3  
      c=c3
  12  IF ((l1.LE.(w-5)).AND.(l2.LE.w)) THEN 
      sum=0.0d0
      s=0.0d0

      DO k=l1,l2
      sum=sum+sm(k)
      s=sum
      END DO

      av=0.0d0
      av2=0.0d0
      x=0.0d0
      x2=0.0d0
      DO k=l1,l2
      av=av+dble(((k)/(c))*(sm(k)/s))
      av2=av2+dble((((k)/(c))**2)*(sm(k)/s))
      x=av
      x2=av2
      END DO

      k1=x2-((x)**2)
      sumk1=sumk1+k1
      snk1=snk1+1
      WRITE (2,10) k1
      l1=l1+1
      l2=l2+1
      k1=0.0d0
      GOTO 12
      ELSE 
      c3=c3+1
      GOTO 13
      END IF
      END IF
      CLOSE (2)

      N=snk1
      sk1=sumk1
      mk1=dble((sk1)/N)  
      OPEN (3,file='meank1.dat')
      WRITE (3,10) N,mk1
      CLOSE (3)
      RETURN
      END

1
你不能修复一下缩进吗?这段代码几乎无法阅读,也无法编译。 - Vladimir F Героям слава
1
@user3784273 你应该进行编辑,而不是创建一个新的问题。请阅读帮助部分并了解这个网站的工作方式。投票关闭。 - Vladimir F Героям слава
@francescalus 这是相同的代码。我所做的只是将4个0替换为4个0.0d0。我现在正在使用以上的代码。 - user3784273
这里有 call calk1(W,excerpt(i)) 和另一个 call calk1(W,excerpt)。这是非常大的差异,也可能是你问题的根源。 - francescalus
@francescalus。是的,我很抱歉。我的错误。我已经尝试调试了几个小时,并发布了其中一个版本。我已经修复了它。正确的版本是call calk1(W,excerpt)。 - user3784273
请帮我们一个忙,删除其中一个问题并确保另一个问题可读且可编译。谢谢。 - Vladimir F Героям слава
2个回答

3
我还没有尝试编译代码(我发现还有一些错误会使编译器出错),但我可以提出一个问题。
然而,首先要说的是:如果这是你的代码,如果使用更多现代的Fortran特性,将会让事情变得更加容易。
你说excerpt在子例程进入之前每次都会改变。这是正确的,但并没有实际意义。让我们看看数组正在发生什么。这全部都是循环的。
       c1=1
       c2=W

       DO i=c1,c2
         excerpt(i)=m0(i)
       END DO

       CALL calk1(W,excerpt)

       c1=c1+1
       c2=c2+1

在迭代过程中,W 不会改变。在第一次迭代中,您使用数组语法设置 excerpt(1:W)=m0(1:W);在第二次迭代中,您设置 excerpt(2:W+1)=m0(2:W+1),以此类推。也就是说:每次调用 calk1 时,excerpt(1:W) 仍然完全等于未更改的 m0(1:W)。对于 excerpt 的唯一更改发生在第 W 个元素之后,在子程序中建议不使用该元素。

至于您应该用那个 excerpt 设置循环做什么,我无法确定:这取决于您想要发生什么。也许

       DO i=c1,c2
         excerpt(i-c1+1) = m0(i)
       END DO

但是使用现代Fortran。

不过要使用现代的Fortran。


非常感谢!你对摘录设置循环的建议部分地解决了我的问题,但是还出现了其他一些问题。 - user3784273
此外,虚拟参数 sm 的长度比实际参数 excerpt 更长,但这可能不是问题(它仍然是错误的)。 - francescalus
修复了!非常感谢!!!您对摘录设置循环的建议解决了问题!我知道,但现在我只能使用Fortan g77。 - user3784273
如果答案解决了问题,您可以接受它。 - Vladimir F Героям слава

1
当我尝试编译这个时,我得到了许多编译器警告和错误。我建议使用我们的编译器中的最大编译时警告选项,并清理掉那些问题。这将用最小的努力消除一些问题。对于gfortran,请尝试-O2 -ffixed-form -ffixed-line-length-none -W -Wall -pedantic -fimplicit-none -Wsurprising -Waliasing -Wimplicit-interface -Wunused-parameter -fcheck=all -pedantic -fbacktrace
缩进您的代码有助于您理解它。为什么在2014年还要使用FORTRAN 77?Fortran 95/2003更容易编程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接