3.3 forループ

(1/1)
ペンローズの階段
ペンローズの階段
複利計算や通日計算のように、繰り返し計算を行うときに for ループが活躍する。
さらに、for ループの中に if~else 文switch~case 文を組み込んだり、break を使って脱出することで応用範囲が広がる。

サンプル・プログラム

複利計算

Excelで複利計算
10,000 円のお金を金利 1.1%で 10 年間預けると‥‥この複利計算を Excel で表計算すると左図のようになる。
10 年ならいいが、これが 30 年、50 年‥‥となると、大きな表計算になってしまう。
こういうときにプログラムを使うと便利だ。

0044:         //複利計算
0045:         var deposit = principal; //預金額
0046:         for (let i = 0; i < periodi++) {
0047:             deposit *= (1 + rate);
0048:         }

JavaScriptで複利計算
for ループを使うと、期間(年数)が何百年になろうが、実質3行のプログラムで複利計算ができる。
JavaScriptで複利計算
for ループ は次のようにして使う(再掲)。
for (初期値; 繰り返し条件; 繰り返し計算式) {
    処理1;
    処理2;
    ‥‥
}
まず初期値を計算する。そして、繰り返し条件が成立する間、ブレース {...} で囲まれたブロック文を実行し、繰り返し計算式を計算する。
複利計算のように繰り返しが「回数」で決まる場合、初期値、繰り返し条件、繰り返し計算式にはカウンタが入る。カウンタとしては変数 i を使うのがお作法だ。

通日計算

通日計算
その年の 1 月 1 日から数えて、今日が何日目に当たるか――通日を求めるプログラムを作ってみよう。

0042:         //通日計算
0043:         for (let i = 1; i <= monthi++) {
0044:             let mm = 0;
0045:             //月の大小判定
0046:             switch (i) {
0047:                 case 1:
0048:                 case 3:
0049:                 case 5:
0050:                 case 7:
0051:                 case 8:
0052:                 case 10:
0053:                 case 12:
0054:                     mm = 31;
0055:                     break;
0056:                 case 4:
0057:                 case 6:
0058:                 case 9:
0059:                 case 11:
0060:                     mm = 30;
0061:                     break;
0062:                 case 2:
0063:                     //うるう年判定
0064:                     if (year % 400 == 0) {
0065:                         mm = 29;
0066:                     } else if (year % 100 == 0) {
0067:                         mm = 28;
0068:                     } else if (year % 4 == 0) {
0069:                         mm = 29;
0070:                     } else {
0071:                         mm = 28;
0072:                     }
0073:                     break;
0074:             }
0075:             //当月
0076:             if (i == month) {
0077:                 current_day += (day - 1);
0078:             //それ以外
0079:             } else {
0080:                 current_day += mm;
0081:             }
0082:         }
0083:         //計算結果

制御文のブロックの中に他の制御文を含めることができる。
ここでは、for ループ の中に、「3.2 switch~case 文」で紹介した月の大小を求めるため switch~case 文と、「3.1 if~else 文」で紹介したうるう年を求めるため if~else 文を組み込むことで通日を計算している。

再び複利計算

JavaScriptで複利計算
話は複利計算に戻る。
お気づきの方も多いと思うが、Excel の FV関数を知っていれば、1行で複利計算ができる。
ここで、10,000 円のお金を金利 1.1%で預けたとき、11,000 円を超えるのは何年目か――この問題を Excel で解くにはやや手間がかかる。だが、プログラムであれば、前述の for ループ に 1行 if 文 を追加するだけで解くことができる。
制御文を適切に使うことで、問題が変わった場合に、少しの変更で対応が可能になる。

0048:         //複利計算
0049:         var deposit = principal; //預金額
0050:         for (var i = 0; i < periodi++) {
0051:             deposit *= (1 + rate);
0052:             if (deposit > border)   break;       //計算終了
0053:         }

境界値となる 1,100 円を変数 border に入力する。
for ループ で複利計算中をしている最中、預金額 deposit が境界値 border を超えたら break する。
break は「3.2 switch~case 文」で紹介したが、これを実行すると処理を中断し、ブロックの外へ制御を移す。つまり、if 文を使って預金額 deposit が境界値 border を超えたら、複利計算を中断(ループから脱出)する。

コラム:GOTO文

柵をすり抜けて侵入する人のイラスト
BASIC や FORTRAN といったプログラミング言語では、break に相当する命令がなく、GOTO を使って for ループから脱出した。

"for5.html" と同じプログラムを BASIC で書くと、次のようになる。

deposit = 10000
For i = 0 to 30
    deposit = deposit * 1.011
    If deposit > 11000 Then Goto *Disp
next
*Disp
Print deposit
End
GOTObreak と違って、ブロックからの脱出といった使い方の制約がなく、どこへでもジャンプすることができる。無制限に GOTO を使うとプログラムの流れを追うことが難しくなり、バグの温床となった。
こうして「GOTO は使ってはいけない」というお作法が広まったのだが、本来の経緯から言えば、ループからの脱出に用いるなど使用法を制限すればいいのであって、GOTO そのものが悪いわけではない。

さらに言えば、CPU に直接命令を書くことができるアセンブラ言語では、制御文に当たる命令がなく、ほとんどが条件演算と GOTO に相当する jmp 命令(プログラムカウンタに代入する)の組み合わせで実現している。つまり、JavaScript も BASIC も、最終的には GOTO に相当する命令を CPU に送っている。

本シリーズを含め、プログラミングの参考書で「お作法」を見かけたときは、なぜそのお作法ができたのか、経緯まで遡って調べてほしい。そういう手間暇を惜しまないのが、技術者のあるべき姿なので。
(この項おわり)
header