fortran66のブログ

fortran について書きます。

【メモ帳】loop を抜けた後の loop 変数の値

不定の輩

DO LOOP を抜けた時の loop 変数の値は FORTRAN 66 では不定でしたが、FORTRAN 77 以降では loop を抜けた時点での値になっています。

例えば、以下のようなプログラムの場合、i = 6 で do loop 脱出条件を満たすので、i=6 が出力されます。loop の途中で exit する場合もその時点での i の値を保ちます。

    program loops
        implicit none
        integer :: i
        
        i = 99
        do i = 1, 5
            print *, 'loop'
        end do
        print *, 'i=', i
    end program loops
 loop
 loop
 loop
 loop
 loop
 i=           6

一方 do concurrent や forall の場合は局所スコープとなって値は更新されません。さらに、これらの構造では、局所変数の宣言もできます。(局所変数の宣言は gfortran 13 でもまだ対応していません。)

    program loops
        implicit none
        integer :: i, m(10)
        
        i = 6

        do concurrent(i = 1:10)
            m(i) = i**2
        end do   
        print *, i
        
        forall (i = 1:10)
            m(i) = i**2
        end forall   
        print *, i

        do concurrent(integer :: k = 1:10)
            m(k) = k**2
        end do   
        print *, m(10)
        
        forall (integer:: k = 1:10)
            m(k) = k**2
        end forall   
        print *, m
    
    end program loops
           6
           6
         100
           1           4           9          16          25          36
          49          64          81         100

同様の事は implied do loop でもあって、以前書いたように array constructor / DATA statement 中では局所的スコープを持ち局所的な変数宣言も可能です (f2018)、一方 I/O 文中では 非局所的なスコープを持ち局所的な変数宣言はできません。

fortran66.hatenablog.com

参照: Modern Fortran Explained 赤本 §23.9

FORTRAN IV

興味深いことに、これらは FORTRAN IV での LOOP 脱出時の LOOP 変数の不定性にさかのぼると言えます。IBMFORTRAN IV では、DO LOOP 中で LOOP 変数が使用されるかされないかで、LOOP 脱出時の LOOP 変数の値が変化します。これが FORTRAN 66 で LOOP 脱出時の LOOP 変数の値が不定とされている一因と思われます。

単なる n 回反復の場合、LOOP カウンタ変数がレジスタとかに置き換えられているのかもしれません。一方、DO LOOP 内で LOOP 変数が使用される場合は LOOP カウンタ変数を記述通り更新しているのでしょう。

IBM7094 emulator で試してみた結果

JOB card と 出力結果の一部

$JOB           LOOP VARIABLE
$EXECUTE       IBJOB
$IBJOB         GO,LOGIC,MAP,FIOCS
$IBFTC PRIME   FULIST,REF,NODECK,M90
C
C   LOOP CHECK
C
      I = 99
      DO 10 I=1,5
        WRITE(6,900)
   10 CONTINUE  
C
      WRITE(6,901) I 
C
      DO 20 I=1,5
          WRITE(6,901) I
   20 CONTINUE     
C
      WRITE(6,901) I 
      STOP
C
  900 FORMAT(6H LOOP1)
  901 FORMAT(3H I=,I5)
      END
LOOP1
LOOP1
LOOP1
LOOP1
LOOP1
I=   99
I=    1
I=    2
I=    3
I=    4
I=    5
I=    5
        511 LINES OUTPUT.
           $IBSYS
           $STOP

fortran66.hatenablog.com