[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

コンピュータIIB(Javaプログラミング入門)第5回

目次
5.1 反復
5.1.1 while文
5.1.2 for文
5.1.3 反復の使用例
5.2 演習5
5.3 レポート課題
5.4 参考文献
索引
for文   while文   繰返し文   反復   無限ループ   ループ制御変数   ループ文  

5.1 反復

5.1.1 while文

前回の授業では、選択というプログラムの構成要素を紹介しました。 今日は、 反復iteration ) について説明します。 反復を表す文は、 繰返し文repetitive statement ) 、または ループ文loop statement ) とよばれます。

反復にはいくつか種類がありますが、「何々が成り立つ間、何々を繰り返す」というものが基本です。 この種の反復には while文while statement ) を使います。 while 文は以下の形をとります。

while (condition) {
    statement; ...
}

これで、条件 condition が成り立っている間、文 statement ; ... が繰り返し実行されます。

while文の流れ
図 5.1  while文の流れ

ここで、Good afternoon!と10回出力するプログラムを考えます。 もちろん、

        System.out.println("Good afternoon!");
        System.out.println("Good afternoon!");
        System.out.println("Good afternoon!");
        ...
        System.out.println("Good afternoon!");

と書けば10回出力できますが、これと同じことを while 文で表すわけです。

はじめは数え上げ方式です。 これは、変数 i に0を代入しておき、Good afternoon!と一回出力するごとに i の値を1増やすということを、 i の値が10未満の間繰り返すものです。

/*  1*/ class TenAfternoons {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 0;
/*  5*/         while (i < 10) { // iが10未満の間繰り返す
/*  6*/             System.out.println("Good afternoon!");
/*  7*/             i++;
/*  8*/         }
/*  9*/     }
/* 10*/ }
asiaa1:~/comp2b b08a001$ java TenAfternoons
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
Good afternoon!
asiaa1:~/comp2b b08a001$

5行目から8行目までの while 文は次のように実行されます。

1. 変数 iの値は0。条件 i < 10 が成り立つので、Good afternoon!と出力し、i の値を1増やす。
2. 変数 i の値は1。条件 i < 10 が成り立つので、Good afternoon!と出力し、i の値を1増やす。
...
10. 変数 i の値は9。条件 i < 10 が成り立つので、Good afternoon!と出力し、i の値を1増やす。
11. 変数 i の値は10。条件 i < 10 は成り立たないので、このwhile文の実行を終える。

次はカウントダウン方式です。 これは、変数 i に10を代入しておき、Good afternoon!と一回出力するごとに i の値を1減らすということを、 i の値が正の数の間繰り返すものです。

/*  1*/ class TenAfternoons2 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 10;
/*  5*/         while (i > 0) { // iが正の数の間繰り返す 
/*  6*/             System.out.println("Good afternoon!");
/*  7*/             i--;
/*  8*/         }
/*  9*/     }
/* 10*/ }

5行目から8行目までの while 文は次のように実行されます。

1. 変数 i の値は10。条件 i > 0 が成り立つので、Good afternoon!と出力し、i の値を1減らす。
2. 変数 i の値は9。条件 i > 0 が成り立つので、Good afternoon!と出力し、i の値を1減らす。
...
10. 変数 i の値は1。条件 i > 0 が成り立つので、Good afternoon!と出力し、i の値を1減らす。
11. 変数 i の値は0。条件 i > 0 は成り立たないので、このwhile文の実行を終える。

数え上げ方式とカウントダウン方式のどちらがよいかは、問題によって変わります。 数え上げ方式のほうがよく使われますが、カウントダウン方式が適切な場合もあります。

さて、上記のプログラムで、7行目を書き忘れたとしましょう。

/*  1*/ class InfiniteAfternoons {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 10;
/*  5*/         while (i > 0) { // 永遠に条件が成立
/*  6*/             System.out.println("Good afternoon!");
/*  7*/             // i--;
/*  8*/         }
/*  9*/     }
/* 10*/ }

このプログラムを実行しますと、変数 i の値は10のままです。 したがって、条件 i > 0 がずっと成り立ち、永遠にGood afternoon!と出力され続けることになります。

このような、いつまでも続く繰り返しを、 無限ループinfinite loop ) とよびます。 反復を使うときは、無限ループにならないように気をつける必要があります。 なお、誤って無限ループに陥ったときは、Ctrl-Cで強制終了してください。

無限ループ
図 5.2  無限ループ

また、繰り返しの回数を0にしますと、0回繰り返す、つまり、一度も実行されなくなります。

/*  1*/ class NoAfternoons {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         i = 0;
/*  5*/         while (i < 0) { // 最初から条件が不成立
/*  6*/             System.out.println("Good afternoon!");
/*  7*/             i++;
/*  8*/         }
/*  9*/     }
/* 10*/ }

このプログラムを実行しますと、条件 i < 0 は初めから成り立ちませんので、何も出力されないのです。

一度も実行されないループ
図 5.3  一度も実行されないループ

5.1.2 for文

反復の種類の中には、繰り返す回数が明確なものがあります。 この場合、 ループ制御変数loop control variable ) とよばれる変数を増加(あるいは減少)させながら繰り返すのが一般的です。 for文for statement ) を用いますと、このような反復をコンパクトに書き表すことができます。 for 文は次のような形をとります。

for (statement1; condition; statement2) {
    statement3; ...
}

これで、まず文 statement1 が一度だけ実行されます。 そして条件 condition が成り立っている間、文 statement3 ; ...statement2 が繰り返し実行されます。

while 文を使ってこの for 文を書きますと、次のようになります。

statement1;
while (condition) {
    statement3; ...
    statement2;
}

for 文を用いますと、Good afternoon!と10回出力するプログラムは次のように書けます。 数え上げ方式については、

/*  1*/ class TenAfternoons3 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         for (i = 0; i < 10; i++) { // 10回繰り返す
/*  5*/             System.out.println("Good afternoon!");
/*  6*/         }
/*  7*/     }
/*  8*/ }

です。 カウントダウン方式は、

/*  1*/ class TenAfternoons4 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         for (i = 10; i > 0; i--) { // 10回繰り返す
/*  5*/             System.out.println("Good afternoon!");
/*  6*/         }
/*  7*/     }
/*  8*/ }

となります。

while 文と for 文には本質的な差はありません。 繰返しの回数がはっきりしているときには for 文、そうでないときには while 文を使うのがよいでしょう。

5.1.3 反復の使用例

反復の使用例として、はじめに 1 + 2 + ... + 100 の計算を行います。

この問題は、レジの計算をまねることで解決できます。 つまり、それまでの合計を表す変数 sum を用意して、初期値を 0 とします。 そして、 sum の値を 1 増やし、2 増やし、…と繰り返し、100 増やした時点の sum の値が答になるわけです。 したがって、

        sum = sum + 1;
        sum = sum + 2;
        sum = sum + 3;
        ...
        sum = sum + 100;

と同じことを for 文で表します。

プログラムは次の通りです。

/*  1*/ class Summation100 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, sum = 0;
/*  4*/         for (i = 1; i <= 100; i++) { // 100回繰り返す
/*  5*/             sum = sum + i;
/*  6*/         }
/*  7*/         System.out.println(sum);
/*  8*/     }
/*  9*/ }
asiaa1:~/comp2b b08a001$ java Summation100
5050
asiaa1:~/comp2b b08a001$

次の例は、360 の約数をすべて求めるものです。

360 の約数が、1 から 360 までの間にあることは、数学的に分かっています。 したがって、1 から 360 までの数一つ一つに対して、360 がその数で割り切れるかどうかを判断すれば、約数がもれなく見つけられます。 つまり、

        if (360 % 1 == 0) {
            System.out.println(1);
        }
        if (360 % 2 == 0) {
            System.out.println(2);
        }
        ...
        if (360 % 360 == 0) {
            System.out.println(360);
        }

と同じことを for 文で表します。

プログラムは次の通りです。

/*  1*/ class Divisors360 {
/*  2*/     public static void main (String[] args) {
/*  3*/         int i;
/*  4*/         for (i = 1; i <= 360; i++) { // 360回繰り返す
/*  5*/             if (360 % i == 0) {
/*  6*/                 System.out.println(i);
/*  7*/             }
/*  8*/         }
/*  9*/     }
/* 10*/ }
asiaa1:~/comp2b b08a001$ java Divisors360
1
2
3
4
5
6
8
9
10
12
15
18
20
24
30
36
40
45
60
72
90
120
180
360
asiaa1:~/comp2b b08a001$

アプレットの例として、正方形を描きます。

以前、次のような図形を描きました。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/ 
/*  4*/ public class BlackBox extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         g.setColor(Color.black);
/*  7*/         g.fillRect(50, 50, 100, 100);
/*  8*/     }
/*  9*/ }
塗り潰した正方形
図 5.4  塗り潰した正方形

塗り潰した正方形(長方形)を描くために、 g.fillRect( ... ); を使っています。 ここではこれを用いず、自分で正方形を塗り潰すことにします。

正方形は、上から順にすきまなく水平線を引いていけば、塗り潰すことができます。 この場合は、

        g.fillRect(50, 50, 100, 100);

の代わりに

        g.drawLine(50, 50, 149, 50);
        g.drawLine(50, 51, 149, 51);
        g.drawLine(50, 52, 149, 52);
        ...
        g.drawLine(50, 149, 149, 149);

と同じことを実行すればよいわけです。 ( g.drawLine(50, 50, 150, 50); だと、101ピクセルになってしまいます。)

プログラムは次の通りです。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/
/*  4*/ public class FillSquare extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         int i;
/*  7*/         for (i = 0; i < 100; i++) { // 100回繰り返す
/*  8*/             g.drawLine(50, 50 + i, 149, 50 + i);
/*  9*/         }
/* 10*/     }
/* 11*/ }

この方法を応用しますと、色々な図形が描けるようになります。 例えば、次のような直角三角形を考えます。

直角三角形
図 5.5  直角三角形

この図形は、

        g.drawLine(50, 50, 51, 50);
        g.drawLine(50, 51, 53, 51);
        g.drawLine(50, 52, 55, 52);
        ...
        g.drawLine(50, 149, 249, 149);

と同じことを実行すれば描けます。

プログラムは次の通りです。

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/
/*  4*/ public class RightTriangle extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         int i;
/*  7*/         for (i = 0; i < 100; i++) { // 100回繰り返す
/*  8*/             g.drawLine(50, 50 + i, 51 + 2 * i, 50 + i);
/*  9*/         }
/* 10*/     }
/* 11*/ }

5.2 演習5

以下の二等辺三角形を for 文を用いて描きます。

二等辺三角形
図 5.6  二等辺三角形

この図形は、

        g.drawLine(150, 50, 151, 50);
        g.drawLine(149, 51, 152, 51);
        g.drawLine(148, 52, 153, 52);
        ...
        g.drawLine(51, 149, 250, 149);

と同じことを実行すれば描けます。 この描き方に対応するアルゴリズムを考え、プログラムを作成してください。

余力のある人は、平行四辺形、ひし形など、自分で考えた図形を for 文を用いて描いてください。


5.3 レポート課題

今日の演習5の答案(Javaプログラム)をメールで提出してください。 差出人は学内のメール・アドレス(b08a001@cis.twcu.ac.jpなど)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(5月9日)を明記してください。


5.4 参考文献


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2008年5月9日更新
小西 善二郎 <konishi@cis.twcu.ac.jp>
Copyright (C) 2008 Zenjiro Konishi. All rights reserved.