本文摘於 Devil(璉璉) Devil.bbs@vlsi1.iie.ncku.edu.tw ---------------------------------------------------------------------------- 語法: DO [label [,]] dovar = start, stop [, inc] [statment] exit [statment] cycle [statment] [label]end do 語法: DO [label [,]] WHILE (logicalexpr) [statment] exit [statment] cycle [statment] [label]end do Fortran 的 Do 迴圈一般分以上兩種回圈, 常用的 Do 迴圈是給定一起始變量 及終了變量, 另一種 Do While 迴圈是邏輯式. 在一般容易出錯的迴圈是上述的 Do 迴圈, 平常 Dovar使用整數變量是不會發 生問題, 但一始用實數或複數時, 很容易會發生問題. 網友不彷試以下兩個小 例子: Do i=1,10 Write(*,*) Real(i)/10 End Do Do r=0.1,1,0.1 Write(*,*) r End Do 輸出 前例的結果是: 後例的結果是: 1.000000E-01 1.000000E-01 2.000000E-01 2.000000E-01 3.000000E-01 3.000000E-01 4.000000E-01 4.000000E-01 5.000000E-01 5.000000E-01 6.000000E-01 6.000000E-01 7.000000E-01 7.000000E-01 8.000000E-01 8.000001E-01 9.000000E-01 9.000001E-01 1.000000 可以發現後例比前例少一個值. 我們先討論一下 Do 迴圈的邏輯再回過頭來看原 因. Do i=1,10 Write(*,*) Real(i)/10 End Do 將上例的迴圈拆開如下: i=1 10 if (i .gt. 10) then goto 20 else write(*,*) Real(i)/10 i=i+1 goto 10 end if 20 continue ----------------------------------- Do r=0.1,1,0.1 Write(*,*) r End Do 再將後例的迴圈拆開如下: r=0.1 10 if (r .gt. 1) then goto 20 else write(*,*) r r=r+0.1 goto 10 end if 20 continue ------------------------------------ 由此我們知道迴圈是否中止決定於判斷敘述是否成立!! 在 r應該等於 0.9的輸出位置上, r=9.000001E-01, 當 r=r+0.1 後, r=1.0000001 , 這時的 r大於 1, 所以迴圈結束, 也不會輸出 1.0000001 的值. 那為何會有誤差產生? 假設 bit(i) 表示實數在記憶體中的位元值, bit=0 or 1 實數的表示法是以下列公式計算的. do i=2, n real=real+1/2**(i-2) end do 數值計算出來後再以浮點控制來決定小數點的移位. 由上述的計算式知道, 要表現 0.3的數值實際上會有小於0.0000001的誤差, 但這 個誤差會保留在變數的位元末端, 不斷的誤差累積造成的 0.000001的誤差, 也影 響了整個迴圈的判斷值. 解決的方法是盡量讓迴圈變數採用整數, 在要用到的部份在作型別轉換的工作, 這 樣才能保持迴圈在計算上的正確性.