
武蔵野個別指導塾の特徴
高校情報I 条件による反復—変数の更新と終了判定から止まる理由を説明する|武蔵野個別指導塾

一定量ずつ材料を使う処理を表で追い、更新忘れや0回の処理を比べながら、whileが止まる根拠を説明します。
よくあるのは、高校生が残量を使う処理を書いたものの、条件に使う変数の更新を忘れる場面です。最初の残量が条件を満たすと、同じ判定が繰り返され、いつまでも先へ進めません。何回動くかを数える前に、判定に使う値がどう変わり、どの状態で止まるかを決めましょう。
条件を読む問いと設計する問い
条件による反復では、処理を何回行うかが初めから決まっていなくても、続ける条件を指定できます。例えば、残量が1回分以上ある間だけ一定量を使うなら、残量によって回数が変わります。問題では、初期値から各回の値と終了時の値を求める型、止まらない原因を探す型、目的に合う条件と更新を設計する型が考えられます。
答えの形式まで先に決めます。以下のモデルでは残量と消費量を整数で表し、残量は0以上、1回分は正とします。途中で補充せず、1回分に満たない残量は使わずに残します。出力は処理回数と残量の組です。数は説明のために作ったもので、単位をそろえた量として扱います。
例えば残量が1回分より少なければ、本体を1回も実行せずに終了します。残量がちょうど1回分なら、1回使って0になり、次の判定で終わります。この2つを区別すると、条件の等号の有無を決めやすくなります。
判定、更新、次の判定
図1のように、whileは先に条件を判定し、真なら本体を実行して再び判定します。偽なら本体を通らず、反復の後へ進みます。初期値は最初の判定に使われ、更新後の値は次の判定に使われます。条件自体が値を減らすわけではありません。

図1の戻る矢印は、更新を終えた後にもう一度条件を見ることを表します。回数も本体で1増やせば、回数は実際に消費した回数になります。最初から条件が偽なら、回数の初期値0がそのまま答えです。
止まる理由は、条件の中の残量が減るから、というだけでは不十分です。減る量が正であることと、残量が負にならないことも必要です。条件を「残量が1回分以上」とし、1回分を引けば、各回の後の残量は0以上です。正の整数だけ減り続けるので、いつまでも条件を満たすことはできません。反復が終わったとき、残量は0以上かつ1回分未満です。
反復中に保たれる関係も確認します。初期残量は「処理回数に対応する消費量と現在の残量を合わせた量」と等しくなります。開始時は回数0なので成立し、1回消費するたび残量が1回分減り回数が1増えるため、関係が保たれます。終了時にこの関係と残量の範囲を合わせれば、回数と残量が目的に合うと説明できます。実行例は誤りを見つける材料であり、一般の入力に対するこの説明の代わりにはなりません。
基本例題:材料を使い切れる回数
材料が14単位あり、作業1回につき4単位使います。1回分に満たない材料は残します。作業回数と残量を整数の組で求め、残量の変化を追ってください。手で考えると、4単位を3回使って12単位、残りは2単位です。4回目には4単位必要なので実施できません。期待する組は (3, 2) です。

図2のように残量は14、10、6、2と変わります。最後の2は処理後の値であり、もう1回本体を実行する値ではありません。判定は14、10、6で真、2で偽です。本体は3回、条件の判定は最後の偽を含めて4回です。
次の関数はこの規則を実装します。整数以外、負の残量、0以下の消費量は不正として ValueError を送出します。真偽値はPythonでは整数の一種として扱われるため、この仕様では明示的に除外します。
def consume(stock, amount):
if type(stock) is not int or type(amount) is not int:
raise ValueError("integer required")
if stock < 0 or amount <= 0:
raise ValueError("invalid quantity")
count = 0
while stock >= amount:
stock = stock - amount
count = count + 1
return count, stock
print(consume(14, 4))
最初の行は関数名と2つの入力を定めます。型の判定は、小数や文字列を受け取って誤った規則で計算するのを防ぎます。次の判定は量の範囲を確かめ、違反なら例外で呼出し側に失敗を伝えます。正常な入力に進んだら、回数を0に初期化します。
whileの行は残量が1回分以上かを判定します。真の場合、次の行は残量から1回分を引き、その次の行が回数を1増やします。2行はともに本体なので、判定が偽ならどちらも実行しません。returnは反復後の回数と残量を組で返し、最後の行が表示します。
判定前の残量 判定 処理後の残量 回数
14 真 10 1
10 真 6 2
6 真 2 3
2 偽 実行なし 3
Python 3.15.0で入力14、4を実行した実際の出力は (3, 2) でした。手計算と一致し、3回分の12と残量2を合わせると元の14に戻ります。残り2は1回分の4より小さいので、追加の作業はできません。
境界を含む入力で確かめる
標準例題として、同じ関数に残量12、1回分3を渡します。答えは (4, 0) です。残量は12、9、6、3、0と進み、0の判定で止まります。最後の3でも作業できるため、条件が stock > amount では1回不足します。4回分は12であり、残量0と合わせて最初の量に戻ります。
一方、残量2、1回分5なら最初の判定が偽です。期待値と実行結果は (0, 2) です。0回分と残量2で元の2に戻り、残りは5より小さいため、作業回数0は妥当です。残量0、1回分5も (0, 0) になります。これらは更新の前に止まる経路を調べる試験です。
発展として、消費量0を許すと何が起きるでしょうか。残量が0以上であれば条件は常に真で、0を引いても残量は変わりません。この入力で反復を開始してはいけません。上の関数は事前に例外を出し、呼出し側に入力の見直しを求めます。負の消費量なら残量が増えるため、同じ停止の説明は成立しません。残量が負の場合も場面の前提に反するため拒否します。
入力が不正な場合の期待と実行結果を、正常な境界と対にして示します。次の表で「例外」は ValueError です。例外のとき回数と残量の組は返しません。外部の装置や通信はこの関数に含まれないため、その失敗は関数の入力仕様として扱っていません。
入力 期待 実際
(12, 3) (4, 0) (4, 0)
(2, 5) (0, 2) (0, 2)
(0, 5) (0, 0) (0, 0)
(1, 1) (1, 0) (1, 0)
(12, 0) ValueError ValueError
(12, -1) ValueError ValueError
(-1, 3) ValueError ValueError
("12", 3) ValueError ValueError
例えば文字列の "12" は数字に見えても、整数の12ではありません。自動変換せず例外とするのがここでの約束です。呼出し側が入力文字を整数に変換するなら、その変換の失敗も別途受け止める必要があります。関数の中でどんな入力も直してよいと考えると、誤入力を見逃すことがあります。
更新忘れを表で見つけて直す
次は基本例題のつもりで書いた誤りです。実際には無制限に実行せず、最初の3回だけを紙上で追います。
残量を14、回数を0にする
残量が4以上の間:
回数を1増やす
図3のように、残量は14のままで、判定は毎回真です。回数だけが増えても、判定に使う残量は変わりません。処理を待ち続けても期待の3回では終わらないため、外の道具による時間切れを正常な答えとして扱ってはいけません。

原因は、消費する操作が本体から抜けたことです。回数を増やす前に残量から4を引く行を加えます。修正後に14、4を再実行すると (3, 2) です。さらに12、3では (4, 0)、2、5では (0, 2) となり、元の例と境界の両方で期待に合います。
誤りは更新忘れだけではありません。消費量を加えてしまえば残量が増えますし、更新を反復の外に置けば、反復中の残量は動きません。等号を落とせばちょうど1回分あるときに早く終わり、逆に残量が正なら続ける条件では1回分に満たない残量からも引いて負になります。どの場合も、最初に食い違う判定前後の行を探すと、修正箇所を絞れます。
自分で追う5問
各問は互いに独立しています。量は整数、消費は1回分以上あるときに行い、残量が不足したら止めます。指定した形で答え、途中の値も記してください。
- 紙が17単位あり、1回に5単位使います。回数と残量を整数の組で答えてください。
- 糸が18単位あり、1回に6単位使います。回数と残量を整数の組で答えてください。
- 水が3単位あり、1回に7単位使います。本体の回数と、最後の偽を含む判定回数を整数の組で答えてください。
- 素材が11単位あり、1回に4単位使います。誤って条件を残量が正の間とした場合、残量の推移と、正しい規則との違いを答えてください。
- 関数に残量8、消費量0を渡します。返る組または例外の名前を答え、消費量0のまま検査なしで反復を始めた場合の状態を説明してください。
答えと照合
(3, 2)です。残量は17、12、7、2で、判定は最後に偽です。5単位を3回使うと15単位で、2を戻せば17です。2は5未満なので4回目はできません。(3, 0)です。18、12、6、0と進みます。6単位を3回で18単位となり、ちょうど残りません。最後の6を使えることが等号の確認になります。(0, 1)です。最初の3は7未満なので本体は0回、最初の判定が偽となる1回です。水3単位はそのまま残り、1回分には不足しています。- 誤った推移は11、7、3、-1です。正しい条件なら3で止まり、2回使って残量3です。8と3を合わせて11に戻ります。誤った条件は3の時点で必要な4を確保できず、負の残量を作ります。
ValueErrorです。関数は消費量が正でないことを先に検出します。検査を省くと残量8は0を引いても8のままで、条件は真のままです。無制限に実行せず、同じ状態が続くことから停止しないと判断します。
Python 3.15.0で前の関数に順に (17, 5)、(18, 6)、(3, 7)、(11, 4)、(8, 0) を渡した実際の結果は、それぞれ (3, 2)、(3, 0)、(0, 3)、(2, 3)、ValueError です。問3は返された残量3から最初の判定が偽と確かめ、問4の誤りは有限回の手追いで検証しました。別の計算として、正常入力の回数と残量は整数の商と余りでも照合できます。ただし商と余りの照合だけで更新忘れの原因を説明することはできません。
手元に残す要点
- 判定が真なら本体を行い、更新後に再び判定します。
- 最初の判定が偽なら、本体は0回です。
- 正の量ずつ減り、負にならないことが停止の根拠です。
- 終了時の残量と回数を、元の量へ戻して照合します。
- 不正な量を反復前に拒否し、失敗を正常な結果と区別します。
説明が止まった箇所から見直す
個別指導で確かめるなら、まず本人に最初の判定前の残量を指してもらいます。次に本体の各行の後で、残量と回数のどちらが変化したかを表に書きます。最後の偽の判定を表から落とす人には、反復の後へ進む矢印を説明してもらうと、処理回数と判定回数の混同が見えます。
更新したから止まると言えた場合も、更新の向きと量を変えたらどうなるか尋ねます。0を引く場合や負の量を引く場合に元の説明が使えないと気づけば、正の消費量という前提の役割が見えてきます。残量がちょうど1回分の行と、初めから不足する行を並べて、条件の等号と0回の経路を自分の言葉で説明できれば、停止の根拠までたどれます。
読んで終わりにするか、ここから変えるか。
武蔵境駅徒歩30秒、講師1人に生徒1人の完全1対1。授業のあいだ、先生は隣を離れません。いまの詰まりを、無料相談でそのまま話してください。
まず15分だけ電話で話したい方は、無料電話相談(15分)から。塾からお電話を差し上げます。
本気になった日が、入塾の日。
お子様の教育、迷ったら「丸投げ」してください。必ず、期待以上の結果で返します。武蔵野で育む、武蔵境で学ぶ。
電話は年中無休。365日、24時間、お電話可能。




