Fortran での bool値 の初期値宣言について、おかしなエラーがあったので呟いてみる【解決済】


Fortran での bool値 の初期値宣言にまつわるエラー

  • はじめに

fortran95 で以下のプログラムを作成中におかしなエラーに遭遇したので書いてみる。

  • 課題: 初期値を .true. で宣言したはずの変数flagが、勝手に .false. へとプログラム内で変更される

まずはプログラムの内容から


module mod_qs

public :: main_qs

contains
subroutine main_qs( &
                !inout変数
                  )
  implicit none

  logical :: flag = .true.


  !変数チェック
  write(6,*) '  1 ' , flag

  !メインとなるループ
  do while (flag)
    ....
  end do

end subroutine main_qs

end module

1.まずはテストのために、このサブルーチンだけを呼び起こす(問題なしケース)

  program test

    call  main_qs

  end test
実行結果

  1 T

初期宣言で True としてるので、こうなるはず!

2. 巨大なメインプログラムから呼び出したサブルーチン(親)内で、このサブルーチンを呼び出す(問題ありケース)

    program main

       call test

    end program
    subroutine test

      call  main_qs

    end subroutine test
実行結果
    1 F

初期宣言で True としてるはずなのに、なぜかプログラム内で勝手にfalseに置き換わってる!

  • とりあえずの解決策

 => 初期値をプログラム内で宣言することで正常動作


subroutine main_qs( &
                !inout変数
                  )
  implicit none

  logical :: flag 

  flag = .true.

  !変数チェック
  write(6,*) '  2 ' , flag

  !メインとなるループ
  do while (flag)
    ....
  end do

end subroutine main_qs

実行結果

  2 T

もちろん、bool 宣言ではなく、0,1のinteger や、初期化するモジュールないし場所をプログラムで設ければ問題は解決するはずですが、
よく、私自身logicalをプログラムで使うので、記事にまとめました。

問題解決

cure_honey さんから下記のようなアドバイスをいただきました。ありがとうございます!

結果的に、下記のコメントのとおり、Fortranでは、サブルーチン内の変数宣言で初期化した値は、2回目以降の呼び出しでは反映されず、前回の操作結果の値を保持する(別個に初期値を設定する箇所を設ける必要がある)という仕様?が原因となっていました。

C言語等とは異なり、少し混乱するようなところでした。
まだまだFortranの勉強が足りないようです(笑)

簡単なデモ等を作成し、確認してみました。C言語でも同様のコードを作成し、違いを見てみました。その結果を下記に記載します。

  • 実際に確認してみた!
デモ
  1 program test
  2   implicit none
  3
  4   integer, parameter  :: n = 10
  5   integer             :: i
  6
  7   do i = 1, n
  8     call main_qs(  &
  9                  i & ! IN
 10                 )
 11   end do
 12
 13 end program test
 14
 15 subroutine main_qs(  &
 16                   ii & !  IN
 17                   )
 18   implicit none
 19
 20   integer,  intent(in)  :: ii
 21   logical               :: flag = .true.
 22   integer               :: j
 23
 24   write(6,*) 'Visit This SUB. Number ', ii  , ' FLAG ==  ', flag
 25
 26   do while ( flag )
 27     do j = 1, ii
 28         if ( j == ii  ) then
 29           flag = .false.
 30         end if
 31     end do
 32   end do
 33
 34   return
 35 end subroutine
実行結果
 Visit This SUB. Number            1  FLAG ==   T
 Visit This SUB. Number            2  FLAG ==   F
 Visit This SUB. Number            3  FLAG ==   F
 Visit This SUB. Number            4  FLAG ==   F
 Visit This SUB. Number            5  FLAG ==   F
 Visit This SUB. Number            6  FLAG ==   F
 Visit This SUB. Number            7  FLAG ==   F
 Visit This SUB. Number            8  FLAG ==   F
 Visit This SUB. Number            9  FLAG ==   F
 Visit This SUB. Number           10  FLAG ==   F
  • C言語でも試してみた!
デモ
  1 #include  <stdio.h>
  2 #include  <stdbool.h>
  3
  4 void main(void)
  5 {
  6   int n = 10;
  7   int i;
  8   for(i=0; i<n; i++  ){
  9     main_qs( i );
 10   }
 11 }
 12
 13 int main_qs( int ii  )
 14 {
 15   bool flag = true;
 16   int j = 0;
 17
 18   printf(" Visit This SUB. Number %d",ii ) ;
 19   printf(" FLAG  =  %d \n", flag ) ;-
 20
 21   while ( flag ){
 22     while( j <=  ii  ){
 23       if ( j == ii  ){
 24         flag = false;
 25       }
 26       j++;
 27     }
 28   }
 29 }
実行結果
 Visit This SUB. Number 0 FLAG  =  1
 Visit This SUB. Number 1 FLAG  =  1
 Visit This SUB. Number 2 FLAG  =  1
 Visit This SUB. Number 3 FLAG  =  1
 Visit This SUB. Number 4 FLAG  =  1
 Visit This SUB. Number 5 FLAG  =  1
 Visit This SUB. Number 6 FLAG  =  1
 Visit This SUB. Number 7 FLAG  =  1
 Visit This SUB. Number 8 FLAG  =  1
 Visit This SUB. Number 9 FLAG  =  1

ということで、fortran で初期宣言するときは気を付けていかないといけませんね。