Fortranを使用してAtCoderの競技プログラミングコンテストに挑む際に便利な構文、関数などをまとめます。随時更新予定です。
#はじめに
AtCoderのコンテストにおいて、使用可能なFortranコンパイラーはGNU Fortran 9.2.1のみです(2020/09/27現在)。これ以外のコンパイラーを使用することは考えません。
#本文
##大文字-小文字判定、変換
iachar
関数による文字コードの取得、achar
関数による文字コードから文字への変換を使用します。
文字コード(ASCII)を得て、その値のある範囲を調べることで大文字か小文字か判定できます。
大文字から小文字への変換は文字コードを32増やせばよく、逆なら減らします。対象が大文字か小文字かによって処理内容が変わるので注意が必要です。
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
GNU Fortran Compiler: achar
ABC171-A αlphabet 大文字小文字の判定が必要な問題です。
##数値と文字列の変換
内部ファイルの入出力を使用することで、文字列と数値の変換が可能です。integer
、real
の両方に対応しています。
! 数値 ==>> 文字列
write(文字列変数, 編集記述子) 数値変数 ! * はダメ
! 文字列 ==>> 数値
read(文字列変数, 編集記述子) 数値変数
write
では、編集記述子の代わりに*
を使うとエラーを吐きます。整数なら'I0'
、小数ならF0.d (dは小数点以下の桁数)
を使うのが便利です。(これらを使用すると出力桁数が変換する数値に依存してしまいますが、そもそも文字列変数の長さは大きめに確保するのが良いでしょう。)
read
では編集記述子の代わりに*
を使用できます。
参考)
nag Fortran Tips集: 数値と文字列の変換を行う方法
nag Fortran 入門: データ入出力
##文字列の結合
文字列の結合には連結演算子//
を使用できます。
print'(3A)', 'ABCD', ',', 'EFG' ! 下の文と同じ結果
print'(A)' , 'ABCD'//','//'EFG'
##文字列の繰り返し(repeat関数)
repeat関数を用いることで、ある文字列を数回繰り返し、結合させた文字列を得ることができます。
repeat(文字列, 繰り返し数)
print'(A)', repeat('20', 2)
! 2020
GNU Fortran Compiler: repeat
ACL Beginner Contest-A Repeat ACL repeat関数が効果的な問題です。
##編集記述子の*
編集記述子*
を使用することで、回数を問わない繰り返しを表現できます。
print'( *(I0,X,",",X) )', [2, 2, 2, 2, 2]
! 2 , 2 , 2 , 2 , 2 ,
参考)
nag Fortran 2008 Overview: 8 Input/output extensions
##btest
関数
bit全探索など、ある整数の〇番目のbitが1か0か知りたい場合、btest
関数を使用できます。bitの位置が0から始まることに注意が必要です。
btest(整数, bitの位置)
! bitが1なら.true.、0なら.false.
print*,btest(2,1), btest(2,0)
! T F
参考)
けんちょんの競プロ精進記録: bit全探索
GNU Fortran Compiler: btest
##リテラルの精度の指定
_
によって、プログラムに直接書き込む数値(リテラル)の精度を指定することができます。指定しない場合は整数、小数ともに4 byteに打ち切られます。
print*, 3.1415926535897932384626433832795028841971_16
! 指定なし : 3.14159274
! 4 byte : 3.14159274
! 8 byte : 3.1415926535897931
! 16 byte : 3.14159265358979323846264338327950280
参考)
GNU Fortran Compiler: KIND Type Parameter
ABC168-C :(Colon) 筆者が精度の指定を忘れたせいで苦しんだ問題です。
##parameterで精度指定
下記のようにparameter属性をつけた変数は、変数の精度指定用の変数として使えます。コーディング中に精度を変えたくなった時に一括で変えられるので便利です。
integer,parameter :: p = 16
integer(p) :: var1 = 12345678901234567890_p
integer(p), allocatable :: var2(:)
##型の範囲
コンテスト中に各型の安全に扱える範囲が気になることがあると思います。
range
を使うことで安全に扱える10進数での桁数が求まります。
huge
を使うことで扱える最大の整数が求まります。これらの関数はreal
型でも使用できます。
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 の最大値 range
、huge
の挙動がまとめられています。感謝。
GNU Fortran compiler: range
GNU Fortran compiler: huge
####更新履歴
2020/09/27 repeat関数を追加しました。
2020/03/10 @implicit_noneさんのコメントをうけ,大文字-小文字判定、変換の記述を変更しました。