Fortran 2008 の編集記述子まとめ (出力時)

#はじめに
Fortran も 2008 になると編集記述子や機能が追加されたりしている。派手な機能ではないけれど地味に便利だったりする場合もあるのでまとめておこう。ただし出力時限定。
基本的に Fortran 2008 の Draft を見ながら gfortran 5.1, 4.9.2 で動作確認を行ってはいる。行ってはいるが、正確さの保証はできないので使用するときは自分で動作確認をしてほしい。その際、間違いなど見つけたら指摘してくれるとありがたい。

#データ編集記述子
##整数型

|編集記述子|概要|
|:---:|:---|
|I _w_ [ . _m_ ]|wの幅に右詰め最低m字以上で10進整数を出力。wが0なら最小幅で出力|
|B _w_ [ . _m_ ]|2進で出力。あとはIと同じ|
|O _w_ [ . _m_ ]|8進で出力。あとはIと同じ|
|Z _w_ [ . _m_ ]|16進で出力。あとはIと同じ|
|G0|I0を指定したときと同じ|
|G _w_ . d [ . E _e_ ]|I _w_ と同じ。_d_, _e_ の指定は無視される|

```fortran:整数型の表示例
integer :: n
n = 47
write(6, '(I8)') n    ! '      47' 8文字幅右詰め
write(6, '(I8.3)') n  ! '     047' 8文字幅3桁に足りない分は0でパディング
write(6, '(I0)') n    ! '47'       表示に必要な最小幅 (ここでは2文字)
write(6, '(I0.3)' n   ! '047'      3桁に足りない分は0でパディング

n = -47
write(6, '(I8)') n    ! '     -47' 8文字幅右詰め
write(6, '(I8.3)') n  ! '    -047' 最小幅3桁に符号は含まれない
write(6, '(I0)') n    ! '-47'      表示に必要な最小幅 (符号を入れて3文字)
write(6, '(I0.3)') n  ! '-047'     符号込みで4文字
write(6, '(I2)') n    ! '**'       表示幅が足りないと '*' で埋められる

write(6, '(G0)') n    ! '-047'     整数にG0を指定するとI0を指定したときと同じ
!write(6, '(G8)' n    !            エラーになる
write(6, '(G8.3)') n  ! '     -47' I8と同じ '.3' の指定は無視される
```

##実数型・複素数型

|編集記述子|概要|
|:---:|:---|
|F _w_ . _d_|幅_w_に小数点以下_d_位まで値を出力。_w_が0なら最小幅|
|E _w_ . _d_ [ E _e_ ] |幅_w_に小数点以下_d_位で指数表示。実数部は1.0未満に正規化される。指数の幅は_e_字|
|ES _w_ . _d_  [ E _e_ ] |Eと同じだが実数部の正規化を1以上10未満で行う|
|EN _w_ . _d_  [ E _e_ ] |Eと同じだが実数部の正規化を1以上1000未満、指数部が3の倍数になるように行う|
|D _w_ . _d_|E _w_ . _d_ と同じだが指数部の記号を 'D' で表す|
|G0|値の大きさによって幅、表記が変わる|
|G _w_ . _d_ [ E _e_ ]|E _w_ . _d_ [ E _e_ ] と同じだが、_w_ が0でもよい|

```fortran:実数型
real(real32) :: f = 299792.458_real32
real(real64) :: d = 299792.458_real64
write(6, '(F12.2)') d   ! '   299792.46' 小数点以下3位を丸めて2位まで出力
write(6, '(F12.0)') d   ! '     299792.' dが0でも小数点は出力される
write(6, '(F0.2)') d    ! '299792.46'    wが0なら最小幅
write(6, '(F0.0)') d    ! '299792.'      w,dがともに0でもルールは同じ

write(6, '(E12.3)') d   ! '   0.300E+06' 整数部が0になるように正規化
write(6, '(ES12.3)') d  ! '   2.998E+05' 整数部が1～9になるように正規化
write(6, '(EN12.3)') d  ! ' 299.792E+03' 整数部が1～999かつ指数部が3の倍数になるように正規化

write(6, '(E12.3E1)') d ! '    0.300E+6' 指数部の桁を1桁に変更する
write(6, '(D12.3)') d   ! '    0.300D+6' 指数記号を'D'にする

write(6, '(E12.3)') d * 1.D100 ! '   0.300+106' 指数部が3桁になる場合'E'は表示されない

write(6, '(G12.3E1)') d ! '    0.300E+6' 'E12.3E1'を指定したときと同じ
write(6, '(G0.3)') d    ! '.300E+006'    倍精度では指数部が3桁になるが
write(6, '(G0.3)') f    ! '.300E+06'     単精度では指数部が2桁である

! G0 指定の場合は絶対値の対数の大きさによって表示が切り替わる
! 対数が大きくまたは小さくなると指数表記になる
! この例は gfortran 4.9.2, 5.1.0 による
write(6, '(G0)') d       ! '299792.45799999998'
write(6, '(G0)') d*1.E3  ! '2997924578.0000000'
write(6, '(G0)') d*1.E12 ! '.29979245677205005E+018' 指数部の分だけ幅が伸びる
write(6, '(G0)') d*1.E-9 ! '.29979244952129026E-003'

write(6, '(G0)') f       ! '299792.469'     単精度と倍精度では幅が異なる
write(6, '(G0)') f*1.E3  ! '299792480.'   
write(6, '(G0)') f*1.E12 ! '.299792462E+18' 指数部の幅は単精度では2桁
write(6, '(G0)') f*1.E-9 ! '.299792446E-03'
```

```fortran:複素数型
complex(real64) :: z = ( 259.627891_real64, 149.896234_real64 )

! 表示に2つ分の書式指定が必要なことを除けば実数型の場合と同じ
write(6, '(2(f8.2))') z    ! '  259.63  149.90'
write(6, '(2(g0," "))') z  ! '259.62789099999998 149.89623399999999'
```


##論理型

|編集記述子|概要|
|:---:|:---|
|L _w_|_w_幅で右詰めで表示。真で'T'、偽で'F'。_w_は1以上|
|G0|L1と同じ|
|G _w_ . _d_ [ E _e_ ]|L _w_ と同じ。_d_, _e_ は無視される|

```fortran:論理型
logical :: t = .TRUE., f = .FLASE.
write(6, '(L4)') t   ! '   T'
write(6, '(L4)') f   ! '   F'
write(6, '(G0)') t   ! 'T'
```

##文字型

|編集記述子|概要|
|:---:|:---|
|A|変数の幅で表示|
|A _w_ |_w_ 幅で右詰め表示。幅が短ければ切り捨て|
|G0|A と同じ|
|G _w_ . _d_ [ E _e_ ]|A _w_ と同じ。_d_, _e_ は無視される|

```fortran:文字型
character(len=6) :: s = 'ABCDEF'
write(6, '(A)') s   ! 'ABCDEF'   幅を指定しなければ変数の長さで表示
write(6, '(A4)') s  ! 'ABCD'     足りなければ切り捨てられる
write(6, '(A8)') s  ! '  ABCDEF' 幅の方が長ければ右詰めで表示
write(6, '(G0)') s  ! 'ABCDEF'   'G0'は'A'と同じ

s = 'ABC'           ! 変数の長さより短い文字列を代入
write(6, '(A)') s   ! 'ABC   '   表示幅は文字列変数の長さとなる
write(6, '(G0)') s  ! 'ABC   '   'G0'でも同じ
```

##ユーザ定義型 (GFortranではまだ非サポート)

|編集記述子|概要|
|:---:|:---|
|DT \[ _char-literal-constant_ \] ( _v-list_ )|_v-list_ でユーザ定義入出力ルーチンにパラメータを渡せる|

#制御編集記述子
##位置編集記述子

|編集記述子|概要|
|:---:|:---|
|T _n_|先頭より _n_ 字の位置へ移動|
|TL _n_|現在位置から _n_ 文字戻る|
|TR _n_|現在位置から _n_ 文字進む|
|_n_ X|現在位置から _n_ 文字進む。TR _n_ と同じ|

```fortran:制御編集記述子
write(6, '("12345678",T3,"_")')   ! '12_45678'
write(6, '("12345678",TL3,"_")')  ! '12345_78'
write(6, '("12345678",TR3,"_")')  ! '12345678   _'
write(6, '("12345678",3X,"_")')   ! '12345678   _'
```

##桁移動数の指定
桁位置の移動量 _k_ を指定する。F, E, D, G 編集記述子に作用するが、F とそれ以外で動作が異なる。
F では表示する値が 10 の _k_ 乗として表示されるが、E, D, G では仮数部の桁位置が変化し、指数部もそれに合わせて変更されるので表示される値は変化しない。
また、G で表記が小数形式となる場合は表示は変化しない。

|編集記述子|概要|
|:---:|:---|
|_k_ P|_k_ 桁移動する|

```fortran:桁移動数の指定
real :: r = 3.14159
write(6, '(F8.3)') r           ! '   3.142' F編集記述子での通常の表示
write(6, '(2P,F8.3)') r        ! ' 314.159' 100倍に表示される

write(6, '(E12.3)') r          ! '   0.314E+01' E編集記述子での通常の表示
write(6, '(2P,E12.3)') r       ! '   31.42E-01' 仮数部が100倍になるが値は同じ

write(6, '(G12.3)') r          ! '    3.14    ' 編集記述子での通常の表示
write(6, '(2P,G12.3)') r       ! '    3.14    ' G編集記述子で小数表記のときは変化しない
write(6, '(G12.3)') r*1.E6     ! '   0.314E+07' 指数表記の場合
write(6, '(2P,G12.3)') r*1.E6  ! '   31.42E+05' E編集記述子のときと同じ
```

##符号モードの変更
符号モードを変更する。SIGN='SUPPRESS', 'PLUS', 'PROCESSOR_DEFINED' と同等の機能。

|編集記述子|概要|
|:---:|:---|
|SS|正符号を出力しないモードに切り替える|
|SP|正符号を出力するモードに切り替える|
|S|符号モードを処理系のデフォルトに戻す|

```fortran:符号モードの変更
real :: r = 3.14159
write(6, '(F8.3)', SIGN='PLUS') r    ! '  +3.142' SIGN='PLUS'で正符号出力
write(6, '(SS,F8.3)', SIGN='PLUS') r ! '   3.142' 正符号出力抑制に変更
write(6, '(SP,F8.3)') r              ! '  +3.142' 正符号出力に切換え 
write(6, '(S,F8.3)') r               ! '   3.142' デフォルトに戻す
```


##丸めモードの変更
実数と複素数の丸めモードを変更する。ROUND='UP', 'DOWN', 'ZERO', 'NEAREST', 'COMPATIBLE', 'PROCESSOR_DEFINED' と同等の機能。

|編集記述子|概要|
|:---:|:---|
|RU|切り上げ|
|RD|切り捨て|
|RZ|0に近い方へ丸める|
|RN|最近接偶数への丸め|
|RC|近い方へ、ちょうど中央の時は0から遠い方へ丸める|
|RP|処理系のデフォルトへ戻す|

```fortran:丸めモードの変更
integer :: i
real :: r(6) = [ -0.25, -0.15, -0.05, 0.05, 0.15, 0.25 ]
  
write(6, '(4X,6F6.2)') (r(i),i=1,6)
write(6, '(40("-"))')
write(6, '("RU:",RU,6F6.1)') (r(i),i=1,6)
write(6, '("RD:",RD,6F6.1)') (r(i),i=1,6)
write(6, '("RZ:",RZ,6F6.1)') (r(i),i=1,6)
write(6, '("RN:",RN,6F6.1)') (r(i),i=1,6)
write(6, '("RC:",RC,6F6.1)') (r(i),i=1,6)
write(6, '("RP:",RP,6F6.1)') (r(i),i=1,6)

!      -0.25 -0.15 -0.05  0.05  0.15  0.25
! ----------------------------------------
! RU:  -0.2  -0.1  -0.0   0.1   0.2   0.3
! RD:  -0.3  -0.2  -0.1   0.0   0.1   0.2
! RZ:  -0.2  -0.1  -0.0   0.0   0.1   0.2
! RN:  -0.2  -0.2  -0.1   0.1   0.2   0.2
! RC:  -0.3  -0.2  -0.1   0.1   0.2   0.3
! RP:  -0.2  -0.2  -0.1   0.1   0.2   0.2
```

##小数点記号の変更
小数点記号を書式内で変更する。DECIMAL='COMMA', 'POINT' と同等の機能。

|編集記述子|概要|
|:---:|:---|
|DC|小数点記号をカンマ ',' に変更|
|DP|小数点記号をピリオド '.' に変更|

```fortran:小数点記号の変更
real :: r = 3.14159
write(6, '(DC,F6.2)') r   ! '  3,14'
write(6, '(DP,F6.2)') r   ! '  3.14' 通常はこちら
```

##その他の編集記述子

|編集記述子|概要|
|:---:|:---|
|/|改行|
|:|データがなければ処理を打ち切る|

```fortran:コロンの使用例
integer :: i, n(6) = [ 1, 2, 3, 4, 5, 6 ]
write(6, '(*(I0,:,",")') (n(i),i=1,6) ! '1,2,3,4,5,6'  末尾のカンマは出力されない
write(6, '(*(I0,",")') (n(i),i=1,6)   ! '1,2,3,4,5,6,' 末尾にカンマが出力されてしまう
```


#参考資料
+ [Fortran 2008 Draft WD1539-1 J3/10-007 (WG5/N1826)](http://www.j3-fortran.org/doc/year/10/10-007.pdf)