for は「何回回すか」を先に書く繰返しでした。while は違います。条件が真である間ずっと繰り返すので、何回で終わるかは動かしてみるまで分かりません。この違いが分かると、読み方が変わります。
正典が定めていること
出典:擬似言語の記述形式(基本情報技術者試験用)
-
while (条件式) 処理 endwhile
- 前判定繰返し処理を示す。
条件式が真の間,処理を繰返し実行する。
処理は,0 以上の文の集まりである。 -
do 処理 while (条件式)
- 後判定繰返し処理を示す。
処理を実行し,条件式が真の間,処理を繰返し実行する。
処理は,0 以上の文の集まりである。
覚えることは「判定が先か、処理が先か」だけです。名前の前判定・後判定がそのまま順番を表しています。
for との違い ── 回数が決まっているか
| 回す回数 | 典型的な使われ方 | |
|---|---|---|
for |
先に決まっている(制御記述に書いてある) | 配列を先頭から末尾まで見る |
while |
やってみないと分からない | ある状態になるまで繰り返す |
for (i を 1 から 10 まで 1 ずつ増やす) なら、読んだ瞬間に10回だと分かります(G6)。while にはそれがありません。回数を知りたければ、実際に追うしかないのです。
while の中では、条件式に出てくる変数のどれかが必ず変化します。変化しなければ条件は真のままで、繰返しが終わらないからです。
だから while を読むときは、まず条件式に出てくる変数を見つけ、それが中のどこで変わるかを探すのが近道です。そこが「終わりに近づいていく仕組み」です。
前判定と後判定 ── 違いが出るのは1か所だけ
2つの形の差は、条件が最初から偽だったときにしか現れません。
最初から偽のとき
前判定(while)
整数型: n ← 5 while (n > 10) "A" を出力する endwhile
先に条件を見ます。5 > 10 は偽なので、中には一度も入りません。出力はありません(0回)。
後判定(do-while)
整数型: n ← 5 do "A" を出力する while (n > 10)
先に処理をやります。“A” が1回出力されてから条件を見て、偽なので終わります(1回)。
逆にいえば、条件が最初から真ならどちらも同じ動きになります。違いが出るのは最初の1回だけ ── ここだけ押さえておけば十分です。
整数型: n ← 5 のあとに while (n > 10) と書き、中で “A” を出力して endwhile で閉じました。“A” は何回出力されますか。
同じ条件式・同じ処理で、前判定(while)と後判定(do-while)の結果が変わるのはどんなときですか。
実際の出題ではこう出る
「1回だけやるのか、繰り返すのか」を正面から問う出題があります。解答群が if と while の対比になっているのが目印です。
出典:基本情報技術者試験 科目B サンプル問題 問4
次のプログラム中の a 〜 c に入れる正しい答えの組合せを,解答群の中から選べ。
関数gcd は,引数で与えられた二つの正の整数num1 とnum2 の最大公約数を,次の(1)〜(3) の性質を利用して求める。
(1) num1 とnum2 が等しいとき,num1 とnum2 の最大公約数はnum1 である。
(2) num1 がnum2 より大きいとき,num1 とnum2 の最大公約数は,(num1 - num2) とnum2 の最大公約数と等しい。
(3) num2 がnum1 より大きいとき,num1 とnum2 の最大公約数は,(num2 - num1) とnum1 の最大公約数と等しい。
〔プログラム〕
○整数型: gcd(整数型: num1, 整数型: num2) 整数型: x ← num1 整数型: y ← num2 a if ( b ) x ← x - y else y ← y - x endif c return x
解答群
| a | b | c | |
|---|---|---|---|
| ア | if (x ≠ y) |
x < y |
endif |
| イ | if (x ≠ y) |
x > y |
endif |
| ウ | while (x ≠ y) |
x < y |
endwhile |
| エ | while (x ≠ y) |
x > y |
endwhile |
答えだけ先に見る
正解は エ(a が while (x ≠ y)、b が x > y、c が endwhile)。if ではなく while である理由が、この問題のすべてです。
問題文の性質を、そのままプログラムに写す
(1) は終わりの条件です。「等しいとき、最大公約数はその値」= x と y が等しくなったら答えが出ている。だから return x が最後にあります。
(2) と (3) は1歩進める方法です。大きいほうから小さいほうを引くと、答えを変えずに数が小さくなります。
つまり 「等しくなるまで、大きいほうから小さいほうを引き続ける」。「〜まで」「〜し続ける」は繰返しです。1回引いただけでは等しくなりません。
b は「どちらを引くか」の判定です。x ← x - y をするのは x のほうが大きいときなので、条件は x > y になります。
追う前に、ひとつ予想してみましょう
正解を入れた状態で gcd(12, 18) を呼び出すと、while の中は何周しますか。
動かして確かめます。条件を判定した回数と、中を通った回数に注目してください。
トレースシミュレータ gcd(12, 18) を追う
出典:科目B サンプル問題 問4(正解を入れた状態)
ループ開始前
いま計算していること
変数の状態
戻り値
トレース表(進めると1行ずつ積み上がります)
上のプログラムには、次の3行が入れ子になっています。
while (x ≠ y)
if (x > y)
x ← x - y
実行が x ← x - y の行に来たとき、確実に分かっていることはどれですか。
正解は エ(a が while (x ≠ y)、b が x > y、c が endwhile)。
ア・イ(if を選ぶ)は「1回で終わる」誤りです。gcd(12, 18) なら y が 6 になった時点で終わってしまい、return x は 12 を返します。正しい答えは 6 です。問題文の「〜と等しい」は、同じことをもう一度やれという意味でした。
ウ(x < y にする)は「引く向きが逆」です。x が小さいときに x ← x - y をするので x が負になり、x と y は近づくどころか離れていきます。条件 x ≠ y はいつまでも真のままで、繰返しが終わりません。
この2つは while の誤り方の典型です ── 「繰り返さない」か「終わらない」か。
つまずきポイントまとめ
| まちがえ方 | 正しい理解 |
|---|---|
| 前判定でも1回は実行されると思う | 条件が最初から偽なら0回。中に入らない |
| 後判定でも0回がありうると思う | 処理が先なので必ず1回は実行される |
| 判定の回数と周回数を同じだと思う | 前判定は抜けるための判定が1回多い |
| 条件式の変数が中で変わらない | 変わらなければ終わらない。どこで変わるかを探す |
「〜まで繰り返す」を if で書く |
if は1回だけ。繰返しではない |
次に読む
本記事で引用した出典:擬似言語の記述形式(基本情報技術者試験用)/基本情報技術者試験 科目B サンプル問題 問4(独立行政法人情報処理推進機構)。IPAは公表済みの試験問題について、教育目的での使用に許諾および使用料を不要としていますが、著作権は放棄していません。本記事では問題文を改変せずに引用しています。n ← 5 を使った前判定・後判定の例は当サイトのオリジナルです。
