プログラミング/3

出典: CourseWiki

目次

繰り返し(while文)

コンピュータは繰り返しが得意と言われています.今度は繰り返しに挑 戦してみましょう. コンピュータに次の図のように繰り返し処理をさせたいことはよくあります.

画像:Whileloop.png

while文はこのようなことを書くための構文です.while文はこんな形をしています.

while (条件) {
  文;
}

条件の部分は,if文と同じように真偽式を書きます.

while文を使うと,「ある条件が成り立っている間,ある処理を繰り返す」ことができます. 次のプログラムは下の図のように実行されます.

処理1;
while (条件) {
  処理2;
  処理3;
}
処理4;

画像:While.png

while文の中を実行することによってそのうち条件が満たされるようにプログラムを書きます. (そうしないと,プログラムの実行が終わりません).

逐次処理条件分岐(if文)繰り返し(while文) の3つがプログラムの基本的な構造になります.どんなに複雑な処理も(理論的には)この3つを使って書くことができます.

注意: while文で指定した条件のチェックは,while文に入るときと,while文の最後でのみ行われます. 最初から条件が満たされていなければ,while文の実行はスキップされます.

while文を使った繰り返しの方法

繰り返しの回数が予めわかっているならば,繰り返しの回数を変数で数え ます.繰り返しの数を数えるために使う変数を,カウンタあるいはループ変数などと呼ぶこと があります.

while文を書くときは,カウンタの値をどのように変化させるかを考えることがポイントです.

以下は n 回繰り返す場合の典型的な例です.

// 0から数えるスタイル
int i = 0;              // 繰り返しの数を数える変数(カウンタ)
while (i < n) {
  繰り返したいコト;
  i = i + 1;	        // カウンタを増やす
}
System.out.println("i の値は " + i + " です");

i = i + 1 というのは変な気がするかも知れませんが,Java の = は, 等しいという意味ではなく,右側の値を左側の変数に代入するという意味 なので,これで i の値を 1 増加させることができます.

n = 3 のとき,このプログラムは以下のように実行され,結局「繰り返したいコト」が3回実行されます.

1 int i = 0; i に 0 が代入される
2 i < n か判定 true なので while 文の中へ進む
3 繰り返したいコト;
4 i = i + 1; i に 1 が代入される
5 i < n か判定 true なので while 文の中へ進む
6 繰り返したいコト;
7 i = i + 1; i に 2 が代入される
8 i < n か判定 true なので while 文の中へ進む
9 繰り返したいコト;
10 i = i + 1; i に 3 が代入される
11 i < n か判定 false なので,while文を終了して次に進む
12 System.out.println("i の値は" + i + "です"); "i の値は3です" と表示

他にもいろいろな書き方が可能です.

// n から減らしていくスタイル
// これだと,変数 i が不要になる.
// nの値が書き変わっても問題ない場合(後でnの値を参照しない場合)はこれを使うとスマート.
while (n > 0) {
  繰り返したいコト;
  n = n - 1;
}
// 1から数えるスタイル (あまり使われない)
int i = 1;
while (i <= n) {
  繰り返したいコト;
  i = i + 1;
}

簡単な例

while文を使って,整数の掛け算を * (乗法演算子) を使わずにやってみ ましょう.x * y は,x を y 回加えることで計算できます.

// 乗算演算子(*)を使わずに掛け算してみる
 
public class Multiple {
    public static void main(String[] arg) {
        System.out.print("x: ");
        int x = Keyboard.intValue();
        System.out.print("y: ");
        int y = Keyboard.intValue();
 
        // 結果を覚えておく変数を用意して 0 にしておく
        int kekka = 0;
 
        while (y > 0) {                 // この条件が成り立つ間繰り返す
            // 繰り返したいコト
            kekka = kekka + x;          // 結果に x を足す
            System.out.println("kekka = " + kekka); // 実行観察用の表示
            System.out.println("y = " + y);         // 実行観察用の表示
 
            y = y - 1;                  // y から 1 を引く
        }
        System.out.println("乗算結果は " + kekka + " です");
    }
}

whileの中を一度実行すると,y の値が 1 減るので,そのうち y > 0が偽になって,while 文の実行が終わり,結果が表示されます.

実際に動かして,while文の中がy回実行されることを確認してください.


演習(階乗)

キーボードから整数nを入力し,nの階乗(1 * 2 * .... * n) を求めるプログラム Factorial を作って下さい. 結果はかなり大きな数になるので,int型ではなくlong型を使ってください.

考え方

(fact = fact * 1)
fact = fact * 2
fact = fact * 3
...
fact = fact * n
のように繰り返し計算すれば良いので while文を使って
 fact = fact * i
 i = i + 1
を繰り返す構造を書きます.
fact の初期値が 0 だと,何回掛けても 0 になってしまうので注意.

演習(階乗)の解答例

演習(ユークリッドの互除法)

2つの数A, B(正の整数とする)を入力し,次の方法を使って最大公約数を計算するプログラム(Euclid)を作ってください. この方法は「ユークリッドの互除法」として知られています.

  • A, B がともに 0 より大きい間,以下を繰り返す
  • A > B のとき: A を B で割った余りを A とする
  • そうではないとき(A <= B のとき): B を A で割った余りを B とする
  • A が 0 ならば,B の値を出力
  • B が 0 ならば,A の値を出力

演習(ユークリッドの互除法)の解答例

++ 演算子と -- 演算子

プログラミングでは,1を足したり1を引いたりすることがよくあります. このために,Javaでは簡単な書き方を用意しています.

i++;  // i = i + 1; と同じ
++i;  // i = i + 1; と同じ
i--;  // i = i - 1; と同じ
--i;  // i = i - 1; と同じ

i++ と ++i はどちらもiを1増加させますが,式として見たときの値が異なります.

i++ の式としての値は i です.つまり,a = i++; と書くと,a には i を1増やす前の値が代入されます. 一方,++i の式としての値は i+1 です.つまり,a = ++i; と書くと,a にはiを1増やした後の値が代入されます.

同様に,i-- の式としての値は i,--i の式としての値は i-1 になります.


繰り返しからの脱出(break文)

次のようなプログラムを考えます.

キーボードから整数を2つ入力し,両者の和を表示するプログラム Wa を作ってください. ただし,何度も計算できるように,入力した2つの数が両方とも0だった場合は,プログラムを終了し,そうでなかった場合はまたキーボードから入力して和を計算できるようにしてください.

[... ~/Java/Wa] java Wa
x: 10
y: 15
10 + 15 = 25
x: 2
y: 10
2 + 10 = 12
x: 0
y: 0
終了します
[... ~/Java/Wa] 

こんな感じで書けるでしょう.

// キーボードから整数を2つ入力
while ((両方とも0)ではない) {
  // 和を計算して表示
  // キーボードから整数を2つ入力
}

でも,この書き方は「キーボードから整数を2つ入力」する処理が2回でてくるのがイマイチです (プログラミングでは,なるべく同じ処理を2度書かないというのが基本). 次のように書けると便利です.

while (条件) {
  // キーボードから整数を2つ入力
  // 両方とも 0 だったら,while 文を終わる.
  // 和を計算して表示
}
//「終了します」と表示する.

このように,while 文の途中で繰り返しを終了できると都合がよい場合ががよくあります.このために Javaでは break文というものを用意しています.while 文の中で break 文を実行すると,while 文の実行をそこで中断し,while 文の次の文の実行に移ります.例えば,次のプログラムは下の図のように実行されます.

while (条件1) {
  処理1;
  if (条件2) {
    break;
  }
  処理2;
}

画像:Break.png

先ほどの例は break 文を使って次のように書くことができます.

while (条件) {
  // キーボードから整数 (x, y) を2つ入力
  // 両方とも 0 だったら,while 文を終わる.
  if (x == 0 && y == 0) {
    break;
  }
  //x と y の和を求めて表示する.
}
//「終了します」と表示する.

無限ループ

さて,今度はwhile文の条件について考えてみましょう.上のプログラム で while 文の実行を続ける条件はどうしたらよいでしょうか? x と y のチェックをしないといけないと思いましたか? 実はそんなこ とはしなくてもかまいません.break 文によって while 文を終わるので, while 文のほうではチェックする必要がないのです.

こういうときには,条件に true と書きます.true は真偽式のところで出てきましたが,「条件成立」を意味する Java の特別な定数です(反対の定数に条件不成立を表す false があります).

while (true) と書くと,while 文の条件は常に成り立つので,break 文を実行しない限り while 文から抜け出すことはありません.このような while 文のことを無限ループと呼びます. while (true) と書いておいて,途中で if 文で条件を判定して適宜 break を実行するようなスタイルはよく使われるので慣れておきましょう.

while (true) {
  // キーボードから整数 (x, y) を2つ入力
  x = ...;
  y = ...;
  // 両方とも 0 だったら,while 文を終わる.
  if (x == 0 && y == 0) {
    break;
  }
  //x と y の和を求めて表示する.
  System.out.println...
}
//「終了します」と表示する.


段階的詳細化

上の例でやったように,プログラムを書くときは,まずおおまかなプロ グラムの構造を書いてみましょう.日本語で構いません.それをだんだんと 詳細化していき,最後にはプログラミング言語 (Java) の記述にします.こ れを段階的詳細化と言います.プログラム言語でいきなり書き出す よりも簡単に書くことができます. 繰り返しがあるときは,何を繰り返すのか,つまりwhile文の中でやるべ きことは何かに注意して詳細化していきます. 詳細化するときに,日本語をコメントとして残すようにしましょう.分 かりやすいプログラムを書くことができます.

課題3-1 (駐車料金)

A駐車場の料金は,60分まで1000円,以後,30分毎に600円です.
駐車する時間を分単位で入力し,駐車料金を求めるプログラム ParkingCharge を書け.while文の練習なので,while文を使うこと.

ソースプログラム,実行結果,感想を提出すること.

ヒント

while文を使って,1回繰り返す毎に600円加算するような構造を作る.

  • キーボードから駐車時間(time)を入力する.
  • 料金(charge)を1000円にセットする.
  • 駐車時間から 60 を引く.
  • 以下を繰り返す.
    • 駐車時間が 0 より大きいならば,料金に600円加算し,駐車時間から30を引く.
  • 料金を表示する.

課題3-2 (数当てゲーム)

コンピュータが考えた0から99までの整数を人が当てるゲーム Kazuate を作れ.

0〜99の範囲で値を入れてください.
Number: 30
30より大きいです
Number: 80
80より小さいです
Number: 40
40より大きいです
Number: 44
4回目で正解!         (このように何回目で正解したかも表示してください)

余裕がある人は,入力された値が正解の±1だったときに,惜しい!と表示して下さい. さらに余裕がある人は,入力された値が正解の±1だったときに,惜しい!と表示して,コンピュータの考えている数を再度計算しなおしてください.

ソースプログラム,実行結果,感想を提出すること.

ヒント

  • いきなりプログラムを書きはじめるのではなく,プログラムの大まかな構造を考える.繰り返される部分は while を使って書けるはず.
  • 何回目で正解したかの表示は後から付け加えたら良い.
  • 例えば以下のような構造で実現できる.
while (true) {
  入力
  正解なら break
  大小の表示
}
  • 何回目で正解したかを表示するためには,何回目かを覚えておく変数を作っておき,繰り返す度にその変数を +1 する.

乱数

コンピュータにでたらめな数を考えさせるには,乱数を使います. JavaではMath.random()を使うことで,0以上1未満の範囲の乱数(double型) を発生させることができます. 0〜99までの整数で乱数が欲しいときは,

int answer = (int)(Math.random() * 100);

のように書きます.

キャスト演算子

Math.random() は実数型(double)の値を返します.double型の値を int 型 の変数に代入するためには,(int) というおまじないが必要です. この(int)によって,実数型の値が整数型に変換(小数点以下切り捨て)されます.

このようにかっこ()の中に型名を書いたものは キャスト演算子 と 呼ばれます.キャスト演算子は,値の型を明示的に変換するためのものです (double型をint型に,long型をint型に,等).

double型をint型の変数に代入する場合のように,代入するときに精度が悪くなる可能性があるときは, 必ずキャスト演算子が必要です. これを忘れるとコンパイルエラー(Type mismatch: cannot convert double to int など)になるので気をつけてください.

なお,上の例ではカッコの位置に気をつけてください.

int answer = (int)(Math.random()) * 100;

だと answer には常に 0 しか入りません.

Copyright (C) 2002-2015 Kota Abe, Osaka City University

ナビゲーション