はじめに
この記事を読んでいる皆さんには,プログラミングにおいて自身が得意とするあるいは一番よく用いている第1言語があることでしょう.しかし,いかに第1言語といえども,苦手な機能もあるのではないでしょうか?
私はFortranをプログラミングにおける第1言語としていますが,私がFortranの機能の中で苦手としているのは,書式指定入出力です.
Fortranの書式は,入出力するデータの書式(桁数など)を決めるだけでなく,表示位置の移動や繰り返し,小数点の種類の切り替えや+記号出力の切り替えなど多くの機能があり,覚えきれません.Qiita上にもFortranの書式に関する記事がいくつかあり1234567,単体の機能に着目した記事としては一番多いのではないでしょうか?
書式は文字列として記述される8ため,アポストロフィ'や引用符"が混在するという地味なところから,書式に記述されている指定子と変数の数が対応しない場合があるなど,ジワジワと思考に負荷をかけてきます.
例えば,複素数型の値を表示する際の出力は,書式指定も含めると下記のようになります.
program main
use, intrinsic :: iso_fortran_env, only: real32
implicit none
complex(real32) :: c = cmplx(1.0, 0.0)
print '("(",G0,",",G0,")")', c
! (1.00000000,0.00000000) gfortranの場合
! (1.000000,.000000) intel fortranの場合
end program main
どの括弧や引用符が対応していて,どのカンマが書式指定子の区切りか一見してわかりにくく,毎回手を止めてじっくりと考えることになります.
Fortranの書式と親しくなるために,Fortranの書式について調査し,何回かに分けて投稿することにしました.
- 書式仕様全般(本記事)
- データ編集記述子
- 制御編集記述子
- 文字列編集記述子
調査には,JIS規格書9を主に参照しました.
書式仕様
Fortranでは,print,write, read等の文を用いて入出力する際にデータの書式を制御できます.書式を明示的に指定するための情報を書式仕様(format specifications)とよびます.
明示的に指定せず,コンパイラに任せる場合は*が利用できます.*を用いると,細々とした書式指定が不要になるので積極的に使っていきたいところですが,暗黙的に設定される書式がコンパイラ依存であることは意識しておく必要があります.
program main
use, intrinsic :: iso_fortran_env, only: real32
implicit none
complex(real32) :: c = cmplx(1.0, 0.0)
print *, c
! (1.00000000,0.00000000) gfortranの場合
! (1.000000,0.0000000E+00) intel fortranの場合
end program main
書式仕様は(で始まり)で終わります.今日では,多くの場合文字列として記述するので,(で始まり)で終わる書式仕様を'あるいは"で囲んで文字列とします.著者は,書式仕様を囲むときに'を用いることを推奨しています.
上述の複素数に対する書式指定の例においては,'("(",G0,",",G0,")")'が書式仕様ということです.
書式項目と書式項目並び
データの書式を具体的に指定するための記述子を書式項目(format item)とよびます.複数のデータを一つの文で出力(あるいは入力)することを想定すれば,書式仕様に一つの書式項目しか記述できないのは不便ですから,複数の書式項目を記述することが許されています.この複数の書式項目をまとめて,書式項目並び(format items)とよびます.
書式項目をならべていく場合,書式項目同士の区切りにはカンマ,が用いられます10.
文字列'()'の中に書式項目並びを記述することで,書式仕様が作られます.つまり,書式仕様'("(",G0,",",G0,")")'において,'()'の中にある"(",G0,",",G0,")"が書式項目並び,"(",G0, ",", G0, ")"がそれぞれ書式項目に相当します.
編集記述子
書式項目は,下記の編集記述子(edit descriptor)のいずれかです.
| 書式項目 | 役割 |
|---|---|
| データ編集記述子 (data edit descriptor) |
数値の書式を設定する |
| 制御編集記述子 (control edit descriptor) |
位置制御や,符号・小数点の形式などを制御する |
| 文字列編集記述子 (character string edit descriptor) |
書式仕様の中に文字列を記述する |
"(",G0,",",G0,")"においては,制御編集記述子は存在せず,G0がデータ編集記述子,"(", ",", ")"が文字列編集記述子です.
なお,Fortranの仕様においては,書式項目並びの中にスペースを入れても,表示には影響がありません.(文字列編集記述子は除く)
書式仕様の解釈
さて,ここまで見てきた限りでは非常に明確でした.
上記のように階層構造を書くこともできますし,なんだったらプログラムで表現することもできそうです.
書式反復
一方で,「ここまで見てきた限り」と書いてあるとおり,実際の仕様はもう少し便利で複雑です.
Fortranの書式仕様は,複数回の繰り返しを簡略化できるように定められています.確かに,10個の整数を同じ書式で出力する時に,同じデータ編集記述子を10個も書くのは馬鹿げているので,繰り返しができるようになっていることは非常にありがたいです.
繰り返しは,データ編集記述子あるいは書式項目並びの前に整数のリテラルを付与するか,アスタリスク*を付与します.このとき,アスタリスクを付与されたデータ編集記述子は無制限書式項目,アスタリスクを付与された書式項目並びは無制限書式項目並びとよばれます.
反復回数が指定された(あるいは無制限反復が指定された)書式項目を,反復書式項目とよぶことにしましょう.反復書式項目が規定されていることを反映して仕様をアップデートすると,下記のようになります.
- 書式仕様は,
'(書式項目並び)'もしくは'([書式項目並び, ]無制限書式項目並び)' - 書式項目並びは,
書式項目 [, 書式項目...] - 書式項目は,
[反復]データ編集記述子もしくは制御編集記述子もしくは文字列編集記述子もしくは反復書式項目並び
書式項目並びは書式項目からなるのに,書式項目に反復書式項目並びが現れる,再帰的な構造となっています.
複素数の書式指定を,書式反復数を使って強引に書いてみると,次のようになるでしょうか.
program main
use, intrinsic :: iso_fortran_env, only: real32
implicit none
complex(real32) :: c = cmplx(1.0, 0.0)
print '(*(G0:,","))', c
! 1.00000000,0.00000000 gfortranの場合
! 1.000000,.000000 intel fortranの場合
end program main
*(G0:,",")が無制限書式項目並びです.:は制御編集記述子であり,入出力する内容がなくなった場合に,書式制御を終了させる機能があります.特に,配列データをCSV形式で出力する場合などに役立ちます1112.
コロンを用いると,出力する変数がなくなった時点で書式制御が打ち切られるので,複素数を括弧で囲もうと思うと,閉じる側の括弧が表示されることなく表示が終了します.
program main
use, intrinsic :: iso_fortran_env, only: real32
implicit none
complex(real32) :: c = cmplx(1.0, 0.0)
print '("(",*(G0:,","),")")', c
! (1.00000000,0.00000000 gfortranの場合
! (1.000000,.000000 intel fortranの場合
end program main
セミコロンも含めた表示を途中で打ち切らず,表示されたセミコロンを括弧で上書きするという強引な方法も採ることができます.
program main
use, intrinsic :: iso_fortran_env, only: real32
implicit none
complex(real32) :: c = cmplx(1.0, 0.0)
print '("(", 2(G0, ","), TL1, ")")', c
! (1.00000000,0.00000000) gfortranの場合
! (1.000000,.000000) intel fortranの場合
end program main
2(G0,",")の2が書式反復数,TL1はカーソルを左に一つ移動させる制御編集記述子です.同様にカーソルを右に移動させるTRという制御編集記述子も存在し,これはFortran/FORTRANコードでよく見るXと同じ役割です.
おわりに
Fortranの書式仕様をFortran 2018の仕様から確認しました.出てきた記述子とその使い方を場当たり的に覚えるよりも,思考が整理されたように思います.(「書式項目は反復書式項目並びである」という項目以外)
次の記事からは,データ編集記述子や制御編集記述子の機能と使い方をまとめていきます.