6日目 | Nim100日ドリル
~今日のテーマ~

今日の目標

今日は、条件が成り立っている間だけ処理を繰り返す while 文を学ぶ。
Day5 で学んだ for 文は「何回繰り返すか」が比較的はっきりしている場面で使いやすいが、while 文は「ある条件を満たしている間は続ける」という考え方で書く。
さらに、while 文ではカウンタ変数を自分で更新する必要があるため、更新を書き忘れると同じ処理が終わらずに続く無限ループになる。
最後に、0 から指定した数までの合計を while 文で求め、条件、更新、合計用の変数を組み合わせて使う練習をする。

今日の内容

6ー1 ~while 文は「条件が正しい間だけ繰り返す」ための道具である~

プログラムでは、同じような処理を何度も行いたい場面がよくある。
たとえば、0 から 5 までの数字を順番に表示したい場合、echo 0echo 1echo 2 と何行も書くことはできる。
しかし、表示する数が 5 ではなく 100 や 1000 になったら、この方法はすぐに破綻する。そこで繰り返し処理を使う。

while 文は、「条件が true である間、同じ処理を繰り返す」ための文である。Nim では次の形で書く。

                    
while 条件:
  繰り返したい処理
                    
                

例えば、次のようになる。

                    
var i = 0

while i <= 5:
  echo i
  i = i + 1
                    
                

このコードの読み方として、まず var i = 0 は繰り返しを始める位置を決めている。
次に while i <= 5: は、i が 5 以下である間だけ処理を続けるという条件である。
最後の i = i + 1 は、次の数字へ進むための更新である。
この更新がないと、i は 0 のままになり、繰り返しが終わらなくなる。

大事なのは、while の後ろに書いた条件が成り立つかどうかを、繰り返しのたびに確認するという点である。
条件が成り立っていれば中の処理を実行し、条件が成り立たなくなれば while 文を抜ける。

初心者が最初に混乱しやすいのは、while 文が「指定回数だけ勝手に回る文」ではないという点である。
for i in 0..5: のように書けば、Nim が i を順番に変化させてくれる。
しかし while 文では、変数を用意し、その変数をどう変化させるかまで自分で書く必要がある。
ここを曖昧にすると、思った回数だけ動かなかったり、いつまでも終わらない処理になったりする。

Nim では while の行の最後にコロン : が必要である。
また、while の中に入る処理はインデントで表す。インデントがずれていると、繰り返しの中にあるつもりの処理が外側に出てしまう。
Nim はインデントを文法として扱う言語なので、空白の位置は見た目以上に重要である。

6ー2 ~カウンタ変数の更新を書き忘れると無限ループになる~

while 文では、条件に使う変数を変化させる必要がある。
たとえば、i が 0 から始まり、5 まで表示したいなら、1回表示するたびに i を 1 増やす必要がある。
このように、繰り返しの回数や位置を管理する変数をカウンタ変数と呼ぶことが多い。

                    
var i = 0

while i <= 5:
  echo i
  i = i + 1
                    
                

このコードでは、最初に i は 0 である。
i <= 5 が成り立つため、echo i で 0 を表示する。
その後、i = i + 1 によって i は 1 になる。次の繰り返しでは、i が 1 の状態で条件を確認する。
この流れを繰り返し、i が 6 になった時点で i <= 5 が成り立たなくなり、while 文が終わる。

ここで i = i + 1 を書き忘れると危険である。i はずっと 0 のままなので、i <= 5 は永久に成り立ち続ける。
その結果、プログラムは 0 を表示し続ける。これが無限ループである。

無限ループは、プログラムが壊れたように見える代表的な原因である。
実行中のプログラムが止まらなくなった場合、多くの環境では Ctrl + C で停止できる。
ただし、毎回止めればよいという考え方ではなく、while 文を書くときには「この条件はいつか必ず false になるか」を確認する癖をつけるべきである。

Nim では i += 1 という短い書き方もできる。これは i = i + 1 とほぼ同じ意味である。
ただし、初学者の段階では、まず i = i + 1 と書いて「右辺で新しい値を計算し、左辺の変数に入れ直す」という流れを理解した方がよい。
慣れてから i += 1 を使えばよい。

6ー3 ~合計を求めるには「現在の数」と「合計用の変数」を分けて考える~

while 文は、数字を順番に表示するだけでなく、合計を求める処理にも使える。
たとえば、0 から 5 までの合計は 0 + 1 + 2 + 3 + 4 + 5 であり、結果は 15 である。
これをプログラムで書くには、今どの数を足そうとしているかを表す変数と、これまでの合計を保存する変数を分けて考える。

                    
var i = 0
var total = 0

while i <= 5:
  total = total + i
  i = i + 1

echo total
                    
                

このコードでは、i が現在足す数、total が合計を保存する変数である。
最初はまだ何も足していないので、total は 0 から始める。
while i <= 5: の中で total = total + i を実行すると、現在の total に i の値が加えられる。
その後、i = i + 1 で次の数へ進む。

初心者がよく間違えるのは、total の初期値を用意しないこと、または total = i のように毎回上書きしてしまうことである。
合計を作りたい場合は、前回までの合計を残したまま、そこに新しい値を足す必要がある。
そのため、total = total + i という形になる。

もう一つの注意点は、入力された文字列を数値として扱う場合である。
Nim の readLine(stdin) は文字列を返すため、そのままでは整数として計算できない。
整数に変換するには parseInt を使う。
そのためには、ファイルの先頭で import std/strutils と書く必要がある。
これを書き忘れると、parseInt が見つからないという意味の undeclared identifier: 'parseInt' というエラーになる。

課題1

この問題では、while 文を使って 1 から 5 までの整数を1行ずつ表示する。
穴埋め箇所には、繰り返しを続ける条件と、カウンタ変数を1増やす処理を入れる。
出力は数字だけにし、余計な説明文は表示しない。

                    
var i = 1

while ____:
  echo i
  ____
                    
                

期待する出力は次の通りである。

                    
1
2
3
4
5
                    
                

while の条件には「i が 5 以下である間」という意味の式を書く。
Nim では「以下」は <= で表す。
もう一つの穴には、i を 1 増やす処理を書く。i += 1 と書けば、現在の i に 1 を足した値を、もう一度 i に保存できる。

課題2

この問題では、出発コードを改造して、0 から 10 までの偶数だけを表示する。
出発コードは 0 から 5 までの数をすべて表示するコードである。
これを、2 ずつ増える形に変更する。

                    
var i = 0

while i <= 5:
  echo i
  i = i + 1
                    
                

期待する出力は次のとおりである。

                    
0
2
4
6
8
10
                    
                

終了条件は i <= 10 に変える必要がある。
さらに、1ずつ増やすのではなく、2ずつ増やす必要がある。つまり、更新部分は i = i + 1 では足りない。
偶数だけを表示したいなら、i を 0、2、4、6、8、10 と変化させればよい。

課題3

この問題では、標準入力から整数 n を1つ受け取り、0 から n までの合計を while 文で求めて表示する。
入力は整数1つであり、処理では i を 0 から始めて、n 以下である間だけ total に足していく。
出力は合計値だけにする。

                    
import std/strutils

let n = parseInt(readLine(stdin))

var i = ____
var total = ____

while ____:
  total = ____
  i = ____

echo total
                    
                

次の入力の場合を考える。

                    
5
                    
                

期待する出力は次のとおりである。

                    
15
                    
                

入力が 10 の場合は、0 から 10 までの合計なので、期待出力は 55 である。

よくあるエラーとして、import std/strutils を書き忘れて parseInt を使うと、undeclared identifier: 'parseInt' というエラーが出る。
これは、parseInt という名前の処理を Nim が見つけられないという意味である。
直し方は、ファイルの先頭に import std/strutils を書くことである。

もう一つのよくある失敗は、total = i と書いてしまうことである。
これでは合計ではなく、毎回 total が現在の i に上書きされるだけである。
合計を求めるには、前回までの合計に今回の i を足す必要があるため、total = total + i と書く。

今日のまとめ

今日は、while 文を使って条件が成り立っている間だけ処理を繰り返す方法を学んだ。
for 文は決まった範囲を順番に処理するときに使いやすいが、while 文は条件を自分で管理しながら繰り返す書き方である。
その分、カウンタ変数の初期値、条件式、更新処理の3つを正しくそろえる必要がある。

特に重要なのは、while 文ではカウンタ変数を自分で更新するという点である。
i = i + 1 のような更新を書き忘れると、条件がいつまでも変わらず、無限ループになる。
プログラムが止まらなくなったときは、条件に使っている変数が本当に変化しているかを確認するべきである。

また、合計を求める処理では、現在の数を表す i と、合計を保存する total を分けて考えた。
total = total + i は、前回までの合計に今回の値を足して、もう一度 total に保存するという意味である。
この形は、合計、個数、得点、回数などを扱う多くのプログラムで使う基本形である。

明日は、繰り返しの中で条件分岐を組み合わせる考え方に進むと、プログラムらしい処理が一気に増える。





5日目へ

7日目へ

トップへ戻る


お問い合わせ