Help us understand the problem. What is going on with this article?

Fortran入門(Fortran版APG4b)

本記事について

競技プログラミングサイトAtCoderではプログラミング初心者のためにC++入門 AtCoder Programming Guide for beginners (APG4b)というC++のプログラミング教材が提供されています.
更にこれのPython版であるPython入門(Python版 APG4b)もありPython初心者への大きな助けとなっています.
本記事は本家APG4bのFortran版となっており, Fortran初心者でも本記事を読めば実際のコンテストでFortranを使えるようになることを目的としています.

本記事の大部分をAPG4b及びPython版APG4bをもとにしているため, 問題があれば本記事は削除いたします.
各節の見出しは本家へのリンクとなっています.

現在途中までの記述となっていますが第1章までは追記する予定です.

目次

Fortranとは
実行環境
提出練習
第1章
- 1.01.出力とコメント
- 1.02.プログラムの書き方とエラー
- 1.03.四則演算と優先順位
- 1.04.変数と型
- 1.05.実行順序と入力
- 1.06.if文・比較演算子・論理演算子
- 1.07.条件式の結果とlogical型
- 1.08.変数のスコープ
- 1.09.複合代入演算子
- 1.10.do while文
参考文献

Fortranとは

Fortranは主に数値計算で使われている言語です.
CやC++に引けを取らないくらい速く, 簡単に並列化ができることから未だに人気の根強い言語となっています.
競技プログラミングではAtCoderを始め, yukicoderやPOJで使用することができます.
ソート関数や各種データ構造を自分で実装しなくてはならないデメリットもありますがC++よりも記述が簡単でかつPythonよりも実行速度が早いため個人的にはおすすめの言語です.
Fortranについてもっと詳しく知りたい方はこちらをご覧ください.
Fortranとは -日本NAG

Fortranには大きく分けてFORTRANとFortranがあります.
FORTRANはFortran77以前のものを指し, 一行に書ける文字数が決まっているなど古き良きレガシーなものとなっています(Fortranをあまり知らない人がイメージするFortranはこちらのほうが多いように感じます).
一方, FortranはFortran90以降のいわゆるModern Fortranのことを指し, 一行に何文字でも書けたりモジュールを記述できたりします.
ここではFortran90以降のModern Fortranを使って説明していきます.
FORTRANについてはこちらに詳しく書いてありますので興味のある方はこちらも合わせてご覧ください.
知識として必要な過去の Fortran - 日本NAG

実行環境

手元に環境を構築するかAtCoderのコードテストを使用してください.
Linux環境であれば以下のコマンドでFortranの環境構築をすることができます.

sudo apt install gfortran

提出練習

以下に記載するコードをコピーし, A - 1.00.はじめにの下にある提出欄に移動し提出してみましょう.

program main
    implicit none
    print'(A)',"Hello, world!"
end program main

提出する際は言語をFortran(GNU Fortran9.2.1)にしてから提出するようにしてください.
見つからない場合は言語欄にFortranと入力すると出てきます.

第1章

1.01.出力とコメント

プログラムの基本形

以下がFortranのプログラムの基本形となります.

program main
    implicit none
end program main

mainがこのプログラムのプログラム名となります. 必ずmainである必要はなく, 別の文字列にしても構いませんが, プログラム中の変数と大文字小文字の区別なく重複しないようにしてください.
後述しますが例えばプログラム名がMaINであるときに変数名でmainを使用するとコンパイルエラーとなり, プログラムが動かなくなってしまうため注意してください.
なお, FortranはPythonのようにインデントに注意しなくても大丈夫です.

出力

Fortranで出力はprint文を使います.
基本的な書き方は以下のとおりです.

program main
    implicit none
    print*,"Hello, World!"
end program main

FortranはPythonと同じくデフォルトで改行されるようになっています.
print*を使用することで出力する変数型を気にすることなく出力できるのですが, 以下のように先頭に空白が入った状態出力されてしまい, 不正解となってしまいます.

実行結果
 Hello, World!

そのため, 文字列を出力する際には以下のように書くと不正解(WA)にならず安全です.

program main
    implicit none
    print'(A)',"Hello, World!"
end program main
実行結果
Hello, World!

整数を出力する際には以下のように書きます.

program main
    implicit none
    print'(i0)',1
end program main
実行結果
1

小数点以下までの数値を出力する際には以下のように書きます.

program main
    implicit none
    print'(f0.3)',3.141
end program main
実行結果
3.141

f0.3のように.以降で小数点以下何桁まで表示させたいかを指定しています.
もし例えば小数点以下1桁まで表示させたい場合は以下のように書くとできます.

program main
    implicit none
    print'(f0.1)',3.141
end program main
実行結果
3.1

文字列と整数型を同じ行に出力したい場合は以下のように書きます.

program main
    implicit none
    print'(A,i0)',"Hello",1
end program main
実行結果
Hello1

空白区切りで出力したい場合には以下のように書きます.

program main
    implicit none
    print'(A,1x,i0)',"Hello",1
end program main
実行結果
Hello 1

改行無しで出力したい場合には以下のように書きます

program main
    implicit none
    write(*,'(A)',advance='no')"Hello" !改行なし出力
    print'(A)',"World"!改行あり出力
end program main
実行結果
HelloWorld

コメント

コメントアウトする際は!を使用します.
!を使用すると!以降の1行がコメントアウトとなり, コンパイルの際に無視されます.

program main
    implicit none
    !コメントアウト
    print'(A)',"Hello, World" !ここ以降もコメントアウト
end program main

全角文字について

全角文字はC++と同様, プログラム中にあるとエラーとなってしまいますが出力する際に" "で囲ってあれば問題なく出力されます.

問題

ここまで読み進めたら以下のリンク先の問題を解いてみましょう.
EX1 - コードテストと出力の練習
解答例

1.02.プログラムの書き方とエラー

プログラムの書き方

FortranはC++と違い必ず1行に1つの命令文を書き, 改行するようにします.
命令文の途中で改行したいときは以下のように行末に&と記述して改行します.

program main
    implicit none
    integer(8)::a
    a=1+2+ &
    3
    print'(i0)',a
end program main

一方でC++と同様にスペースとインデントで動作が変わることはありません.
また, C++と同様にプログラム中に全角スペースが入っているとコンパイルエラーとなりますので注意してください.

問題

ここまで読み進めたら以下のリンク先の問題を解いてみましょう.
EX2 - エラーの修正

A君の書いたプログラム
program ex2
    implicit none
    print'(A,i0)',"いつも,252
    print'(A)',"AtCoderくん"
end program ex2

標準エラー出力
./Main.f08:3:19:

    3 |     print'(A,i0)',"いつも,252
      |                   1
Error: Unterminated character constant beginning at (1)

解答例

1.03.四則演算と優先順位

四則演算

次のプログラムは上から順に「足し算」「引き算」「掛け算」「割り算」を行っています.

program main
    implicit none
    print'(i0)',1+1 !2
    print'(i0)',3-4 !-1
    print'(i0)',2*3 !6
    print'(i0)',7/3 !2
end program main
実行結果
2
-1
6
2

+, -, *, /を算術演算子といいます.
C++と同様に*が掛け算で/が割り算です.

剰余演算

FortranにはC++やPythonのような剰余演算子はなく, 代わりに組み込み関数であるmod()を使います.
例えば7を3で割った余りを求めたい場合は以下のように書きます.

program main
    implicit none
    print'(i0)',mod(7,3)
end program main
実行結果
1

このようにNMで割ったあまりを出したいときにはmod(N,m)と書くと求めることができます.

演算子の優先順位

Fortranの演算子の優先順位はC++と同様算術演算子と同じです.
そのため1+2*3+4→1+6+4となります.

優先順位 高い 低い
演算子 *
/
mod()
+
-

C++と同様( )を使うことで計算の優先順位を変えることができます.

program main
    implicit none
    print'(i0)',1+2*3 !7
    print'(i0)',(1+2)*3 !9
end program main
実行結果
7
9

割り算の順序

C++と同様小数点以下の切り捨ての関係により割り算の順序によって計算結果が異なってしまうことがあります.
なるべく割り算は計算の後ろの方で行うようにしましょう.
3/2*4→1*4→4
3*4/2→12/2→6

ゼロ除算

以下のようにプログラム中でゼロ除算を行うとコンパイルエラーが出るため注意してください

program main
    implicit none
    print'(i0)',3/0
end program main
標準エラー出力
./Main.f08:3:17:

    3 |     print'(i0)',3/0
      |                 1
Error: Division by zero at (1)

負の数の剰余

C++と同様に負の数の剰余は$A$, $B$の絶対値をそれぞれ$|A|$, $|B|$としたときに以下のようになります.

  • $A$が正のとき: mod($|A|$,$|B|$)
  • $A$が負のとき: -mod($|A|$,$|B|$)

このように$B$の正負に関わらず出力は$A$の正負に一致します.

問題

ここまで読み進めたら以下のリンク先の問題を解いてみましょう.
EX3 - 計算問題
解答例

1.04.変数と型

変数

Fortranの主な変数型は以下のとおりです.

書き込むデータの種類
integer 整数
real 小数(実数)
character(n) 文字列(nに文字列の長さを指定する)

使用例は以下のとおりです.

program main
    implicit none
    integer a
    real b
    character(7) s
    a=10
    b=3.14
    s="AtCoder"

    print'(i0)',a !10
    print'(i0)',a+2 !12
    print'(i0)',a*3 !30
    print'(f0.2)',b !3.14
    print'(A)',s !AtCoder
end program main
実行結果
10
12  
30  
3.14
AtCoder

宣言

変数を使用する際には宣言をする必要があります.
宣言は以下のように「データ型」「変数名」の順で記述します.
Fortran
integer a

代入

宣言した変数にデータ(値)を格納する際には=を使用します.

a=10

読み込み

mainプログラム内のprint文で変数の値を読み込み出力しています.

print'(i0)',a !10
print'(i0)',a+2 !12
print'(i0)',a*3 !30

変数の初期化

変数を宣言すると同時に値を代入することができます.
宣言するだけのときと記述が変わりますので注意してください

program main
    implicit none
    integer::a=10
    print'(i0)',a
end program main
実行結果
10

値は代入されませんが以下のように宣言のみ行うことも可能です.

program main
    implicit none
    integer::a
    a=10
    print'(i0)',a
end program main

変数のコピー

変数1=変数2と書くと変数1変数2の値がコピーされます.

program main
    implicit none
    integer::a=10
    integer b
    b=a !bにaの値である10が代入される
    a=5 !aの値は5に変わるがbの値は10のまま
    print'(i0)',a !5
    print'(i0)',b !10
end program main
実行結果
5
10

変数を同時に宣言

変数の宣言時に,を間に入れることで複数の変数を同時に宣言できます.

program main
    implicit none
    integer::a=10,b=5
    print'(i0)',a
    print'(i0)',b
end program main
実行結果
10
5

1つ以上変数を宣言すると同時に初期化する場合は以下のように必ずinteger::と書いてください

program main
    implicit none
    integer::a=10,b
    b=2*a
    print'(i0)',a
    print'(i0)',b
end program main
実行結果
10
20

いずれの変数も宣言と同時に初期化しない場合は以下のように書くことが可能です.

program main
    implicit none
    integer a,b
    a=10
    b=2*a
    print'(i0)',a
    print'(i0)',b
end program main
実行結果
10
20

特に理由がない場合はinteger::のように書くことをおすすめします.

変数名のルール

利用できない変数名

以下の条件に該当する変数名は使用できません

  • 数字や_で始まる変数名
  • _以外の記号を含む変数名 _は先頭以外に含まれている分には問題ありません.

以下は変数にできない名前の例です.

integer 1abd !数字で始まる名前にできない
integer _abc !_で始まる名前にできない
integer abc+def !_以外の記号を含んではいけない

以下は変数にできる名前の例です

integer abc1 !2文字目以降であれば数字にできる
integer abc_ !2文字目以降であれば_にできる

同じ名前の変数は定義できない

C++と同様同じ名前の変数は定義できません.
ここで注意してほしいのは大文字小文字の区別なく同じ名前の変数は定義できません.
以下は変数を定義できないプログラムの例です

program main
    implicit none
    integer abc
    integer abc !3行目と同じ変数名なので定義できない
    integer AbC !3行目と大文字小文字の区別なく同じ変数名なので定義できない
end program main
標準エラー出力
./Main.f08:3:15:

    3 |     integer abc !2行目と同じ変数名なので定義できない
      |               1
Error: Symbol ‘abc’ at (1) already has basic type of INTEGER
./Main.f08:4:15:

    4 |     integer AbC !2行目と大文字小文字の区別なく同じ変数名なので定義できない
      |               1
Error: Symbol ‘abc’ at (1) already has basic type of INTEGER

プログラム名と同じ名前の変数は定義できない

FortranではC++と違いプログラム名を自由に設定することができます.
その際, プログラム名と同じ名前の変数は大文字小文字の区別なく定義できないことに注意してください.
以下は変数を定義できないプログラムの例です

program A
    implicit none
    integer A !プログラム名と同じ変数名なので定義できない
    integer a !大文字小文字の区別なくプログラム名と同じ変数名なので定義できない
end program A
標準エラー出力
./Main.f08:2:13:

    2 |     integer A !プログラム名と同じ変数名なので定義できない
      |             1
Error: Symbol ‘a’ at (1) cannot have a type
./Main.f08:3:13:

    3 |     integer a !大文字小文字の区別なく同じ変数名なので定義できない
      |             1
Error: Symbol ‘a’ at (1) cannot have a type

integer型以外にも様々な変数型があります.
ここではよく使う3つの型を紹介します.

書き込むデータの種類
integer 整数
real 小数(実数)
character(n) 文字列(nに文字列の長さを指定する)
program main
    implicit none
    integer::i=10
    real::d=0.5
    character(5)::S="Hello"

    print'(i0)',i
    print'(f0.1)',d
    print'(A)',S
end program main
実行結果
10
.5
Hello

異なる型同士の計算

異なる型同士の計算はC++と同様型変換が行われます.
integer型とreal型の計算結果はreal型になります.
そのため, 出力で整数型を指定すると実行時エラーになりますので注意してください.
また, integer型とcharacter型など変換できない型同士の計算はコンパイルエラーになるので注意してください.

実行できるプログラムの例
program main
    implicit none
    integer::i=10
    real::d=0.5
    print'(f0.1)',i+d
end program main
実行結果
10.5
実行時エラーとなるプログラムの例
program main
    implicit none
    integer::i=10
    real::d=0.5
    print'(i0)',i+d
end program main
標準エラー出力
At line 4 of file ./Main.f08 (unit = 6, file = 'stdout')
Fortran runtime error: Expected INTEGER for item 1 in formatted transfer, got REAL
(i0)
 ^

Error termination. Backtrace:
#0  0x7f4615c5074a
#1  0x7f4615c51235
#2  0x7f4615c51c9b
#3  0x7f4615e66aa9
#4  0x7f4615e733b3
#5  0x7f4615e76462
#6  0x7f4615e7682b
#7  0x7f4615e73035
#8  0x5652a61f3876
#9  0x5652a61f370e
#10  0x7f4615861b96
#11  0x5652a61f3749
#12  0xffffffffffffffff
コンパイルエラーになるプログラムの例
program main
    implicit none
    integer::i=10
    character(1)::s="a"
    print'(i0)',i+s
    print'(A)',i+s
end program main
標準エラー出力
./Main.f08:4:16:

    4 |     print'(i0)',i+s
      |                1
Error: Operands of binary numeric operator ‘+’ at (1) are INTEGER(4)/CHARACTER(1)
./Main.f08:5:15:

    5 |     print'(A)',i+s
      |               1
Error: Operands of binary numeric operator ‘+’ at (1) are INTEGER(4)/CHARACTER(1)

異なる型同士の代入

異なる型同士の代入でも型変換は行われます.
ただし以下のプログラムのように宣言と初期化を同時に行うときに前で宣言した変数で初期化を行うことはできないので注意してください.

コンパイルエラーになるプログラムの例
program main
    implicit none
    integer::i=10
    real::d=i !iで初期化しようとするとコンパイルエラーになる
end program main
標準エラー出力
./Main.f08:4:12:

    4 |     real::d=i !iで初期化しようとするとコンパイルエラーになる
      |            1
Error: Parameter ‘i’ at (1) has not been declared or is a variable, which does not reduce to a constant expression

別途変数を代入する場合は以下のように一旦変数を宣言してから代入を行うことでできます.

実行できるプログラムの例
program main
    implicit none
    integer::i=10
    real d
    d=i
end program main

計算と同様に型変換できない変数型の代入はできないので注意してください.

コンパイルエラーになるプログラムの例
program main
    implicit none
    integer::i=10
    real d
    character(5)::S="Hello"

    i=S !integer型とcharacter型は変換できない
    print'(i0)',S
end program main
標準エラー出力
./Main.f08:7:6:

    7 |     i=S !integer型とcharacter型は変換できない
      |      1
Error: Cannot convert CHARACTER(1) to INTEGER(4) at (1)

implicit noneについて(重要!!!)

ここまでのサンプルコードでは何の説明もなしに2行目にimplicit noneといういわばおまじないのようなものを書いていたのでこれについて説明します.
implicit noneとはかつてのFortran(FORTRAN)で使われていた「暗黙の型宣言」を使用しないようにするおまじないです.
「暗黙の型宣言」とは変数名から自動的に変数型を推測する機能のことです.
例えばiから始まる変数名は自動的にinteger型であると判定したりします.
これを使用することはバグの原因となるため使用しないためにも必ず2行目にはimplicit noneを書くようにしてください.
尚, 自分の環境でVSCodeを使ってプログラムを書く場合はFortran拡張を入れれば自動で入れてくれますので特に心配する必要はないと思います.
implicit noneや暗黙の型宣言についてはこちらに詳細な説明がありますので合わせてご覧ください.
implicit none について - 日本NAG
暗黙の型宣言 - 日本NAG

問題

ここまで読み進めたら以下の問題を解いてみましょう.
EX4 - ◯年は何秒?

以下のプログラムをコピー&ペーストして指定した場所にプログラムを追記してください

program main
    !1年の年数
    integer::seconds=365*24*60*60

    print'(i0)',!1年は何秒か
    print'(i0)',!2年は何秒か
    print'(i0)',!5年は何秒か
    print'(i0)',!10年は何秒か
end program main

解答例

1.05.実行順序と入力

プログラムの実行順序

C++やPythonと同様プログラムは上から下へ実行されます.

program main
    implicit none
    integer name

    !nameに10を代入
    name=10

    print'(i0)',name !10

    !nameに5を代入
    name=5

    print'(i0)',name !5
end program main
実行結果
10
5

入力

入力はread文を使います.
以下のプログラムは入力された数値を10倍して出力する例です.

program main
    implicit none
    integer a
    !入力を受け取る
    read*,a

    print'(i0)',a*10
end program main
標準入力
10
実行結果
100

print*,変数名で変数に入力を受け取ることができます.
整数型以外のデータを受け取りたいときにはあらかじめ受け取りたいデータ型で変数を宣言し, その変数で入力を受け取るようにすればよいです.

program main
    implicit none
    character(100) text
    real d

    read*,text
    read*,d
    print'(A,A,f0.3)',text(1:len_trim(text)),", ",d
end program main
標準入力
Hello
1.5
実行結果
Hello, 1.500

ここでプログラム中にtext(1:len_trim(text))という記述がありますが, これは先頭から入力された文字数分だけ出力するという意味になっています.
詳細は後述予定なのでとりあえずおまじないだと思っておいてください.
ちなみに以下のようにtext(1:len_trim(text))textに書き換えてプログラムを実行すると実行結果が以下のように変わってしまいます.

program main
    implicit none
    character(100) text
    real d

    read*,text
    read*,d
    print'(A,A,f0.3)',text,", ",d
end program main
標準入力
Hello
1.5
実行結果
Hello                                                                                               , 1.500

繋げて入力

,で繋げて変数名を書くと複数の変数で入力を受け取ることができます.
C++と同様スペースか改行で区切られていれば分解して入力してくれます.

program main
    implicit none
    integer a,b,c
    read*,a,b,c

    print'(i0)',a*b*c
end program main
標準入力
2 3
4
実行結果
24

問題

ここまで読み進めたら以下の問題を解いてみましょう.
EX5 - A足すB問題
解答例

1.06.if文・比較演算子・論理演算子

if文

if文はある条件が正しいときのみ処理をしたいときに使います.
Fortranでの書き方は以下のとおりです.

if(条件式) then
    処理
end if

条件式が正しいときthenからend ifの間の処理が実行され, 正しくないときには処理が飛ばされます.
以下のプログラムは入力の値が10より小さければ「xは10より小さい」と出力してから「終了」と出力し, 10以上であれば「終了」のみ出力するプログラムです.

program main
    implicit none
    integer x
    read*,x

    if(x<10)then
        print'(A)',"xは10より小さい"
    end if

    print'(A)',"終了"
end program main
入力
5
実行結果
xは10より小さい
終了
入力
11
実行結果
終了

プログラム中の以下のコード

Fortran
if(x<10)then
    print'(A)',"xは10より小さい"
end if

は, xが10より小さいときxは10より小さいと出力する, という意味になっています.

比較演算子

条件式のところには他の言語と同じく比較演算子を使って記述することが多いです.
比較演算子は以下の6つです

演算子 意味
x==y xはyと等しい
x/=y xはyと等しくない
x>y xはyより大きい
x<y xはyより小さい
x>=y xはy以上である
x<=y xはy以下である

ほとんどC++やPythonと同じですが, 等しくないことを表す演算子が!=でなく/=であることに注意してください.
以下のプログラムは入力された整数値がどんな条件を満たしているかを出力するプログラムです.

program main
    implicit none
    integer x
    read*,x

    if(x<10)then
        print'(A)',"xは10より小さい"
    end if

    if(x>=20)then
        print'(A)',"xは20以上"
    end if

    if(x==5)then
        print'(A)',"xは5"
    end if

    if(x/=100)then
        print'(A)',"xは100ではない"
    end if

    print'(A)',"終了"
end program main
入力
5
実行結果
xは10より小さい
xは5
xは100ではない
終了
入力
100
実行結果
xは20以上
終了

論理演算子

Fortranの代表的な論理演算子を紹介します.
|演算子|意味|真になるとき|
|:---:|:---:|:---:|
|.not. 条件式|条件式の結果を反転|条件式が偽|
|条件式1 .and. 条件式2|条件式1が真かつ条件式2が真|条件式1と条件式2の両方が真|
|条件式1 .or. 条件式2|条件式1が真または条件式2が真|条件式1と条件式2の少なくともどちらか一方が真|

他にも論理値が等しいことを意味する.eqv.や論理値が等しくないことを意味する.neqv.がありますが, 筆者自身使った経験がないため説明は省略します.
詳しく知りたい方はこちらをお読みください.
条件分岐(IF文)- 日本NAG

program main
    implicit none
    integer x,y
    read*,x,y

    if(.not.x==y)then
        print'(A)',"xとyは等しくない"
    end if

    if(x==10.and.y==10)then
        print'(A)',"xとyは10"
    end if

    if(x==0.or.y==0)then
        print'(A)',"xかyは0"
    end if

    print'(A)',"終了"
end program main
入力
2 3
実行結果
xとyは等しくない
終了
入力
10 10
実行結果
xとyは10
終了
入力
0 8
実行結果
xとyは等しくない
xかyは0
終了

前の条件が真でないときの処理

else

elseはif文の後ろに書くことでif文の条件式を満たさなかったときに処理を行えるようになります.
書き方は以下のとおりです

Fortran
if(条件式)then
    処理1
else
    処理2
end if

以下のプログラムは入力の値が10より小さいときに「xは10より小さい」と出力し, そうでなければ「xは10より小さくない」と出力するプログラムです.

Fortran
program main
    implicit none
    integer x
    read*,x

    if(x<10)then
        print'(A)',"xは10より小さい"
    else
        print'(A)',"xは10より小さくない"
    end if
end program main
入力
5
実行結果
xは10より小さい
入力
15
実行結果
xは10より小さくない

else if

else ifは前のif文の条件が偽かつelse if中の条件が真であるときに処理を行います.
書き方は以下のとおりです.

if(条件式1)then
    処理1
else if(条件式2)then
    処理2
end if

条件式1が偽かつ条件式2が真のとき処理2が実行されます.
もちろんelse ifのあとにelse ifを書くこともできますしelse ifのあとにelseも書くことができます.

以下のプログラムはその例です.

program main
    implicit none
    integer x
    read*,x

    if(x<10)then
        print'(A)',"xは10より小さい"
    else if(x>20)then
        print'(A)',"xは10より小さくなくて, 20より大きい"
    else if(x==15)then
        print'(A)',"xは10より小さくなくて, 20より大きくなくて, 15である"
    else
        print'(A)',"xは10より小さくて, 20より大きくなくて, 15でもない"
    end if
end program main
入力
5
実行結果
xは10より小さい
入力
30
実行結果
xは10より小さくなくて, 20より大きい
入力
15
実行結果
xは10より小さくなくて, 20より大きくなくて, 15である
入力
13
実行結果
xは10より小さくて, 20より大きくなくて, 15でもない

注意点

==のつもりで=と書かないように, そして!=のつもりで/=と書かないように気をつけましょう.
また, ifelse ifでは条件式のあとにthenをつけ,最後にend ifをつけ忘れないようにしてください.(VSCodeでFortran拡張を入れたら入れてないって教えてくれるので忘れる心配がないです)

細かい話

飛ばしても大丈夫です.

then, end ifの省略

ifのみでelse ifelseがない場合は以下のようにthenend ifを省略できます.

if(x<10)print'(A)',"xは10より小さい"

ただしC++と違って以下のようにはできないことに注意してください.

if(x<10)print'(A)',"xは10より小さい"
else if(x>20)print'(A)',"xは10より小さくなくて, 20より大きい"
else print'(A)',"xは10より小さくて, 20より大きくない"

このようにelse ifelseを付ける場合は必ずthenend ifをつけ忘れないようにしてください.

問題

ここまで読み進めたら以下の問題を解いてみましょう.
EX6 - 電卓をつくろう

標準入力の部分については以下のコードを使用してください.

program ex6
    implicit none
    character(100) line
    integer::A,B,i,cur=1!curは読み取り済みでない場所の先頭
    character(1) op
    !一行まるごと文字列型として読み込む
    read(*,'(A)')line

    !入力された文字列の先頭から終わりまで繰り返し
    do i=1,len_trim(line)
        !i文字目が空白文字のとき
        if(line(i:i)==" ")then
            !1文字目から読み取り済みでないとき
            if(cur==1)then
                !先頭から空白の前の文字までを整数型の変数Aに格納
                read(line(1:i-1),*)A
            else
                !前の空白文字の後ろから2つ目の空白の前までを文字列型の変数opに格納
                op=line(cur:i-1)
            end if
            !読み取り済みでないところにカーソルを移動
            cur=i+1
        end if
    end do
    !読み取り済みでない残りを整数型の変数Bに格納
    read(line(cur:len_trim(line)),*)B
end program ex6

このプログラムは1行をまるごと文字列として読み込み, 空白を検知することでそれぞれの変数A, op, Bに振り分けて格納するようになっています.
read*,A,op,Bとすると例えば5 / 2と入力した際に/が文字列としてopに格納されず, 実行時エラーとなってしまいます.
これは/がFortranでは入力の終わりとして使用されているためだからだそうです.

詳しくはこちらをお読みください.
Fortran の構成要素 - Oracle
read 文と / (スラッシュ) | 計算機の達人への道

解答例

1.07.条件式の結果とlogical型

条件式の結果

Fortranでは真のことを.true.で表現し, 偽のことを.false.で表現します.
次のプログラムは条件式の結果をそのまま出力し, 真のときと偽のときでどのような値を取るか確認しています.

program main
    implicit none
    print*,1<2 !真
    print*,1>2 !偽
end program main
実行結果
 T
 F

条件式の部分に直接.true..false.を書くことができます.
次のプログラムはその例です.

program main
    implicit none
    !.true.は真を表すのでhelloと出力される
    if(.true.)print'(A)',"hello" 

    !.false.と書くと偽を表すので出力されない
    if(.false.)print'(A)',"world"
end program main
実行結果
hello

logical型

logical型というデータ型があります.
この型の変数には.true.または.false.が入ります.

program main
    implicit none
    integer x
    logical::a=.true.,b,c=.false.
    read*,x

    b=x<10

    if(a.and.b)print'(A)',"Hello"
    if(c)print'(A)',"world"
end program main
Hello

このように条件式の結果など, 真偽のデータを変数で扱いたい場合はlogical型を扱います.
C++やPythonのように真を1で, 偽を0で表せないことに注意してください.

問題

ここまで読み進めたら以下の問題を解いてみましょう.
EX7 - bool値パズル

以下のプログラムを書き換えて使用してください.

書き換えるプログラム
program main
    implicit none
    logical::a=!.true.または.false.
    logical::b=!.true.または.false.
    logical::c=!.true.または.false.

    !ここから先は変更しないこと
    if(a)then
        write(*,fmt='(A)',advance='no')"At"
    else
        write(*,fmt='(A)',advance='no')"Yo"
    end if

    if(.not. a .and. b)then
        write(*,fmt='(A)',advance='no')"Bo"
    else if(.not. b .or. c)then
        write(*,fmt='(A)',advance='no')"Co"
    end if

    if(a.and.b.and.c)then
        write(*,fmt='(A)',advance='no')"foo!"
    else if(.true. .and. .false.)then
        write(*,fmt='(A)',advance='no')"yeah!"
    else if(.not. a .or. c)then
        write(*,fmt='(A)',advance='no')"der"
    end if

    print'(A)',""
end program main

解答例

1.08.変数のスコープ

C++ではif文の中で変数を定義することができます.
しかし, Fortranではできません.
例えば, 次のプログラムはコンパイルエラーとなります.

program main
    implicit none
    integer(8)::i=5
    if(i==5)then
        integer(8)::j=10
        print'(i0)',i+j
    end if
end program main
標準エラー出力
./Main.f08:5:24:

    5 |         integer(8)::j=10
      |                        1
Error: Unexpected data declaration statement at (1)
./Main.f08:6:23:

    6 |         print'(i0)',i+j
      |                       1
Error: Symbol ‘j’ at (1) has no IMPLICIT type

必ずプログラムの最初で使用する予定のすべての変数を定義するようにしましょう.

問題

ここまで読み進めたら以下の問題を解いてみましょう.
EX8 - たこ焼きセット

解答例

1.09.複合代入演算子

C++などではx=x+yx+=yのように書けたりx+=1x++のように書けたりすることができます.
これを複合代入演算子といいます.
一方で, Fortranではこのような複合代入演算子を使うことができません.
そのため, 以下のようなプログラムはコンパイルエラーとなります.

program main
    implicit none
    integer::x=2,y
    y=3
    x+=y
    y++
    print'(i0)',x,y
end program main
標準エラー出力
./Main.f08:5:4:

    5 |     x+=y
      |    1
Error: Unclassifiable statement at (1)

必ず複合代入演算子を使わずにx=x+y, x=x+1のように書くようにしてください.
あくまで筆者の勝手な推測でしかないですが, Fortranで複合代入演算子が使えないのはあくまで数値計算用に開発された言語で, 代入の式を数式のように書くことができることに重点をおいたためだと思います.

問題

ここまで読み進めたら以下の問題を解いてみましょう.
問題では複合代入演算子を使おうとなっていますが, Fortranでは使えないため通常通り書くようにしてください.
EX9 - 複合代入演算子を使おう

よかったら以下のサンプルプログラムを使用してください

サンプルプログラム
program main
    implicit none
    integer x,a,b
    read*,x,a,b

    !1の出力
    x=x+1
    print'(i0)',x

    !ここにプログラムを追記
end program main

解答例

1.10.do while文

do while文を使うとプログラムを書く上で非常に重要な機能である繰り返し処理を書くことができます.

無限ループ

次のプログラムはHelloと出力して改行した後, Fortranと出力する処理を無限に繰り返すプログラムです.

program main
    implicit none
    do while(.true.)
        print'(A)',"Hello"
        print'(A)',"Fortran"
    end do
end program main
実行結果
Hello
Fortran
Hello
Fortran
Hello
Fortran
(無限に続く)

do while文は次のように書き, ()内の条件式が真のとき処理を繰り返します.

do while(条件式)
    処理
end do

先程のプログラムでは.true.と書いてあり, 必ず条件式が真になるためずっと処理を繰り返します.
このようにずっと処理を繰り返し続けることを無限ループといいます.

なお, 無限ループは先程のプログラムのように書くのではなく, 次のように書くことが多いです.

無限ループの書き方
do
    処理
end do

次のプログラムは1から順に整数を出力し続けるプログラムです.

program main
    implicit none
    integer::i=1
    do
        print'(i0)',i
        i=i+1
    end do
end program main
実行結果
1
2
3
4
5
6
7
8
(無限に1ずつ増えていく)

ループ回数の指定

先程の1ずつカウントするプログラムを1から10までカウントするプログラムに変えるには次のようにします.

program main
    implicit none
    integer::i=1
    do while(i<=10)
        print'(i0)',i
        i=i+1
    end do
end program main

C++などではN回処理をする場合, 可読性の観点からカウンタ変数は0からN未満までとすることが推奨していますが, Fortranでは1からN以下までとしたほうが見やすいことが多いです.
そのため, 特に理由がない限り以下のプログラムに示すとおりカウンタ変数は1からN以下までとすることをおすすめします.

program main
    implicit none
    integer::i=1
    do while(i<=4)
        print'(A)',"Hello"
        i=i+1
    end do
end program main
実行結果
Hello
Hello
Hello
Hello

このプログラムの変数iのように何度目のループかを管理する変数をカウンタ変数といい, 一般的にi, j, k, lの順に名前をつけます.

応用例

以下はN人の合計点を求めるプログラムです

program main
    implicit none
    integer N,x_sum,x,i
    read*,N

    x_sum=0!合計点を表す変数
    i=1!カウンタ変数

    do while(i<=N)
        read*,x!入力を受け取る変数
        x_sum=x_sum+x
        i=i+1
    end do

    print'(i0)',x_sum
end program main
入力
3
1
10
100
実行結果
111

問題

ここまで読み進めたら以下の問題を解いてみましょう.
EX9 - 棒グラフの出力

Fortranで改行を伴わない出力は以下のように書きます.

program main
    implicit none
    write(*,'(A)',advance='no')"Hello" !改行なし出力
    print'(A)',"World"!改行あり出力
end program main
実行結果
HelloWorld

また, 改行のみを出力する場合は以下のように書きます.

program main
    implicit none
    print'(A)',""!改行のみ出力
end program main

解答例

参考文献

jj1guj
筑波大学工学システム学類4年. Python, C/C++, Fortran使い. AtCoder緑(Highest: 943). 主にFortranで競プロやってます
https://jj1guj.net/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away