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

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

目次
7.1 繰返し文(1)
7.1.1 while文
7.1.2 for文
7.1.3 繰返し文の使用例(1)
7.2 演習7
7.3 レポート課題
7.4 参考文献
索引
for文   while文   繰返し文   無限ループ   ループ制御変数   ループ文  

7.1 繰返し文(1)

7.1.1 while文

前回の授業では、条件文というものを使って、プログラムを作成しました。 今日は、 繰返し文 ( repetitive statement ) 、または ループ文 ( loop statement ) と呼ばれるものを使用します。

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

while (条件) {
    文; ...
}

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

while文の流れ
図 7.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 { // こんにちは10回
/*  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 { // こんにちは10回2
/*  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(controlキーとCキーを同時に押す)で強制終了してください。

無限ループ
図 7.2  無限ループ

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

/*  1*/ class NoAfternoons { // こんにちは0回
/*  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 は初めから成り立たないので、何も出力されないのです。

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

7.1.2 for文

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

for (変数初期化; 条件; 変数更新) {
    文; ...
}

これで、まず「 変数初期化 」が一度だけ実行されます。 そして「 条件 」が成り立っている間、「 文 」、...と「 変数更新 」が繰り返し実行されます。

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

変数初期化;
while (条件) {
    文; ...
    変数更新;
}

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

/*  1*/ class TenAfternoons3 { // こんにちは10回3
/*  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 { // こんにちは10回4
/*  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 文を使うのがよいでしょう。

ループ制御変数は、整数型にしてください。 実数型にすると、誤差の影響で、繰り返しの回数を間違える可能性があります。

/*  1*/ class ForIntTest { // for文で整数を使うテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         int i; // 整数型
/*  4*/         for (i = 0; i < 10; i++) { // 10 回繰り返す
/*  5*/             System.out.println(i);
/*  6*/         }
/*  7*/     }
/*  8*/ }
asiaa1:~/comp2b b08a001$ java ForIntTest
0
1
2
3
4
5
6
7
8
9
asiaa1:~/comp2b b08a001$
/*  1*/ class ForDoubleTest { // for文で実数を使うテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         double d; // 実数型
/*  4*/         for (d = 0.0; d < 1.0; d += 0.1) { // 11回繰り返してしまう
/*  5*/             System.out.println(d);
/*  6*/         }
/*  7*/     }
/*  8*/ }
asiaa1:~/comp2b b08a001$ java ForDoubleTest
0.0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999
asiaa1:~/comp2b b08a001$

なお、ループ制御変数は、 i , j , k などを使うのが一般的です。 変数名 i は、整数(integer)から来ているようです。

7.1.3 繰返し文の使用例(1)

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

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

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

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

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

/*  1*/ class Summation100 { // 合計100
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, sum = 0;
/*  4*/         for (i = 1; i <= 100; i++) { // 100回繰り返す
/*  5*/             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 { // 約数360
/*  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 BlackRect extends Applet { // 黒い長方形
/*  5*/     public void paint (Graphics g) {
/*  6*/         g.setColor(Color.black);
/*  7*/         g.fillRect(20, 40, 60, 80);
/*  8*/     }
/*  9*/ }
黒い長方形
図 7.4  黒い長方形
この図形の座標
図 7.5  この図形の座標

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

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

        g.fillRect(20, 40, 60, 80);

の代わりに

        g.drawLine(20, 40, 79, 40);
        g.drawLine(20, 41, 79, 41);
        g.drawLine(20, 42, 79, 42);
        ...
        g.drawLine(20, 119, 79, 119);

と同じことを実行すればよいわけです。 ( g.drawLine(20, 40, 80, 40); から g.drawLine(20, 120, 80, 120); までだと、幅61ピクセル、高さ81ピクセルになります。)

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

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/
/*  4*/ public class FillRect extends Applet { // 塗り潰した長方形
/*  5*/     public void paint (Graphics g) {
/*  6*/         int i;
/*  7*/         for (i = 0; i < 80; i++) { // 80回繰り返す
/*  8*/             g.drawLine(20, 40 + i, 79, 40 + i);
/*  9*/         }
/* 10*/     }
/* 11*/ }

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

直角三角形
図 7.6  直角三角形

この図形は、

        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*/ }

7.2 演習7

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

二等辺三角形(IsoscelesTriangle)
図 7.7  二等辺三角形(IsoscelesTriangle)

この図形は、

        g.drawLine(149, 50, 150, 50);
        g.drawLine(148, 51, 151, 51);
        g.drawLine(147, 52, 152, 52);
        ...
        g.drawLine(50, 149, 249, 149);

と同じことを実行すれば描けます。 この描き方に基づいて、プログラムを作成してください。

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


7.3 レポート課題

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


7.4 参考文献


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

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