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

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

目次
7.1 変数と代入文(4)
7.1.1 変数の値の増減
7.2 繰返し文(1)
7.2.1 while文
7.2.2 for文
7.2.3 繰返し文の使用例(1)
7.3 演習7
7.4 レポート課題
7.5 参考文献
索引
for文   while文   繰返し文   無限ループ   ループ制御変数   ループ文  

7.1 変数と代入文(4)

7.1.1 変数の値の増減

以前、変数に格納されたデータは変更可能であると説明しました。 変数 x にデータ100を格納した後で、101を格納すると、100は上書きされ、 x の値は101になるという話でした。 この仕組みを利用すると、変数の値を増加させることができます。

/*  1*/ class IncreaseTest { // 増加のテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         int x = 100;
/*  4*/         x = x + 1; // 1増加
/*  5*/         System.out.println(x);
/*  6*/     }
/*  7*/ }
asiaa1:~/comp2b k12x1001$ java IncreaseTest
101
asiaa1:~/comp2b k12x1001$

このプログラムは、いったん変数 x にデータ100を格納した後、それを1増加させるものです。 4行目は、変数 x に、変数 x の値に1を足したものを格納する代入文です。 xx + 1 が等しいと言っているわけではありません。 このイメージは次の図のようになります。

変数の値の増加
図 7.1  変数の値の増加

変数の値を1増加させることはよく行われるので、省略形が用意されています。

x = x + 1;

の場合なら、

x++;

と書けます。 変数 y の値を1減少させる、

y = y - 1;

という代入文も、

y--;

と省略できます。

1増加や1減少させるのでなく、いくらか増加やいくらか減少させるための省略形もあります。 以下の表を参照してください。

表 7.1  代入文の省略形
代入文 省略形
変数 = 変数 + ; 変数 += ;
変数 = 変数 - ; 変数 -= ;
変数 = 変数 * ; 変数 *= ;
変数 = 変数 / ; 変数 /= ;
変数 = 変数 % ; 変数 %= ;

以下のプログラムでは、変数 x の値を10増加させて、1増加させています。

/*  1*/ class IncreaseTest2 { // 増加のテスト2
/*  2*/     public static void main (String[] args) {
/*  3*/         int x = 100;
/*  4*/         System.out.println(x);
/*  5*/         x += 10; // 10増加
/*  6*/         System.out.println(x);
/*  7*/         x++; // 1増加
/*  8*/         System.out.println(x);
/*  9*/     }
/* 10*/ }
asiaa1:~/comp2b k12x1001$ java IncreaseTest2
100
110
111
asiaa1:~/comp2b k12x1001$

7.2 繰返し文(1)

7.2.1 while文

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

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

while (条件) {
    ; ...
}

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

while文の流れ
図 7.2  while文の流れ

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

        System.out.println("OK");
        System.out.println("OK");
        System.out.println("OK");
        ...
        System.out.println("OK");

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

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

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

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

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

次はカウントダウン方式です。 これは、これから繰り返す回数を覚えておく方法です。 つまり、変数 i に10を代入しておき、OKと一回出力するごとに i の値を1減らすということを、 i の値が正の数の間繰り返します。

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

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

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

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

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

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

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

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

無限ループ
図 7.3  無限ループ

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

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

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

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

7.2.2 for文

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

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

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

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

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

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

/*  1*/ class TenOKs3 { // OK 10回3
/*  2*/     public static void main (String[] args) {
/*  3*/         int i; // ループ制御変数
/*  4*/         for (i = 0; i < 10; i++) { // 10回繰り返す
/*  5*/             System.out.println("OK");
/*  6*/         }
/*  7*/     }
/*  8*/ }

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

/*  1*/ class TenOKs4 { // OK 10回4
/*  2*/     public static void main (String[] args) {
/*  3*/         int i; // ループ制御変数
/*  4*/         for (i = 10; i > 0; i--) { // 10回繰り返す
/*  5*/             System.out.println("OK");
/*  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 k12x1001$ java ForIntTest
0
1
2
3
4
5
6
7
8
9
asiaa1:~/comp2b k12x1001$
/*  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 k12x1001$ 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 k12x1001$

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

7.2.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 k12x1001$ java Summation100
5050
asiaa1:~/comp2b k12x1001$

次の例では、1×2×…×10の計算を行います。

合計の計算と同じように考え、変数 product の値を1倍し、2倍し、…と繰り返し、10倍すれば計算できます。 したがって、

        product *= 1;
        product *= 2;
        ...
        product *= 10;

と同じことを for 文で表します。 ただし、 product の初期値は1とします。

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

/*  1*/ class Product10 { // 積10
/*  2*/     public static void main (String[] args) {
/*  3*/         int i, product = 1;
/*  4*/         for (i = 1; i <= 10; i++) { // 10回繰り返す
/*  5*/             product *= i;
/*  6*/         }
/*  7*/         System.out.println(product);
/*  8*/     }
/*  9*/ }
asiaa1:~/comp2b k12x1001$ java Product10
3628800
asiaa1:~/comp2b k12x1001$

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

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

/*  1*/ import java.applet.*;
/*  2*/ import java.awt.*;
/*  3*/ 
/*  4*/ public class AppletTest extends Applet {
/*  5*/     public void paint (Graphics g) {
/*  6*/         g.setColor(Color.black);
/*  7*/         g.fillRect(20, 40, 60, 80);
/*  8*/     }
/*  9*/ }
黒い長方形
図 7.5  黒い長方形
この図形の座標
図 7.6  この図形の座標

塗り潰した長方形を描くために、 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.7  直角三角形

この図形は、

        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.3 演習7

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

二等辺三角形(IsoscelesTriangle)
図 7.8  二等辺三角形(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 文を用いて描いてください。 座標が実数になる場合は、 (int) を左に書いて整数化すると、うまくいきます。


7.4 レポート課題

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


7.5 参考文献


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

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