FortranでAtCoderに挑む際の小技集

Fortranを使用して[AtCoder](https://atcoder.jp/?lang=ja)の競技プログラミングコンテストに挑む際に便利な構文、関数などをまとめます。随時更新予定です。

#はじめに
AtCoderのコンテストにおいて、使用可能なFortranコンパイラーは**GNU Fortran 9.2.1のみ**です（2020/09/27現在）。これ以外のコンパイラーを使用することは考えません。




#本文

<!--（文字列系）-->
##大文字-小文字判定、変換
　`iachar`関数による文字コードの取得、`achar`関数による文字コードから文字への変換を使用します。
　文字コード(ASCII)を得て、その値のある範囲を調べることで大文字か小文字か判定できます。
　大文字から小文字への変換は文字コードを32増やせばよく、逆なら減らします。対象が大文字か小文字かによって処理内容が変わるので注意が必要です。

```Fortran:サンプル
print*, iachar('A'), iachar('Z'), iachar('a'), iachar('z')
!               65           90           97           122
print*, achar( iachar('A')+32 ), achar( iachar('a')-32)
!              a                        A
```

参考）
[GNU Fortran Compiler: iachar](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gfortran/IACHAR.html#IACHAR)
[GNU Fortran Compiler: achar](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gfortran/ACHAR.html#ACHAR)
[ABC171-A αlphabet](https://atcoder.jp/contests/abc171/tasks/abc171_a) 大文字小文字の判定が必要な問題です。











##数値と文字列の変換
　内部ファイルの入出力を使用することで、文字列と数値の変換が可能です。`integer`、`real`の両方に対応しています。

```Fortran:構文
! 数値 ==>> 文字列
write(文字列変数, 編集記述子) 数値変数 ! * はダメ

! 文字列 ==>> 数値
read(文字列変数, 編集記述子) 数値変数
```
　`write`では、編集記述子の代わりに`*`を使うとエラーを吐きます。整数なら`'I0'`、小数なら`F0.d (dは小数点以下の桁数)`を使うのが便利です。（これらを使用すると出力桁数が変換する数値に依存してしまいますが、そもそも文字列変数の長さは大きめに確保するのが良いでしょう。）
　`read`では編集記述子の代わりに`*`を使用できます。
参考）
[nag Fortran Tips集: 数値と文字列の変換を行う方法](https://www.nag-j.co.jp/fortran/tips/tips_ConvertingBetweenNumbersAndStrings.html)
[nag Fortran 入門: データ入出力](https://www.nag-j.co.jp/fortran/FI_14.html)











##文字列の結合
　文字列の結合には連結演算子`//`を使用できます。

```Fortran:サンプル
print'(3A)', 'ABCD', ',', 'EFG' ! 下の文と同じ結果
print'(A)' , 'ABCD'//','//'EFG' 
```

参考）
[nag Fortran 入門: 文字列操作](https://www.nag-j.co.jp/fortran/FI_13.html)




##文字列の繰り返し(repeat関数)
　repeat関数を用いることで、ある文字列を数回繰り返し、結合させた文字列を得ることができます。

```Fortran:構文
repeat(文字列, 繰り返し数)
```
```Fortran:サンプル
print'(A)', repeat('20', 2)
! 2020
```

[GNU Fortran Compiler: repeat](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gfortran/REPEAT.html#REPEAT)
[ACL Beginner Contest-A Repeat ACL](https://atcoder.jp/contests/abl/tasks/abl_a) repeat関数が効果的な問題です。





<!--（入出力系）-->

<!--
##停滞入出力
書こうかと思ったけど、ほかの工夫で何とかなるから必要ない？
PAST3-Eの入力部分とかで筆者は当時使ったが、今考えれば他の方法でもいけそう。
-->

##編集記述子の`*`
　編集記述子`*`を使用することで、回数を問わない繰り返しを表現できます。

```Fortran:サンプル
print'( *(I0,X,",",X) )', [2, 2, 2, 2, 2]
! 2 , 2 , 2 , 2 , 2 ,
```

参考）
[nag Fortran 2008 Overview: 8 Input/output extensions](
https://www.nag.co.uk/nagware/np/r62_doc/nag_f2008.html#AUTOTOC_8)










<!--（そのた）-->
##`btest`関数
　bit全探索など、ある整数の〇番目のbitが1か0か知りたい場合、`btest`関数を使用できます。bitの位置が0から始まることに注意が必要です。

```Fortran:構文
btest(整数, bitの位置)
! bitが1なら.true.、0なら.false.
```

```Fortran:サンプル
print*,btest(2,1), btest(2,0)
!      T           F
```

参考）
[けんちょんの競プロ精進記録: bit全探索](https://drken1215.hatenablog.com/entry/2019/12/14/171657)
[GNU Fortran Compiler: btest](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gfortran/BTEST.html#BTEST)













##リテラルの精度の指定
　`_`によって、プログラムに直接書き込む数値（リテラル）の精度を指定することができます。指定しない場合は整数、小数ともに4 byteに打ち切られます。

```Fortran:サンプル
print*, 3.1415926535897932384626433832795028841971_16
! 指定なし : 3.14159274
! 4 byte  : 3.14159274
! 8 byte  : 3.1415926535897931
! 16 byte : 3.14159265358979323846264338327950280
```

参考）
[GNU Fortran Compiler: KIND Type Parameter](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gfortran/KIND-Type-Parameters.html#KIND-Type-Parameters)
[ABC168-C :(Colon)](https://atcoder.jp/contests/abc168/tasks/abc168_c?lang=ja) 筆者が精度の指定を忘れたせいで苦しんだ問題です。








##parameterで精度指定
　下記のようにparameter属性をつけた変数は、変数の精度指定用の変数として使えます。コーディング中に精度を変えたくなった時に一括で変えられるので便利です。

```Fortran:サンプル
integer,parameter :: p = 16
integer(p) :: var1 = 12345678901234567890_p
integer(p), allocatable :: var2(:)
```





##型の範囲
　コンテスト中に各型の安全に扱える範囲が気になることがあると思います。
　`range`を使うことで安全に扱える10進数での桁数が求まります。
　`huge`を使うことで扱える最大の整数が求まります。これらの関数は`real`型でも使用できます。

```Fortran:サンプル
print*, range( 2_4 ) , huge( 2_4 )
print*, range( 2_8 ) , huge( 2_8 )
print*, range( 2_16 ), huge( 2_16 )
! 9   2147483647
! 18  9223372036854775807
! 38  170141183460469231731687303715884105727
```

参考）
[Fortran INTERGER*16 の最大値](https://qiita.com/jp_yen/items/ae4a148d0bfdfaedab8e) `range`、`huge`の挙動がまとめられています。感謝。
[GNU Fortran compiler: range](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gfortran/RANGE.html#RANGE)
[GNU Fortran compiler: huge](https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gfortran/HUGE.html#HUGE)












####更新履歴
2020/09/27 repeat関数を追加しました。
2020/03/10 @implicit_noneさんのコメントをうけ，大文字-小文字判定、変換の記述を変更しました。