1.4 繰り返し処理

(1/1)
フリードリヒ・ガウス
フリードリヒ・ガウス
今回は、1から10までの整数の和を求めるプログラムを作ってみよう。

天才数学者ガウスは、7歳の時、 \( \displaystyle \frac{10 \times(1 + 10)}{2} \) という方法で解いてみせた。
しかし、私たちは凡人である――地道に1から10までを順に足し算していくことにする。ただ、プログラムには繰り返し処理という仕組みが用意されており、このような地道な繰り返し処理を簡単に書くことができる。

目次

サンプル・プログラム

1から10までの和

   9: <script>
  10: document.write(1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10);
  11: </script>

"add10.html" は、1から10までの整数の和、すなわち \[1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 \] の計算結果を表示するプログラムである。

数式をそのままプログラムにしただけだが、目的とする計算結果を正しく表示するから、このプログラムは正しい
しかし、1から100までの整数の和を計算しようとすると、1行がとても長くなってしまう。1行があまりにも長いと、たまたま計算結果が間違っていたときの不具合箇所(バグ)を探すのに時間がかかる

   9: <script>
  10: let n = 1;
  11: n = n + 2;
  12: n = n + 3;
  13: n = n + 4;
  14: n = n + 5;
  15: n = n + 6;
  16: n = n + 7;
  17: n = n + 8;
  18: n = n + 9;
  19: n = n + 10;
  20: document.write(n);
  21: </script>

Googleスプレッドシート:1から10の和を求める
Googleスプレッドシート:1から10の和を求める
そこで、足し算の部分を1行1行に分けたプログラムが "add11.html" である。
こうすればバグは見つけやすくなるが、1から100までの整数の和を計算しようとすると、100行になってしまい、わざわざプログラムにせずに ExcelやGoogleスプレッドシートでSUM関数を使って計算した方が早いだろう。

forループ

   9: <script>
  10: let n = 0;
  11: for (let i = 1i <10i = i + 1) {
  12:     n = n + i;
  13: }
  14: document.write(n);
  15: </script>

さて、多くのプログラミング言語には繰り返し処理という仕組みが用意されている。
"for1.html" は、繰り返し処理の一種である forループを使って1から10までの整数の和を計算するプログラムである。

"add11.html" で10行書いた足し算が \( n = n + i \) の1行にまとまっている。変数 i の値を1から10になるまで1ずつ増やし、この足し算の結果となる合計値を変数 n に代入していくのが forループの役割である。
for (初期値; 繰り返し条件; 繰り返し計算式) {
    処理1;
    処理2;
    ‥‥
}
forループ
forループは上図のように、ブレース {...} で囲まれた部分(JavaScriptではブロックと呼ぶ)を繰り返す。これをフロー図にしたのが左図である。

繰り返し条件は、初期値、繰り返し条件、繰り返し計算式で定める。
ここでは、初期値 \( i = 1 \)、繰り返し条件は \( i \leqq 10 \)(iが10以下;不等号は "<=" と記すことに注意)、繰り返す都度 \( i = i + 1 \) を実行する。
1から100までの整数の和を計算したいなら、繰り返し条件を変えるだけで対応できる。
let で宣言した変数はそのブロック内――ここでは forループのブレース {...} で囲まれた中――だけで通用する。いわゆるローカル変数の宣言となる。
足す数である変数 i は、繰り返し処理の他で使うことはないので、let宣言で十分である。

このように forループを使えば、プログラムがシンプルになりバグが発見しやすくなると同時に、似たような計算問題に対してプログラムを若干変更するだけで対応できる(再利用しやすい)。ExcelやGoogleスプレッドシートの関数よりプログラムが便利になるのは、繰り返し処理をはじめとする制御を使うときである。

コメント

   9: <script>
  10: //変数宣言
  11: let a = 1;      //開始値
  12: let b = 10;     //終了値
  13: let n = 0;      //合計値
  14: 
  15: //aからbまでの整数の合計を求める
  16: for (let i = ai <bi++) {
  17:     n = n + i;
  18: }
  19: //結果を表示する
  20: document.write(n);
  21: </script>

あとでプログラムを読み返したとき、その流れが分かるようにコメントを書き足したものが "for2.html" である。

JavaScript では // から行末までをコメントとして読み飛ばす。コメントには、日本語はもちろん、UNICODE絵文字を書くこともできる。
また、/* ... */ を使うと複数行のコメントを書くことができる。
/∗
  複数行の
  コメント
∗/
ここで、forループの繰り返し計算式 \( i = i + 1 \) が \( i++ \) になったことに注目してほしい。後者をインクリメント演算子と呼び、効果は \( i = i + 1 \) と同じだ。
前に述べたとおり、プログラムの可読性を損なわないレベルで短くすることは、バグを発見しやすくする。そのために用意されている演算子である。

コラム:無限ループ

エッシャー「上昇と下降」
エッシャー「上昇と下降」
私が初めて書いたプログラムは、今回紹介した「1から10までの整数の和」を求めるものだった。それから40年以上が経過したわけだが、じつは、forループの繰り返し条件を間違うのが、私のプログラミングの悪い癖の1つである。
小学校の算数で習う植木算を思い出してほしい。木の本数と木の間の数には1だけ差がある。また、道路に並べるときと、池の周りに並べるときとで1だけ差がある。この「1だけ差がある」ケースを間違うことがあるのだ。設計時の考察不足としか言いようがない😓
また、繰り返し条件が途中で割りきれない数(循環小数)になってしまい、正しく終了しないこともある。(「有限小数、循環小数、分数、無理数」参照)

オブジェクトを生成するようなループ処理が正常に終わらないと、メモリリークを起こしてアプリケーションがハングアップすることがある。仕事でプログラムを作っている皆さんは、無限ループに陥らないよう、緊急脱出できる例外処理をあらかじめ組み込んでおこう。

練習問題:植木算

(この項おわり)
header