2011-09-08 54 views
1

我有一些執行模擬的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'會在主代碼裏面重新定義。您是否嘗試過打印這些值以檢查其行爲是否符合您的期望? –

回答

4

如果dt是關係非常小地合計兩種方式,它也可能是在一個點DT是如此之小,將它添加到當時大的et沒有任何影響(數值精度損失),因此et不會超過這一點......

+0

剛剛檢查過,做了et = et + dt'e8次,然後'et'是32.0,並且保持32.0。 – steabert

+0

感謝大家的幫助! – astay13

5

我不知道這是不是你的錯誤,因爲你不給整個程序,但在第一個代碼,第一你做的事情是設置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

0

當你給出部分代碼,跳過聲明,而不是顯示錯誤消息,你只是給你的解釋,而很明顯,如果你知道如何正確解釋它們,你不會讓他們擺在首位。

你的第二個循環與第一個循環的區別在於以下幾點值得注意: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