この文書の URL は http://www.cc.kyoto-su.ac.jp/~mtkg/lecture/comp_B/2012/03.html です。
if 構文
数値の符号や大小関係など、様々な条件の違いに応じて、異なった処理を行いたいことがあります。 そのような場合には if 構文を使います。
if 文にはいくつかの変種がありますが、一番単純なのは次の形の if 文(論理 if 文)です。
if (論理式) 実行文
論理式はある条件が成り立つか判定するための式で、真 (.TRUE.
) または偽 (.FALSE.
)
のどちらかの値を取ります。
論理式が真の場合は実行文が実行され、偽の場合は次の文に処理が移ります。
次のプログラムは、入力された値が正の場合だけ平方根を表示します。
program work0301 implicit none real(8) :: dx write(*,*) 'Input a real:' read(*,*) dx if (dx > 0.0) write(*,*) sqrt(dx) stop end program work0301
キーボードからいろいろな実数を与えて動作を確認してみましょう。
関係演算子
if(...)
の中の論理式 dx > 0.0
によって dx が 0.0 より大きいか判定します。
>
は「関係演算子」の一種です。
関係演算子は算術式の大小関係や等号・不等号の成立を判断するのに用いられ、次の6種類があります。
Fortran 90 FORTRAN77 意味 ----------------------------------------------------------------- e1 < e2 e1 .LT. e2 e1 < e2 ならば真、そうでなければ偽 e1 <= e2 e1 .LE. e2 e1 <= e2 ならば真、そうでなければ偽 e1 == e2 e1 .EQ. e2 e1 = e2 ならば真、そうでなければ偽 e1 /= e2 e1 .NE. e2 e1 /= e2 ならば真、そうでなければ偽 e1 >= e2 e1 .GE. e2 e1 >= e2 ならば真、そうでなければ偽 e1 > e2 e1 .GT. e2 e1 > e2 ならば真、そうでなければ偽
等号は ==
(=
が2つ)であることに注意しましょう。
関係演算子と型
関係演算子で結ばれた2つの算術式の型が異なる場合、より広い方の型に変換されてから比較が行われます。
例えば dx が real(8) 型の変数である場合、
dx > 1
では整数型の定数 1
が real(8) 型の定数 1.0d+0
に変換されてから大小が比較されます。
実数型はあくまでも近似値なので
if (dx == 1.0d+0) ...
といったプログラムは意図したように動かないことがあります。 (計算には誤差が含まれることがあるため dx が厳密に 1.0d+0 になるとは限りません。) 「dx が 1 に十分近い」といった、誤差を考慮した安全な比較方法を使いましょう。
ブロック if 文
入力された整数が偶数か奇数か判定して表示するプログラムを作成してみましょう。 偶奇の判定は 2 で割った余りを調べればよいですね。
program work0302 implicit none integer :: nx write(*,*) 'Input an integer:' read(*,*) nx ! nx を 2 で割った余り mod(nx, 2) を調べて偶奇を判定する if (mod(nx, 2) == 0) then write(*,*) nx, ' is even' ! 偶数 else write(*,*) nx, ' is odd' ! 奇数 end if stop end program work0302
ブロック if 文の構造
条件の成立・不成立に応じて異なる文を実行するにはブロック if 文を利用します。 ブロック if 文は次のような構造をしています。
if (論理式) then block1 (条件が真の場合の処理) else block2 (条件が偽の場合の処理) end if
論理式が真であれば block1
が実行され、偽であれば block2
が実行されます。
次に示すように block1
または block2
を省略することも可能です。
block2
を省略する場合は else
も省略可能です(例3)。
!!! 例1 if (論理式) then else block2 (条件が偽の場合の処理) end if !!! 例2 if (論理式) then block1 (条件が真の場合の処理) else end if !!! 例3 if (論理式) then block1 (条件が真の場合の処理) end if
else if 文
もっと複雑な条件判断の例として閏年 (leap year) の判定を考えてみましょう。 グレゴリオ暦では次の規則に従って閏年が設けられています。
- 西暦年が 4 で割り切れる年は閏年である。
- ただし、西暦年が 4 で割り切れる年のうち、100 で割り切れる年は平年とする。
- ただし、西暦年が 100 で割り切れる年のうち、400 で割り切れる年は閏年とする。
したがって、入力された西暦年が閏年か平年か判定するプログラムは次のようになります。
program work0303 implicit none integer :: year write(*,*) 'Input year:' read(*,*) year if (mod(year, 400) == 0) then ! 400 で割り切れるか write(*,*) 'leap year' else if (mod(year, 100) == 0) then ! 100 で割り切れるか write(*,*) 'common year' else if (mod(year, 4) == 0) then ! 4 で割り切れるか write(*,*) 'leap year' else write(*,*) 'common year' end if stop end program work0303
処理の流れ
このプログラムでは、まず整数型の変数 year が 400 で割り切れるか判定します。
割り切れる場合は leap year と表示し、処理を end if
に移して判定を終了します。
割り切れない場合は else if (mod(year, 100) == 100) then
の行に処理が移され、100 で割り切れるかを判定します。
100 で割り切れるかどうかの判定は 400 で割り切れない場合だけ行われることに注意しましょう。
100 で割り切れる場合は common year と表示し、判定を終了します。 割り切れない場合は 4 で割り切れるか判定します。
4 で割り切れる場合は leap year と表示し、判定を終了します。
割り切れない場合は else
に処理が移され common year と表示して終了します。
条件判断の順序
変数 year が 4 で割り切れるかどうかの判定から始めてしまうと、プログラムがかなり複雑になります(本日の課題)。 条件判断はもっとも厳しいものから行うとすっきり書けることが多いようです。 ただし、効率を重視し、比較の回数をなるべく減らしたいなら、もっとも起こりやすい条件から比較すべきでしょう。
練習問題
キーボードから整数を入力し、符号を判定せよ。 正の場合は positive, 負の場合は negative, 0 の場合は zero と表示すること。
program work0304 implicit none integer :: nx write(*,*) 'Input an integer:' read(*,*) nx if (nx == 0) then write(*,*) 'zero' else if (nx > 0) then write(*,*) 'positive' else write(*,*) 'negative' end if stop end program work0304
複合条件と論理演算子
こんどは月の数を入力してその月の日数を表示するプログラムを考えてみましょう。 ただし、閏年は考慮せず、2月は常に28日とします。
program work0305 implicit none integer :: m write(*,*) 'Input month:' read(*,*) m if (m == 2) then write(*,*) 28 else if (m == 4 .OR. m == 6 .OR. m == 9 .OR. m == 11) then write(*,*) 30 else write(*,*) 31 end if stop end program work0305
論理演算子
最初の else if
の内容
m == 4 .OR. m == 6 .OR. m == 9 .OR. m == 11
は「m が 4 または 6 または 9 または 11」という条件を表します。
演算子 .OR.
は「または」(論理和)を表します。
「または」や「かつ」といった論理演算を行う演算子を「論理演算子」といいます。
論理演算子には次の5種類があります。
e1
, e2
は論理式で dx > 1.0
といった論理式が入ります。
e1 .AND. e2 論理積(かつ) e1, e2 がともに真のときのみ真、他は偽 e1 .OR. e2 論理和(または) e1, e2 がともに偽のときのみ偽、他は真 e1 .EQV. e2 論理等価 e1, e2 がともに真またはともに偽のときのみ真、他は偽 e1 .NEQV. e2 論理非等価 e1 が真で e2 が偽、e1 が偽で e2 が真のときのみ真、他は偽 .NOT. e1 否定 e1 が真なら偽、偽なら真
例えば、「x が正かつ y が負」という条件は論理積演算子 .AND.
を使って次のように表せます。
x > 0 .AND. y < 0
練習問題
キーボードから2つの実数 x, y を読み込み、点 (x, y) が第1象限にあれば OK、 なければ NG と表示するプログラムを作成せよ。
program work0306 implicit none real(8) :: dx, dy write(*,*) 'Input x and y:' read(*,*) dx, dy if (dx > 0 .AND. dy > 0) then write(*,*) 'OK' else write(*,*) 'NG' end if stop end program work0306
case 構文
Fortran 90 から case 構文という新しい条件判断の方法が追加されました。 case 構文は「値が(必ずしも連続でない)ある集合に含まれる」という条件を判定するのに適しています。 case 構文は if と else if を使って書き換えることもできます。 簡潔に記述できる方を選んで、適宜使い分けましょう。
例として、月の数を入力してその月の日数を表示するプログラムを考えてみましょう。 ただし、閏年は考慮せず、2月は常に28日とします。
program work0307 implicit none integer :: m write(*,*) 'Input month:' read(*,*) m select case (m) case (1,3,5,7,8,10,12) write(*,*) 31 case (4,6,9,11) write(*,*) 30 case (2) write(*,*) 28 case default write(*,*) 'Invalid month: ', m end select stop end program work0307
if 文で書くよりすっきりしていると思いますが、いかがでしょうか?
case 構文の構造
case 構文は select case 文で開始され、end select 文で終わります。 書式は次のようになります。
select case (expr) case selector1 block1 case selector2 block2 ... case default blockd end select
expr
には比較を行う変数(整数型、論理型、文字型のスカラー変数)が入ります。
実数型は許されないことに注意しましょう。
select case (expr)
が実行されると expr
の値を含む case セレクタが探され、一致する値がみつかると対応するブロックが実行されます。
セレクタの形式は値の「範囲」をコンマ ,
で区切ったものになります。
「範囲」の指定方法は
個別の値 下限値:上限値 下限値: :上限値
のいずれかです。 以下に例を示します。
case (1) ! m == 1 case (0:50) ! m >= 0 .AND. m <= 50 case (:-1) ! m <= -1 case (10:) ! m >= 10 case (:-1, 2, 5:7) ! m <= -1 .OR. m == 2 .OR. (m >= 5 .AND. m <= 7)
case default
expr
に一致するセレクタがみつからなかった場合は case default に対応するブロックが実行されます。
case default は省略可能で、その場合は何も実行されません。
練習問題
月の数を入力して季節を表示するプログラムを作成せよ。 ただし、月と季節の関係は
- 3, 4, 5月: 春 (spring)
- 6, 7, 8月: 夏 (summer)
- 9, 10, 11月: 秋 (fall)
- 12, 1, 2月: 冬 (winter)
とする。 また、無効な月が入力された場合は invalid と表示すること。
! ! 季節の判定プログラム ! program work0308 implicit none integer :: m write(*,*) 'Input month:' read(*,*) m select case (m) case (3,4,5) write(*,*) 'spring' case (6,7,8) write(*,*) 'summer' case (9,10,11) write(*,*) 'fall' case (12,1,2) write(*,*) 'winter' case default write(*,*) 'invalid' end select stop end program work0308
本日の課題
1. 大きい方の値
2つの整数を入力し、大きい方の値を表示するプログラムを作成せよ。
! ! 2つの数の最大値をみつける ! program work0309 implicit none integer :: i, j write(*,*) 'Input two integers:' read(*,*) i, j if (i > j) then write(*,*) i else write(*,*) j end if stop end program work0309
2. 3つの数の最大値
3つの整数を入力し、最大値 (maximam value) を表示するプログラムを作成せよ。
! ! 3つの数の最大値をみつける ! program work0310 implicit none integer :: i, j, k integer :: m write(*,*) 'Input 3 integers:' read(*,*) i, j, k m = i if (j > m) m = j if (k > m) m = k write(*,*) 'max: ', m stop end program work0310
3. 和暦の計算
キーボードから西暦年を入力し、対応する和暦年を表示するプログラムを作成せよ。 例えば、西暦2000年の場合は Heisei 12 と表示する。 西暦と和暦は次のように対応する。
西暦1868年 明治1年 西暦1912年 大正1年 西暦1926年 昭和1年 西暦1989年 平成1年
元号(明治、大正、昭和、平成)の判定には厳密には月日が必要である。 例えば、1912年は7月29日までが明治45年、7月30日以降が大正1年であるが、ここではプログラムを単純化するため、ある元号の最終年度は次の元号の1年としてよい。 つまり、1912年は大正1年、1926年は昭和1年などとする。 また、1868年以前の西暦年が入力された場合は Not implemented と表示せよ。
! ! 和暦の計算 ! program work0311 implicit none integer :: chera write(*,*) 'Input the Christian Era (1868-2012):' read(*,*) chera select case (chera) case (1868:1911) write(*,*) 'Meiji', chera - 1867 case (1912:1925) write(*,*) 'Taisho', chera - 1911 case (1926:1988) write(*,*) 'Showa', chera - 1925 case (1989:) write(*,*) 'Heisei', chera - 1988 case default write(*,*) 'Not implemented' end select stop end program work0311
チャレンジ問題
1. 平方根の近似計算
正の実数 x の平方根 √(x) はつぎの式から r5 として求められる。
r1 = (1 + x) / 2 r2 = (r1 + x / r1) / 2 r3 = (r2 + x / r2) / 2 r4 = (r3 + x / r3) / 2 r5 = (r4 + x / r4) / 2
実数 x の値をキーボードから読み込み、 r1, r2, r3, r4, r5 の各値を画面に出力するプログラムを作成せよ。
2. 曜日の計算
日曜日を 0、月曜日を 1、…、土曜日を 6 というように番号で表わすものとする。 このとき、今日の曜日を表わす番号 i と日数 n を読み込んで、n 日後の曜日を求め、番号で表示せよ。
3. 三角形の判定
次のような機能をもったプログラムを作成せよ。
- 三角形の各辺の長さ a, b, c の値をキーボードから読み込んで、三角形の面積を求める。
- 三角形ができないときは、そのことを伝えるメッセージを表示して、プログラムの実行を終了する。
ヒント: 「三角形の2辺の和は他の1辺の長さよりも長い」という条件を素直に使うと
a > 0 かつ b > 0 かつ c > 0 かつ a + b > c かつ b + c > a かつ c + a > b
が三角形成立の条件である。
これでは面倒なので、最初の3つの条件は、最小値を返す組込み関数 min(x1, x2, ...)
を利用し、
min(a, b, c) > 0
で済ませることにする。
後半は次のように定義される m
と s
を利用する。
m = (a + b + c) / 2 s = m * (m - a) * (m - b) * (m - c)
s が正であれば面積は √(s) で与えられる。 s が 0 以下であれば三角形ができないことを示す。