LoginSignup
4
3

More than 3 years have passed since last update.

FortranでAtCoderに挑む際の小技集

Last updated at Posted at 2020-07-11

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 大文字小文字の判定が必要な問題です。

数値と文字列の変換

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

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

! 文字列 ==>> 数値
read(文字列変数, 編集記述子) 数値変数

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

文字列の結合

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

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

参考)
nag Fortran 入門: 文字列操作

文字列の繰り返し(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 の最大値 rangehugeの挙動がまとめられています。感謝。
GNU Fortran compiler: range
GNU Fortran compiler: huge

更新履歴

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

4
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3