早崎トップ 研究(気候気象) 研究(大気汚染) データリスト Linux Tips Mac Tips

F90 文法・書式・使用方法 (hysk)

文法・書式・使用方法

作成者自身が忘れやすいもののメモ. つまり,Fortran の文法などに関する包括的な記述ではない. 初学者には不向きである.

文字型データに関する組込関数

 文字列処理の組込関数リスト

下の表にまとめる.I は整数型,C は文字型,L は論理型の引数.

組込み関数 処理内容 解説
ADJUSTL(C) 左詰め 先頭の空白を詰める(左詰め)
ADJUSTR(C) 右詰め 後部の空白を詰める(左詰め)
CHAR(I) 整数式を文字に変換 ASCII コードに対応した文字を返す
ICHAR(C) 文字をASCIIコードに変換
INDEX(C1, C2) 検索 文字型データC1内に文字型データC2文字列を探す.存在すれば開始位置,存在しなければ0 を返す
TRIM(C) 文字の後部の空白を詰める 文字列Cの後部の空白を削除
LEN_TRIM(C) 文字数(後部空白を除外)
LEN(C) 文字数 文字列Cの全文字数を整数型で返す
LGE(C1, C2) 大小比較 ≥ C1 >= C2 なら true
LGT(C1, C2) 大小比較 >
LLE(C1, C2) 大小比較 ≤
LLT(C1, C2) 大小比較 <
REPEAT(C, I) 文字列の連結(繰り返し回数指定) REPEAT('hoge', 3) で hogehogehoge を返す
SCAN(C1, C2, L) 文字列C1中の文字列C2の位置(文字数) 第3引数(論理型)の有無により挙動が異なる(詳細は補足情報を参照)

 補足情報

SCAN 関数

  • ケース (i): SCAN ('FORTRAN', 'TR') は値 3 を返す(第2引数の文字列のひとつ前の文字数を返す)
  • ケース (ii): SCAN ('FORTRAN', 'TR', BACK = .TRUE.) は値 5 を返す(第2引数の最後の文字が存在する文字数を返す)
  • ケース (iii): SCAN ('FORTRAN', 'BCD') は値 0 を返す(一致する文字列がないので,ゼロを返す)

具体的な使用例:

  • フルパスで書いたファイル名の,ディレクトリ部分を除くファイル名部分だけを取り出す. Linux, MacOS などのUN*X系 OS での basename コマンドに相当.
 PROGRAM char_trim_test
 IMPLICIT NONE
 INTEGER, PARAMETER :: max_len = 255
 CHARACTER(LEN=max_len) :: input_path, fullpath_name
 CHARACTER(LEN=max_len) :: in_file, out_file
 INTEGER   start_char, end_char
 INTEGER   ilength1, ilength2

 input_path = '/data/hoge/hogehoge/'
 in_file = 'test.txt'
 fullpath_name = TRIM(input_path)//TRIM(in_file)
 ilength1 = LEN(fullpath_name)
 ilength2 = LEN_TRIM(fullpath_name)

 WRITE(*, '(2i5, " : ", a)')   ilength1, ilength2, TRIM(fullpath_name)

 start_char  = SCAN(fullpath_name, '/', .TRUE.)
 end_char   = LEN_TRIM(fullpath_name)
 out_file      = fullpath_name(start_char+1:end_char)

 WRITE(*, '(2x, a,2x, a)')   'Cut-off filename :', TRIM(out_file)

 END PROGRAM char_trim_test

数値に関する組込み関数

自分がよく忘れるもののみ列挙:

整数化に関する組込み関数

組込み関数名 用途
NINT(a) 四捨五入整数化
FLOOR(a) 引数の値以下の最大の整数値を返す (ガウス記号)
CEILING(a) 引数の値以上で最小の整数値を返す

NINT() は,大気汚染データ処理(環境基準の判定,2%除外値の算出)でも使用. See 大気汚染関連情報 - 大気環境基準

  • 使用例
 PROGRAM main
 IMPLICIT NONE
 INTEGER, PARAMETER :: nv = 8
 REAL, DIMENSION(nv) :: a
 REAL :: r1, r2, r3
 INTEGER :: d1, d2, d3
 INTEGER :: iv

 a(1) =  0.34
 a(2) = -0.34
 a(3) = -0.52
 a(4) = -3.23
 a(5) =  3.80
 a(6) =  0.80
 a(7) = -0.80
 a(8) = -9.80

 WRITE(*, '(a4, 6a8)') &
   "No.", "value", "nint", "floor", "ceiling", "aint", "anint"
 do iv = 1, nv
   d1 = nint( a(iv) )      ! 四捨五入した整数値.整数型
   d2 = floor( a(iv) )     ! 引数の値以下の最大の整数値を返す (ガウス記号)
   d3 = ceiling( a(iv) )   ! 引数の値以上で最小の整数値を返す

   r1 = aint( a(iv) )      ! 切捨てによる整数値,ただし型は real で返す
   r2 = anint( a(iv) )     ! 四捨五入した整数値,ただし型は real で返す
   WRITE(*, '(i4, f8.2,  3i8, 2f8.1)') &
     iv, a(iv),   d1, d2, d3,   r1, r2
 enddo   ! iv

 END PROGRAM main

ビット処理

組込み関数名 処理内容
iand( m, n ) 引数のビット単位の論理積を計算する
(使用例: EASE grid snow cover and sea ice サンプル読みだしスクリプト,Fortran code 付き)
ior( m, n ) 引数のビット単位の論理和を計算する
ieor( m, n ) 引数のビット単位の排他的論理和を計算する
ishft( m, k ) 循環桁上げなしで論理シフトする (k>0 のときは左、k<0 のときは右へ)
ishftc( m, k, ic ) 循環シフト: m の、右から ic ビットを左へ k ビット循環シフトする
ibits( m, i, len) ビットの切り出し: i ビット目から始まる len ビット分を m から切り出す
ibset( m, i ) ビットをセットする: ビット i が 1 であれば戻り値は m と同じです
ibclr( m, i ) ビットをクリアーする: ビット i が 0 であれば戻り値は m と同じです
btest( m, i ) ビットのテスト: m の i 番目のビットをテストする。ビットが 1 のときは .true. を返し、ビットが 0 のときは .false. を戻す

繰り返し処理 (do, while)

do ループの順序(多次元配列使用時)

Fortran では,多次元配列のデータは column major order で メモリ上に格納される. すなわち,a(2, 2) という2行2列の2次元配列のデータは, a(1, 1), a(2, 1), a(1, 2), a(2, 2) という並び順となる.

doループを使って多次元配列にアクセスするとき, 並び順にアクセスする方が高速である. つまり, a(ix, iy) (ix = 1, nx ; iy = 1, ny) というデータでは, iy を変数とした do ループを外側に置き,その中で ix についての do ループにする方が効率的である.

do iy = 1, ny
  do ix = 1, nx
    a(ix, iy) = b + c
  enddo  ! ix
enddo  ! iy

上記が正解.配列数が小さい場合は,順序を入れ替えても人間が実感できる程の差はない. 莫大な量の繰り返しがあると,その差を体感できるだろう.

引数の処理

 簡単な例

Fortran 実行ファイルをコマンド化,コマンド引数に入出力ファイル名を指定して実行... という事をやりたい

PROGRAM MAIN
  INTEGER, PARAMETER :: max_len = 255     ! 255-character
  INTEGER :: i, num_args
  CHARACTER(LEN=max_len) :: arg, exec_name
  CHARACTER(LEN=max_len) :: ifile1, ifile2

! +++ Get number of arguments
  num_args = command_argument_count()
  WRITE(*, '(a, i10)') "No. of arguments = ", num_args

! argument 0: executable filename
! argument 1: 1st argument
! argument 2: 2nd argument
  i = 0 
  DO
    CALL get_command_argument(i, arg)     ! Fortran 2003 or later
    IF (LEN_TRIM(arg) == 0) EXIT

      arg_selector: SELECT CASE (i)
        CASE (0)
          exec_name = TRIM(arg)
        CASE (1)
          ifile1 = TRIM(arg)
        CASE (2)
          ifile2 = TRIM(arg)
      END SELECT  arg_selector
      i = i + 1
    END DO

  WRITE(*, '(a)') "exec_name = "//TRIM(exec_name)
  WRITE(*, '(a)') "ifile1 = "//TRIM(ifile1)
  WRITE(*, '(a)') "ifile2 = "//TRIM(ifile2)

END PROGRAM

下記が実行例. こういう使いかたが出来るようになれば, コマンド引数を利用した「自分専用」実行ファイルを Fortran で自作できる. シェルスクリプトから使用するときも,書式が簡単. これはとても便利.

$ gfortran test.f90
$ ./a.out ~/tmp/hoge1.txt ~/tmp/hoge2.txt
No. of arguments =          2
exec_name = ./a.out
ifile1 = /home/viper/hayasaki/tmp/hoge1.txt
ifile2 = /home/viper/hayasaki/tmp/hoge2.txt

上記プログラムは, ifort (ver. 11.1), gfortran (gcc ver. 4.1.2 20080704 (Red Hat 4.1.2-52)) にて 正常動作することを確認. 他の環境でも,大抵動くだろう.

 参考サイト

最初に見つけたのは,玉川さん@岐阜大のページ. さすがだ.

ファイル操作

inquire 文でいろんなファイル操作が出来そう. size, exist, opened, name, number, など (wrote at 2015-10-03)

  • ファイル容量・ファイルサイズの取得(size)
      integer :: file_size
      open(unit=15, file="input_file")
      inquire(unit=15, size=file_size)
    
      write(*, '(a, i12)') "file size = ", file_size
    
  • ファイル名(name),open済みか否か(opened),ユニット番号(number),の照会
      character(len=256) ::  file_name
      inquire(unit=11, name=file_name)
    
      write(*, '(a)') "file name = "//TRIM(file_name)
    
  • ファイルの存在(exist),open済みか否か(opened),ユニット番号(number),の照会
      integer  unit_num
      logical  open_stat, exist_stat
    
      inquire(file="input_file", opened=open_stat, exist=exist_stat, number=unit_num)