以前、変数に格納されたデータは変更可能であると説明しました。 変数 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*/ }
24102a1:java1 k16x1001$ java IncreaseTest 101 24102a1:java1 k16x1001$
このプログラムは、いったん変数 x にデータ100を格納した後、それを1増加させるものです。 4行目は、変数 x に、変数 x の値に1を足したものを格納する代入文です。 x と x +1が等しいと言っているわけではありません。 このイメージは次の図のようになります。
変数の値を1増加させることはよく行われるので、省略形が用意されています。
x = x + 1;
の場合なら、
x++;
と書けます。 変数 y の値を1減少させる、
y = y - 1;
という代入文も、
y--;
と省略できます。
1増加や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*/ }
24102a1:java1 k16x1001$ java IncreaseTest2 100 110 111 24102a1:java1 k16x1001$
前々回と前回では、条件文を使って、条件が成り立てば何かを実行するというプログラムを書きました。 Javaではこの他に、何かを繰返し実行するというプログラムも書けます。 何かを繰り返す文を、 繰返し文 ( iteration statement )または ループ文 ( loop statement )と呼びます。
何かを繰り返す場合、繰返しの回数が分かっている場合と、分かっていない場合があります。 何回繰返すか分かっている場合は、 for文 ( for statement )を使います。 分かっていない場合は、while文を使います。 (while文は次回説明します。)
以下のプログラムは、10回OKと出力します。
/* 1*/ class ForTest { // for文のテスト /* 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*/ }
24102a1:java1 k16x1001$ java ForTest OK OK OK OK OK OK OK OK OK OK 24102a1:java1 k16x1001$
for文の典型的な形式は以下のとおりです。
int i; ... for (i = 0; i < 回数; i++) { 文; ... }
このfor文で、「 回数 」回「 文 」 ... が実行されます。 なお、for文を使う前に、変数 i を宣言しておきます。 この i は、 ループ変数 ( loop variable )と呼ばれます。
for文の実行の流れは以下のとおりです。
さて、プログラムForTestがなぜ10回繰り返すのか、不思議だと思います。 この謎は、ループ変数を表示してみれば解決します。
/* 1*/ class ForTest2 { // for文のテスト2 /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ for (i = 0; i < 10; i++) { // 0から9まで /* 5*/ System.out.println(i); /* 6*/ } /* 7*/ } /* 8*/ }
24102a1:java1 k16x1001$ java ForTest2 0 1 2 3 4 5 6 7 8 9 24102a1:java1 k16x1001$
ループ変数が0から9まで変化するので、10回だというわけです。 なので、あとはループ変数が変化する仕組みを理解すれば、完全解決します。
for文の一般的な形式は以下のとおりです。
for (初期化; 条件; 更新) { 文; ... }
このfor文で、まず「 初期化 」が実行されます。 そして、「 条件 」が成り立っている間、「 文 」 ... と「 更新 」が繰返し実行されます。
for文の「 初期化 」、「 条件 」、「 更新 」を書き換えれば、別のパターンの繰返しもできます。 例えば、ループ変数を1から10まで変化させたければ、ループ変数は初期化で1, 条件で10以下とします。
/* 1*/ class ForTest3 { // for文のテスト3 /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ for (i = 1; i <= 10; i++) { // 1から10まで /* 5*/ System.out.println(i); /* 6*/ } /* 7*/ } /* 8*/ }
24102a1:java1 k16x1001$ java ForTest3 1 2 3 4 5 6 7 8 9 10 24102a1:java1 k16x1001$
10回繰り返すために、ループ変数を0から9まで変化させるfor文と、1から10まで変化させるfor文を紹介しました。 どちらがよいでしょうか。 1から10のほうが分かりやすいかもしれませんが、コンピュータの世界では「0番目」を積極的に使うので、0から9のほうがよいです。
さて、for文を使って
と出力するには、どうすればよいでしょうか。 普通にやるなら、数式を使います。 つまり、ループ変数を0から9まで変化させ、それを10倍します。
/* 1*/ class LoopVariableTest { // ループ変数のテスト /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ for (i = 0; i < 10; i++) { /* 5*/ System.out.println(10 * i); // ループ変数の10倍 /* 6*/ } /* 7*/ } /* 8*/ }
24102a1:java1 k16x1001$ java LoopVariableTest 0 10 20 30 40 50 60 70 80 90 24102a1:java1 k16x1001$
for文の「
更新
」を書き換えるという方法もあります。
つまり、
i++
で1増加させるのではなく、
i += 10
で10増加させるのです。
/* 1*/ class LoopVariableTest2 { // ループ変数のテスト2 /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ for (i = 0; i < 100; i += 10) { // 10ずつ増加 /* 5*/ System.out.println(i); /* 6*/ } /* 7*/ } /* 8*/ }
24102a1:java1 k16x1001$ java LoopVariableTest2 0 10 20 30 40 50 60 70 80 90 24102a1:java1 k16x1001$
これが実数になると注意が必要です。 for文を使って
と出力する場合、数式を使う(ループ変数を0.1倍する)なら、特に問題は起きません。
/* 1*/ class LoopVariableTest3 { // ループ変数のテスト3 /* 2*/ public static void main (String[] args) { /* 3*/ int i; /* 4*/ for (i = 0; i < 10; i++) { /* 5*/ System.out.println(0.1 * i); // ループ変数の0.1倍 /* 6*/ } /* 7*/ } /* 8*/ }
24102a1:java1 k16x1001$ java LoopVariableTest3 0.0 0.1 0.2 0.30000000000000004 0.4 0.5 0.6000000000000001 0.7000000000000001 0.8 0.9 24102a1:java1 k16x1001$
ところが、for文の「 更新 」を書き換える方法だと、11回繰り返すという間違いを犯します。 プログラムでは、「 更新 」で0.1増加させるために、ループ変数を実数型にしています。 プログラムを実行すると、繰返しのたびに実数の誤差が蓄積していき、11回目で成り立たなくなるはずの「 条件 」が成り立ってしまうのです。
/* 1*/ class LoopVariableTest4 { // ループ変数のテスト4 /* 2*/ public static void main (String[] args) { /* 3*/ double d; // 実数型のループ変数 /* 4*/ for (d = 0.0; d < 1.0; d += 0.1) { // 0.1ずつ増加 /* 5*/ System.out.println(d); // 11回繰り返してしまう /* 6*/ } /* 7*/ } /* 8*/ }
24102a1:java1 k16x1001$ java LoopVariableTest4
0.0
0.1
0.2
0.30000000000000004
0.4
0.5
0.6
0.7
0.7999999999999999
0.8999999999999999
0.9999999999999999 // 余分な出力
24102a1:java1 k16x1001$
この間違いの教訓は、
ループ変数は整数型に限る。実数型にしてはいけない。
ということです。 ループ変数は、慣習的に i , j , k などが使われます。 この i は、整数(integer)の頭文字です。
繰返し文の使用例として、はじめに1+2+...+100の計算を行います。
この問題は、レジの計算をまねることで解決できます。 つまり、それまでの合計を表す変数 sum を用意して、初期値を0とします。 そして、 sum の値を 1増やし、2増やし、…と繰り返し、100増やした時点の sum の値が答になるわけです。 したがって、
sum += 1; // i = 1 sum += 2; // i = 2 ... sum += 100; // i = 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*/ }
24102a1:java1 k16x1001$ java Summation100 5050 24102a1:java1 k16x1001$
次の例では、1×2×…×10の計算を行います。
合計の計算と同じように考え、変数 product の値を1倍し、2倍し、…と繰り返し、10倍すれば計算できます。 したがって、
product *= 1; // i = 1 product *= 2; // i = 2 ... product *= 10; // i = 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*/ }
24102a1:java1 k16x1001$ java Product10 3628800 24102a1:java1 k16x1001$
アプレットの例として、長方形を描きます。
以前、次のような図形を描きました。
/* 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*/ }
<applet code="AppletTest.class" width="300" height="200"> </applet>
24102a1:java1 k16x1001$ javac AppletTest.java 24102a1:java1 k16x1001$ appletviewer AppletTest.html 24102a1:java1 k16x1001$
塗り潰した長方形を描くために、
g.fillRect(
...
);
を使っています。
ここではこれを用いず、自分で長方形を塗り潰すことにします。
長方形は、上から順にすきまなく水平線を引いていけば、塗り潰すことができます。 この場合なら、
g.fillRect(20, 40, 60, 80);
が描く長方形は、下図のような水平線の集まりと考えられます。
1 2 2 2 7 8 9 0 1 2 ... 9 0 39 40 - - - ... - 41 - - - ... - 42 - - - ... - : : : : : 119 - - - ... - 120
したがって、以下と同じことを実行すればよいわけです。
g.drawLine(20, 40, 79, 40); // i = 0 g.drawLine(20, 41, 79, 41); // i = 1 g.drawLine(20, 42, 79, 42); // i = 2 ... g.drawLine(20, 119, 79, 119); // i = 79
プログラムは次の通りです。
/* 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*/ }
この方法を応用すると、色々な図形が描けるようになります。 例えば、次のような直角三角形を考えます。
この三角形の座標は、頂点が(50, 50), 底辺が(50, 149)から(249, 149)までなので、下図のような水平線の集まりと考えられます。
2 2 2 4 5 5 5 5 5 5 ... 4 4 5 9 0 1 2 3 4 5 8 9 0 49 50 - - 51 - - - - 52 - - - - - - : : : : : : : 149 - - - - - - ... - - 150
したがって、以下と同じことを実行すれば描けます。
g.drawLine(50, 50, 51, 50); // i = 0 g.drawLine(50, 51, 53, 51); // i = 1 g.drawLine(50, 52, 55, 52); // i = 2 ... g.drawLine(50, 149, 249, 149); // i = 99
プログラムは次の通りです。
/* 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*/ }
以下の二等辺三角形をfor文を用いて描きます。
この三角形の座標は、頂点が(149, 50), 底辺が(50, 149)から(249, 149)までなので、下図のような水平線の集まりと考えられます。
1 1 1 1 1 1 2 2 4 5 ... 4 4 4 5 5 5 ... 4 5 9 0 7 8 9 0 1 2 9 0 49 50 - - 51 - - - - 52 - - - - - - : : : : : : : 149 - ... - - - - - - ... - 150
したがって、以下と同じことを実行すれば描けます。
g.drawLine(149, 50, 150, 50); // i = 0 g.drawLine(148, 51, 151, 51); // i = 1 g.drawLine(147, 52, 152, 52); // i = 2 ... g.drawLine(50, 149, 249, 149); // i = 99
この描き方に基づいて、プログラムを作成してください。
余力のある人は、平行四辺形、ひし形など、自分で考えた図形をfor文を用いて描いてください。
座標が実数になる場合は、
(int)
を左に書いて整数にキャストすると、うまくいきます。
今日の演習7の答案(Javaプログラム)をメールで提出してください。 差出人は学内のメール・アドレス(学生番号@cis.twcu.ac.jp)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(11月16日)を明記してください。