本記事について
競技プログラミングサイトAtCoderではプログラミング初心者のためにC++入門 AtCoder Programming Guide for beginners (APG4b)というC++のプログラミング教材が提供されています.
更にこれのPython版であるPython入門(Python版 APG4b)もありPython初心者への大きな助けとなっています.
本記事は本家APG4bのFortran版となっており, Fortran初心者でも本記事を読めば実際のコンテストでFortranを使えるようになることを目的としています.
本記事の大部分をAPG4b及びPython版APG4bをもとにしているため, 問題があれば本記事は削除いたします.
各節の見出しは本家へのリンクとなっています.
現在途中までの記述となっていますが第1章までは追記する予定です.
- 1.01.出力とコメント
- 1.02.プログラムの書き方とエラー
- 1.03.四則演算と優先順位
- 1.04.変数と型
- 1.05.実行順序と入力
- 1.06.if文・比較演算子・論理演算子
- 1.07.条件式の結果とlogical型
- 1.08.変数のスコープ
-
1.09.複合代入演算子
参考文献
Fortranとは
Fortranは主に数値計算で使われている言語です.
CやC++に引けを取らないくらい速く, 簡単に並列化ができることから未だに人気の根強い言語となっています.
競技プログラミングではAtCoderを始め, yukicoderやPOJで使用することができます.
ソート関数や各種データ構造を自分で実装しなくてはならないデメリットもありますがC++よりも記述が簡単でかつPythonよりも実行速度が早いため個人的にはおすすめの言語です.
Fortranについてもっと詳しく知りたい方はこちらをご覧ください.
Fortranとは -日本NAG
Fortranには大きく分けてFORTRANとFortranがあります.
FORTRANはFortran77以前のものを指し, 一行に書ける文字数が72文字までと決まっているなど古き良きレガシーなものとなっています(Fortranをあまり知らない人がイメージするFortranはこちらのほうが多いように感じます).
一方, FortranはFortran90以降のいわゆるModern Fortranのことを指し, 一行に132文字まで書けたりモジュールを記述できたりします.
ここではFortran90以降のModern Fortranを使って説明していきます.
FORTRANについてはこちらに詳しく書いてありますので興味のある方はこちらも合わせてご覧ください.
知識として必要な過去の Fortran - 日本NAG
実行環境
手元に環境を構築するかAtCoderのコードテストを使用してください.
Linux
以下のコマンドでFortranの環境構築をすることができます.
sudo apt install gfortran
Windows
-
MinGWをインストールし, PATHを通す.
MinGW-w64のダウンロードとインストール -
MinGW Installation Managerを開き,MinGW Compiler Suiteをクリックし,
mingw-gcc-fortran-bin
のチェックボックスをクリックする.
-
Installation -> Apply Changes
をクリックし, 出てきたウィンドウのAppplyボタンをクリックする.
提出練習
以下に記載するコードをコピーし, 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
コメント
コメントアウトする際は!
を使用します.
!
を使用すると!
以降の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 - エラーの修正
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
このようにN
をM
で割ったあまりを出したいときには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$の正負に一致します.
modulo関数について
※ここを飛ばして問題に行っても構いません.
Fortranにはmod
の他に, modulo
というもう1つ剰余を取る関数が存在します.
modulo
関数での負の数の剰余は$A$, $B$の絶対値をそれぞれ$|A|$, $|B|$としたときに以下のようになります.
- $A$が正, $B$が正のとき: mod($|A|$,$|B|$)
- $A$が負, $B$が正のとき: $|B|$-mod($|A|$,$|B|$)
- $A$が正, $B$が負のとき: -$|B|$+mod($|A|$,$|B|$)
- $A$が負, $B$が負のとき: -mod($|A|$,$|B|$)
このようにmodulo
関数を使用すると__Pythonと同様の結果になります.__
詳しくはこちらに詳細な解説がありますのでこちらをお読みください.
問題
ここまで読み進めたら以下のリンク先の問題を解いてみましょう.
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
宣言
変数を使用する際には宣言をする必要があります.
宣言は以下のように「データ型」「変数名」の順で記述します.
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
read*,変数名
で変数に入力を受け取ることができます.
整数型以外のデータを受け取りたいときにはあらかじめ受け取りたいデータ型で変数を宣言し, その変数で入力を受け取るようにすればよいです.
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
終了
プログラム中の以下のコード
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文の条件式を満たさなかったときに処理を行えるようになります.
書き方は以下のとおりです
if(条件式)then
処理1
else
処理2
end if
以下のプログラムは入力の値が10より小さいときに「xは10より小さい」と出力し, そうでなければ「xは10より小さくない」と出力するプログラムです.
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でもない
注意点
==
のつもりで=
と書かないように, そして!=
のつもりで/=
と書かないように気をつけましょう.
また, if
とelse if
では条件式のあとにthen
をつけ,最後にend if
をつけ忘れないようにしてください.(VSCodeでFortran拡張を入れたら入れてないって教えてくれるので忘れる心配がないです)
細かい話
飛ばしても大丈夫です.
then
, end if
の省略
if
のみでelse if
やelse
がなく, 処理が1文のみの場合は以下のようにthen
とend 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 if
やelse
を付ける場合は必ずthen
とend 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ではif
文の中を始めとして__あとから変数の定義をすることができない__という制約があります.
そのため, このようなプログラムを書くとエラーになります.
program main
implicit none
integer::x=5
if(x==5)then
integer::y=10 !ここでエラーになる
end if
end program main
test.f90:5:50:
5 | integer::y=10 !ここでエラーになる
| 1
Error: Unexpected data declaration statement at (1)
そのため, 基本的には以下のように変数はすべてプログラムの冒頭で宣言するようにしましょう.
block構文について
※かなり発展的な内容になります. 飛ばして問題を解いていただいて構いません.
Fortran2008からblock
構文というものが誕生し, block
の中であとから変数を定義することができるようになっているそうです.
詳細はこちらをお読みください.
これに際しコメントを頂いていました.本当にありがとうございます.(遅くなってしまい申し訳ありません)
問題
ここまで読み進めたら以下の問題を解いてみましょう.
EX8 - たこ焼きセット
以下のプログラムを書き換えて使用してください.
program main
implicit none
integer p
read*,p
!パターン1
if(p==1)then
integer price
read*,price
end if
!パターン2
if(p==2)then
character(20)text
integer price
read*,text,price
end if
integer N
read*,N
print'(A,A)',text(1:len_trim(text)),"!"
print'(i0)',price*N
end program main
もしプログラムを修正した結果、書き換えるプログラムとの違いが大きくなってしまったとしても、ACができればOKです。
1.09.複合代入演算子
C++やPythonではx=x+1
をx+=1
のように書くことのできる複合代入演算子というものがあります.
一方でFortranにはこのような複合代入演算子が__存在しません__.
そのため, Fortranでこのようなものを使うとエラーが出ます.
program main
implicit none
integer::x=5
x+=1+2 !x=x+1+2のつもり. エラーが出る
x-=2 !x=x-2のつもり. エラーが出る
x*=1+2 !x=x*(1+2)のつもり. エラーが出る
x/=2 !x=x/2のつもり.
!エラーは出ないが/=演算子は右辺と左辺が異なるかを
!判定する比較演算子である.
!そのため, x/2の計算はされない.
x%=2 !x=mod(x,2)のつもり. エラーが出る.
!Fortranで%はそもそも剰余演算子ではない.
x++ !x=x+1のつもり. エラーが出る
++x !x=x+1のつもり. エラーが出る
x-- !x=x-1のつもり. エラーが出る
--x !x=x-1のつもり. エラーが出る
end program main
問題
ここまで読み進めたら以下の問題を解いてみましょう.
__複合代入演算子は使えない__ことに注意してください.
EX9 - 複合代入演算子を使おう
解答例