1

プログラムにdo whileループがあり、続行する条件が 1 つずつずれてエラーが発生し続け、その理由がわかりません。次のようになります。

do while (ii .le. nri .and. ed(ii) .le. e1)
    ! do some stuff...
    ii = ii + 1
end do

ここでii、 とnriはスカラー整数、e1はスカラー実数、edは長さの実数配列ですnri。最後の実行後に起こると予想されるのは、2 番目の条件がii.le.nri返されてからテストされず、オフバイワンの問題が発生しないことです。実際に戻る.false.デバッガーで確認しましたがプログラムはクラッシュします。ii.le.nri.false.

1 つの条件のみがテストされるという私の仮定を検証するために、同じコンパイラ オプションでコンパイルした小さなテスト プログラムを作成しました。

 program iftest
     implicit none

     if (returns_false() .and. returns_true()) then
         print *, "in if block"
     end if
 contains
     function returns_true()
         implicit none
         logical returns_true
         print *, "in returns true"
         returns_true = .true.
     end function

     function returns_false()
         implicit none
         logical returns_false
         print *, "in returns false"
         returns_false = .false
     end function
 end program

このプログラムを実行すると、予想どおり、

 $ ./iftest
 in returns false

そして終了します。2 番目のテストは実行されません。

do whileこれが私の条項に適用されないのはなぜですか?

4

2 に答える 2

7

一部の言語とは対照的に、Fortran は複合論理式の特定の評価順序を保証しません。あなたのコードの場合、最後に while ループを回ると、 の値iiが に設定されnri+1ます。コンパイラがテストするコードを生成しed(nri+1)<=e1、それによって の境界外の要素を参照することは正当ですed。これが、プログラムのクラッシュの原因である可能性があります。

あなたの期待は、言語に対する Fortran 標準の規定に反しています。

まだ行っていない場合は、配列境界チェックをオンにしてコードを再コンパイルし、何が起こるかを確認してください。

あなたのテストがこの問題を解決しなかった理由については、あなたのテストが実際に示しているのは、コンパイラがさまざまな種類の条件に対して異なる実行順序を生成し、実際には同じものを比較していないことだけだと思います。

于 2013-04-22T18:07:30.517 に答える
4

答えを拡張する ハイパフォーマンスマーク、これはループを書き直す1つの方法です。

ii_loop: do

  if (ii .gt. nri) exit ii_loop
  if (ed(ii) .gt. e1) exit ii_loop

  ! do some stuff

  ii = ii + 1

end do ii_loop
于 2013-04-22T18:36:06.980 に答える