简体   繁体   English

使用Fortran在循环内计数

[英]Counting inside a loop with Fortran

I have some Fortran code that performs a simulation. 我有一些执行模拟的Fortran代码。 The elapsed time is stored in et , and the timestep is stored in dt . 经过的时间存储在et ,时间步长存储在dt Both are defined as type real. 两者都定义为实数类型。 There is another real variable tot which holds the maximum time the simulation should run. 还有另一个实数变量tot ,它包含模拟应运行的最长时间。 i is a counting variable of type integer. i是整数类型的计数变量。 My first attempt was like this: 我的第一次尝试是这样的:

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 wanted to get rid of i since it was only used in the one place, however, when I tried this, the program hangs when the total time is large: 我想摆脱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

What is the difference between the two code samples that causes the program to respond so differently? 这两个代码示例之间的区别是什么,导致程序响应如此不同? My compiler is g77. 我的编译器是g77。

EDIT: I have added the declarations and initializations to the code samples above. 编辑:我已经将声明和初始化添加到上面的代码示例。

EDIT 2: The initial values passed to the subroutine are dt = 1e-6 and tot = 100. 编辑2:传递给子例程的初始值为dt = 1e-6tot = 100.

I don't know if this is your error since you don't give the whole program, but in the first code, the first thing you do is set et equal to dt , since at that point i=1 . 我不知道这是否是您的错误,因为您没有给出整个程序,但是在第一个代码中,您要做的第一件事就是将et设置为dt ,因为此时i=1 In the second code however, you are using et without having set it (as far as we can guess). 但是,在第二个代码中,您正在使用et而不进行设置(据我们猜测)。 Also, dt seems to be used uninitialized. 另外, dt似乎未初始化使用。 If the bytes at the memory address of et give rise to a large negative float, it may take much longer to reach tot . 如果et的存储地址中的字节引起较大的负浮点数,则到达tot可能需要更长的时间。 That's as far as I can think of anything without have more code. 据我所知,没有更多代码就可以解决任何问题。

EDIT thanks for the update. 编辑感谢您的更新。

Well in that case I think just read the answer of haraldkl, I think that's your solution. 好吧,在这种情况下,我认为只是阅读haraldkl的答案,我认为这就是您的解决方案。 If you need to reach 100 by adding up 1.0e-6 , this isn't going to work for a 4-bytes real, as that only has about 6-7 meaningful digits in base 10. Your first solution is slighly better, since you can reach about 2e9 with a 4-byte int. 如果您需要通过加1.0e-6来达到100 ,那么这对于4字节实数将不起作用,因为基数10中只有6-7个有意义的数字。您的第一个解决方案要好得多,因为您可以使用4字节的int达到2e9左右。 One solution is to use 8-byte variables. 一种解决方案是使用8字节变量。 However, you should always build in an extra check (eg if (et > tot .OR. i > max_iter) ) to allow for a maximum of iterations, so you can safe-guard against this, because even if you use the integer solution, if you would make tot larger, your integer might overflow and you will be stuck in an infinite loop too. 但是,您应该始终进行一次额外的检查(例如if (et > tot .OR. i > max_iter) ),以允许最大程度的迭代,因此即使在使用整数解决方案时也if (et > tot .OR. i > max_iter)这种情况,如果将tot变大,则整数可能会溢出,并且也会陷入无限循环。

如果dt相对于tot非常小,则也可能是因为dt在某一点上是如此之小,以至于将其加到et上就没有影响(数值精度损失),因此et不会增长超出那一点...

It is hard to conclude anything when you give partial code, skip the declarations and instead of showing the error messages you just give your interpretation of them, while it is clear that if you knew how to interpret them correctly you would not be getting them in the first place. 当给出部分代码,跳过声明并且不显示错误消息而只是给出它们的解释时,很难得出任何结论,而很显然,如果您知道如何正确解释它们,就不会得到它们。第一名。

Your second loop differs from the first in several things worth noting: a) what are the values of the variables at the start of the loop, b) what is the loop counter, c) is et real or an integer? 您的第二个循环在几个方面与第一个循环有所不同:a)循环开始时变量的值是什么,b)循环计数器是什么,c)是实数还是整数? ... et cetera ...等等

Here are two ways in which these loops can be written 这是编写这些循环的两种方法

    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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM