使用Fortran进行循环内计数

问题描述:

我有一些执行模拟的Fortran代码。所用时间存储在et中,时间步存储在dt中。两者都被定义为真实类型。还有一个实际变量tot,它保存了模拟应该运行的最长时间。 i是整数类型的计数变量。我第一次尝试是这样的:使用Fortran进行循环内计数

real, intent(in) :: dt 
real, intent(in) :: tot 

real :: et 
integer :: i 

et = 0.0 
i = 0 
do 
    i = i+1 
    et = real(i)*dt 
    if (et > tot) exit 

    ! main code here 
end do 

我想摆脱i,因为它是在一个地方只用,但是,当我尝试这样做,程序时的总时间是大挂起:

real, intent(in) :: dt 
real, intent(in) :: tot 

real :: et 

et = 0.0 
do 
    et = et + dt 
    if (et > tot) exit 

    ! main code here 
end do 

导致程序响应如此不同的两个代码示例有什么不同?我的编译器是g77。

编辑:我已经将声明和初始化添加到上面的代码示例。

编辑2:传递给子程序的初始值是dt = 1e-6tot = 100.

+0

程序如何挂起?错误?无限循环(即'等'永远不会达到'tot')? –

+0

@Anders:我假设一个无限循环,因为程序运行10分钟以上而不停止(使用代码的第一个版本,大约1.5分钟后停止)。 – astay13

+0

我猜'et'会在主代码里面重新定义。您是否尝试过打印这些值以检查其行为是否符合您的期望? –

如果dt是关系非常小地合计两种方式,它也可能是在一个点DT是如此之小,将它添加到当时大的et没有任何影响(数值精度损失),因此et不会超过这一点......

+0

刚刚检查过,做了et = et + dt'e8次,然后'et'是32.0,并且保持32.0。 – steabert

+0

感谢大家的帮助! – astay13

我不知道这是不是你的错误,因为你不给整个程序,但在第一个代码,第一你做的事情是设置et等于dt,因为在那一点i=1。然而,在第二个代码中,您正在使用et而没有设置它(据我们所能猜到)。另外,dt似乎被使用未初始化。如果内存地址为et的字节会产生大的负值浮动,则可能需要更长的时间才能达到tot。就我所能想象的而言,没有更多的代码。

编辑感谢您的更新。

那么在这种情况下,我认为刚刚阅读哈拉尔克的答案,我认为这是你的解决方案。如果您需要通过合并1.0e-6来达到100,则这不适用于4字节的真实数据,因为在基数10中只有大约6-7个有意义的数字。您的第一个解决方案略好,因为您可以达到大约2e9与一个4字节的int。一种解决方案是使用8字节变量。然而,你应该总是建立一个额外的检查(例如if (et > tot .OR. i > max_iter))以允许最大的迭代,所以你可以安全地防止这种情况,因为即使你使用整数解决方案,如果你想增大tot,你的整数可能会溢出,你也会陷入无限循环。

+0

查看上面的修改。对不起,我忽略了在我原来的问题中包含初始化。 – astay13

当你给出部分代码,跳过声明,而不是显示错误消息,你只是给你的解释,而很明显,如果你知道如何正确解释它们,你不会让他们摆在首位。

你的第二个循环与第一个循环的区别在于以下几点值得注意:a)循环开始时变量的值是什么,b)循环计数器是什么,c)是实数还是整数? ......等等

以下是这些循环可以写成

program various_do_loops 
    integer :: i 
    real :: et, tot, dt 


    ! DO WHILE LOOP (whoops, I just now see you're using g77 
    ! so this may or may not work) 
    i = 0 
    et = 0. 
    tot = 10. 
    dt = 1. 
    do while (et<tot) 
     i = i+1 
     et = real(i)*dt 
    ! main code goes here 
    ! .... 
    ! .... 
    write(*,'("et is currently ", f5.2)')et 
    end do 

    ! Old kind of WHILE LOOP 
    i = 0 
    et = 0. 
    tot = 10. 
    dt = 1. 
    10 if(et<tot) then 
     i = i + 1 
     et = real(i)*dt 
    ! main code goes here 
    ! .... 
    ! .... 
    write(*,'("et is currently ", f5.2)')et 
    goto 10 
    end if 

    end program various_do_loops 
+0

请参阅上面的编辑初始化/声明。完整的代码足够大,以至于发布都不切实际。请注意,没有错误消息,我只是偶然注意到,使用循环计数的一种策略,程序运行时间显着延长,并且想要了解其原因。 – astay13