3.3 forループ

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

目次

サンプル・プログラム

複利計算

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

  44:         //複利計算
  45:         let deposit = principal;    //預金額
  46:         for (let i = 0i < periodi++) {
  47:             deposit *= (1 + rate);
  48:         }

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

通日計算

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

  42:         //通日計算
  43:         for (let i = 1i <monthi++) {
  44:             let mm = 0;
  45:             //月の大小判定
  46:             switch (i) {
  47:                 case 1:
  48:                 case 3:
  49:                 case 5:
  50:                 case 7:
  51:                 case 8:
  52:                 case 10:
  53:                 case 12:
  54:                     mm = 31;
  55:                     break;
  56:                 case 4:
  57:                 case 6:
  58:                 case 9:
  59:                 case 11:
  60:                     mm = 30;
  61:                     break;
  62:                 case 2:
  63:                     //うるう年判定
  64:                     if (year % 400 === 0) {
  65:                         mm = 29;
  66:                     } else if (year % 100 === 0) {
  67:                         mm = 28;
  68:                     } else if (year % 4 === 0) {
  69:                         mm = 29;
  70:                     } else {
  71:                         mm = 28;
  72:                     }
  73:                     break;
  74:             }
  75:             //当月
  76:             if (i === month) {
  77:                 current_day += (day - 1);
  78:             //それ以外
  79:             } else {
  80:                 current_day +mm;
  81:             }
  82:         }
  83:         //計算結果

制御文のブロックの中に他の制御文を含めることができる。
ここでは、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文 を追加するだけで解くことができる。
制御文を適切に使うことで、問題が変わった場合に、少しの変更で対応が可能になる。

  48:         //複利計算
  49:         let deposit = principal;    //預金額
  50:         for (let i = 0i < periodi++) {
  51:             deposit *= (1 + rate);
  52:             if (deposit > border)   break;      //計算終了
  53:         }

境界値となる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