2.処理の繰り返し

Copyright(C) 29Aug2013 coskx

このページでは「処理の繰り返し」の記述方法を解説する。
ここで修得して欲しい内容は次の通りである。
1.forループの基本的な制御構造がわかりプログラムを追跡できる。
2.forループにおけるカウンタ変数の役割が理解できる。(ループを抜け出したときのカウンタ変数の値もわかる)
3.2重のforループを追跡できる。
4.forループを用いた連続加算プログラムが書ける。
5.whileループを追跡できる。
6.do-whileループを追跡できる
8.ループ中の合計計算,変数順送り操作が追跡できる。
9.ループのプログラムが書ける。
10.定回数二重ル?ププログラムが書ける。
11.内側ループ回数が外側ループ回に応じて変わる二重ループプログラムが書ける



このページは以下の3つの項目で構成されている。
2.1 forループ
2.2 二重forループ
2.3 forループを用いた連続加算

2.4 whileループ
2.5 do-whileループ

2.1 forループ

同じような処理を何度も繰り返す場合には繰り返しの記述が使われる。特にプログラミング時に何回繰り返すのかわかっている場合にはforループで記述されることが多い。

List 2.1.1 forループ

/*For0.java by Kosaka*/

public class For0 {
    public static void main(String[] args) {
        For0 mainprg = new For0();
    }
   
    For0() {
        int i;
        for (i=0; i<5; i++) {
            System.out.printf("A child says, ");
            System.out.printf("\"The king is naked.\"\n");
        }
    }
}

実行結果
A child says, "The king is naked."
A child says, "The king is naked."
A child says, "The king is naked."
A child says, "The king is naked."
A child says, "The king is naked."
補足

for (i=0; i<5 ;i++)
における「5」が5回繰り返せの意味になる。
裸の王様より,「王様は裸だ」

「\"」は「"」を表示する

5」以外の部分の説明はList 2.1.2で行なう。

このプログラムはつぎのプログラムと同等の動作をしている。

    For0() {
        System.out.printf("A child says, ");
        System.out.printf("\"The king is naked.\"\n");
        System.out.printf("A child says, ");
        System.out.printf("\"The king is naked.\"\n");
        System.out.printf("A child says, ");
        System.out.printf("\"The king is naked.\"\n");
        System.out.printf("A child says, ");
        System.out.printf("\"The king is naked.\"\n");
        System.out.printf("A child says, ");
        System.out.printf("\"The king is naked.\"\n");
    }


同じ作業をするなら,for文を使うと,読みやすいプログラムになる。

通常の日本語の言い回しとの変換は次のように考えられる。

日本語での表現の例 Java言語風表現の例 Java言語のキーワードを用いた表現の例
運動場を5周廻りなさい。

次のことを5回行ないなさい{
  運動場を1周廻りなさい。

int i;
for (i=0; i<5; i++) {
  運動場を1周廻りなさい;
}

「王様は裸だ」と5回表示しなさい。

次のことを5回行ないなさい{
  「王様は裸だ」と表示しなさい。

int i;
for (i=0; i<5; i++) {
  
System.out.printf("王様は裸だ\n");
}

練習2.1

「List 2.1.1」の繰り返し回数「5」を他の値にして繰り返し数が変化することを確かめなさい。特に,「0」や「-1」にしたらどうなるか試しなさい。

次の「List 2.1.2」は繰り返し処理中で繰り返しを制御する変数「i」の値を表示させたものである。

List 2.1.2 forループ

/*For1.java by Kosaka*/

public class For1 {
    public static void main(String[] args) {
        For1 mainprg = new For1();
    }
   
    For1() {
        int i;
        for (i=0; i<5; i++) {
            System.out.printf("(%d) ",i);
            System.out.printf("A child says, ");
            System.out.printf("\"The king is naked.\"\n");
        }
    }
}

実行結果
(0) A child says, "The king is naked."
(1) A child says, "The king is naked."
(2) A child says, "The king is naked."
(3) A child says, "The king is naked."
(4) A child says, "The king is naked."
補足

1.「i++」の意味
「i++」とは「i=i+1」と同じ意味であり,「i++」が
実行されるとiの値が1だけ増加する。
「i++」の記述はfor文以外のところでも使われる。

2.繰り返し処理の仕組み
    for (i=0; i<5; i++ ) {
        System.out.printf("(%d) ",i);
        System.out.printf("A child says, ");
        System.out.printf("\"The king is naked.\"\n");
    }

forループ部分の制御の流れは次の順番で行なわれる。

    for ((1);→ (2); ←(4) ) {
        (3);←←    ↑
         : ;      
        (3);→→→→→→
    }

(1)初期化「i=0」を実行する
(2)終端チェック,「i<5」が偽の場合は(6)へ
(3)処理
(4)後処理「i++」でiの値を1だけ増加させる
(5)(2)へ戻る
(6)繰り返し処理終了

3.繰り返し処理のイメージ

4.記述上の注意
  カッコの位置,セミコロンの数に気をつけよう

  カッコ     カッコ
    ↓  セミコロン ↓ 中カッコ始まり
  ↓ ↓  ↓  ↓ ↓
for (i=0 ; i<5 ; i++ )  {  ←セミコロンなし

} ←中カッコ終わり セミコロンなし

for文を導入する考え方(この考え方は,自分でプログラムを書く際に大事)
ループ回数の指定の仕方 どのような指示方法でも困らないようにしよう。

練習2.2

次のプログラムの実行結果を予想しなさい。

List 2.1.3 forループのプログラム

/*For11.java by Kosaka*/

public class For11 {
    public static void main(String[] args) {
        For11 mainprg = new For11();
    }
   
    For11() {
        int i;
        for (i=0; i<=5; i++) {
            System.out.printf("(%d) ",i);
            System.out.printf("A child says, ");
            System.out.printf("\"The king is naked.\"\n");
        }
    }
}

実行結果の予想1 実行結果の予想2 実行結果の予想3
(0) A child says, "The king is naked."
(1) A child says, "The king is naked."
(2) A child says, "The king is naked."
(3) A child says, "The king is naked."
(4) A child says, "The king is naked."
(0) A child says, "The king is naked."
(1) A child says, "The king is naked."
(2) A child says, "The king is naked."
(3) A child says, "The king is naked."
(4) A child says, "The king is naked."
(5) A child says, "The king is naked."
0 A child says, "The king is naked."
1 A child says, "The king is naked."
2 A child says, "The king is naked."
3 A child says, "The king is naked."
4 A child says, "The king is naked."
5 A child says, "The king is naked."

追加説明 「i<=5」は数学では「i≦5」である。「i=<5」の表現は許されない。(不等号,等号の順)
     
「5<=i」は数学では「5≦i」である。「5=<i」の表現は許されない。(不等号,等号の順)

練習2.3

次のプログラムの実行結果を予想しなさい。
List 2.1.4 forループのプログラム

/*For12.java by Kosaka*/

public class For12 {
    public static void main(String[] args) {
        For12 mainprg = new For12();
    }
   
    For12() {
        int i;
        for (i=0; i<=5; i++) {
            System.out.printf("(%d) ",i);
            System.out.printf("A child says, ");
            System.out.printf("\"The king is naked.\"\n");
        }
        System.out.printf("just after the loop i=%d\n",i);
    }
}

実行結果の予想1 実行結果の予想2 実行結果の予想3
(0) A child says, "The king is naked."
(1) A child says, "The king is naked."
(2) A child says, "The king is naked."
(3) A child says, "The king is naked."
(4) A child says, "The king is naked."
just after the loop i=4
(0) A child says, "The king is naked."
(1) A child says, "The king is naked."
(2) A child says, "The king is naked."
(3) A child says, "The king is naked."
(4) A child says, "The king is naked."
just after the loop i=5
(0) A child says, "The king is naked."
(1) A child says, "The king is naked."
(2) A child says, "The king is naked."
(3) A child says, "The king is naked."
(4) A child says, "The king is naked."
just after the loop i=0

 課題2 その1

(1)x,x2,x3の表を1≦x≦100で出力するプログラムを作りなさい。 (p02ex01.java)
変数xをカウンタとする
forを使ったプログラムとし,変数はx,x2(x2の格納用),x3(x3の格納用)の3つだけを用いなさい。x2,x3はxをもとにして作りなさい。
またprintf文はforループの前に1つ,forループの中に1つだけ使いなさい。
forループ中のprintf文は「printf("%3d %5d %7d\n",x,x2,x3);」にすること。

  x  x^2     x^3
  1    1       1
  2    4       8
  3    9      27
  4   16      64
  5   25     125
  :    :       :

(2)x,y(y= 5x),y2,y3,y4の表を1≦x≦100で出力するプログラムを作りなさい。(p02ex02.java)
変数xをカウンタとするforを使ったプログラムとし,変数はx,y,y2(y2の格納用),y3(y3の格納用),y4(y4の格納用)の5つだけを用いなさい。yはxから算出し,y
2,y3,y4はyをもとにして算出しなさい。
またprintf文はforループの前に1つ,forループの中に1つだけ使いなさい。
forループ中のprintf文は「printf("%3d %3d %6d %9d %12d\n",x,y,y2,y3,y4);」にすること。
実行結果をよく見ると変なことに気づくかもしれない。
どうして変になるのか友人と話し合い考察しなさい。
(ヒント int型整数で扱うことのできる値には限りがある)

  x     y      y^2        y^3          y^4
  1     5       25        125          625
  2    10      100       1000        10000
  3    15      225       3375        50625
  4    20      400       8000       160000
  5    25      625      15625       390625
  6    30      900      27000       810000
  7    35     1225      42875      1500625
  :     :        :          :            :


(3)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中でxをもとにして,y1,y2,y3,y4を計算し次の 表を作りなさい。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。forループ中のprintf文は 「printf("%4d %4d %4d %4d %6d\n",x,y1,y2,y3,y4);」にすること。
(p02ex03.java)
ただし,xの範囲は1≦x≦100としなさい。
ヒント y4の計算ではxの値を1,2,3,4・・・と変化させると5*x*xの値はどのように変化するか考えなさい。

  x     y1      y2        y3          y4
  1    100       3         1           5
  2     99       6         5          20
  3     98       9         9          45
  4     97      12        13          80
  5     96      15        17         125
  6     95      18        21         180
  7     94      21        25         245
  :      :       :         :           :

(4)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中でxをもとにして,y1,y2,y3を計算し次の表を作りなさい。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。(p02ex04.java)
ただし,xの範囲は0≦x≦100としなさい。
ヒント xの値を1,2,3,4・・・と変化させると「x%3」と「x%4」の値はどのように変化するか考えなさい。

x    y1    y2    y3
0     0     0     0
1     1     1     1
2     0     2     2
3     1     0     3
4     0     1     0
5     1     2     1
6     0     0     2
7     1     1     3
8     0     2     0
9     1     0     1

(5)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中にy1,y2,y3を作り次の表を作りなさい。y1は2回,y2 は3回,y3は4回同じ値を繰り返している。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。(p02ex05.java)
ただし,xの範囲は0≦x≦100としなさい。
ヒント xの値を1,2,3,4・・・と変化させると「x/3」と「x/4」の値はどのように変化するか考えなさい。

x    y1    y2    y3
0     0     0     0
1     0     0     0
2     1     0     0
3     1     1     0
4     2     1     1
5     2     1     1
6     3     2     1
7     3     2     1
8     4     2     2
9     4     3     2

2.2 二重forループ

「List 2.2.1」はループ中にもう1つループがある例である。

List 2.2.1 「10この「*」を書いて改行する」という作業を5回行うプログラム

/*Multiloop.java by Kosaka*/

public class Multiloop {
    public static void main(String[] args) {
        Multiloop mainprg = new Multiloop();
    }
   
    Multiloop() {
        int i,j;
        for (i=0;i<5;i++) {
            for (j=0;j<10;j++) {
                System.out.printf("*");
            }
            System.out.printf("\n");
        }
    }
}

実行結果
**********
**********
**********
**********
**********
カッコの対応を確認しよう。
各行の先頭がどこから始まっているのか,その規則をみつけなさい。
「字下げ,インデント」の規則

/*Multiloop.java by Kosaka*/

public class Multiloop
{
    public static void main(String[] args) {
        Multiloop mainprg = new Multiloop();
    }
   
    Multiloop() {

        int i,j;
        for (i=0;i<5;i++) {

  for (j=0;j<10;j++) {
      System.out.printf("*");  
  }
  System.out.printf("\n");

        }
   
}
}

二重ループの通常の日本語の言い回しとの変換は次のように考えられる。

日本語での表現の例 Java言語風表現の例 Java言語のキーワードを用いた表現の例
運動場を5周廻りなさい。
その際,運動場を1周廻るたびに
「私は無敵だ」と3回唱えなさい。
(結局「私は無敵だ」は15回唱え
ることになる)

次のことを5回行ないなさい{
  運動場を1周廻りなさい
  次のことを3回行ないなさい{
    「私は無敵だ」と唱えなさい。
  }  

int i,j;
for (i=0; i<5; i++) {
  運動場を1周廻りなさい;
  for (j=0; j<3; j++) {
    「私は無敵だ」と唱えなさい。
  }
}

『「*」を10個書き,改行する』
という作業を5回行ないなさい

次のことを5回行ないなさい{
  次のことを10回行ないなさい{
    「*」を書きなさい
  }
  改行しなさい。

int i,j;
for (i=0; i<5; i++) {
    for (j=0; j<10; j++) {
        System.out.printf("*");
    }
    System.out.printf("\n");
}

練習2.4

 次のプログラムの実行結果を予想しなさい。
 むずかしいと感じた時は自分がコンピュータになったつもりで1行1行実行し,
 各変数がどうなったか,継続条件判断は真か偽かを絶えず,判断しながら読み
 進むこと。

List 2.2.2

/*Multiloop2.java by Kosaka*/

public class Multiloop2 {
    public static void main(String[] args) {
        Multiloop2 mainprg = new Multiloop2();
    }
   
    Multiloop2() {
        int i,j;
        for (i=0;i<5;i++) {
            for (j=0;j<i+1;j++) {
                System.out.printf("*");
            }
            System.out.printf("\n");
        }
    }
}

実行結果の予想1 実行結果の予想2 実行結果の予想3
*
**
***
****
*****
**
***
****
*****
******
**********
**********
**********
**********
**********

練習2.5

次のプログラムの実行結果を予想しなさい。

List 2.2.3

/*Multiloop3.java by Kosaka*/

public class Multiloop3 {
    public static void main(String[] args) {
        Multiloop3 mainprg = new Multiloop3();
    }
   
    Multiloop3() {
        int i,j;
        for (i=0; i<5; i++) {
            for (j=0; j<i; j++) {
                System.out.printf("/");
            }
            for (j=0; j<5-i; j++) {
                System.out.printf("*");
            }
            System.out.printf("\n");
        }
    }
}

実行結果の予想1 実行結果の予想2 実行結果の予想3
/****
//***
///**
////*
/////
*****
/
****
//
***
///
**
////
*
*****
/****
//***
///**
////*

上の2つのプログラムはどのようにして出来たのか考えてみよう。自分でこれらのプログラムを考える時,あるいは課題の作業中に行き詰まった時は ここ を見なさい。 26May2003追加

Javaのプログラミングスタイル

プログラム中に中カッコ始まり「{」があると,字下げ位置が1段深まる。
中カッコ終わり「}」により,字下げ位置が元に戻る。

public class XXXXX {
    public static void main(String[] args) {
       
XXXXX mainprg = new XXXXX();
    }
   
   
XXXXX() {
   
プログラム本体を書く位置は,行頭をこれに揃える
  :
for ( i=0; i<10; i++) {
     :
繰り返し作業を書く位置は,行頭をこれに揃える
4文字分右にずれる
  :
}
繰り返し作業を抜け出したら,元の位置に戻る
  :
  :
    }
}

二重ループの場合

public class XXXXX {
    public static void main(String[] args) {
        XXXXX mainprg = new XXXXX();
    }
  
    XXXXX() {
   プログラム本体を書く位置は,行頭をこれに揃える
  :
for ( i=0; i<10; i++) {
     :
繰り返し作業を書く位置は,行頭をこれに揃える
4文字分右にずれる
  :
for ( j=0; j<10; j++) {
     :
繰り返し作業を書く位置は,行頭をこれに揃える
さらに4文字分右にずれる
  :
}
繰り返し作業を抜け出したら,元の位置に戻る
  :
}
繰り返し作業を抜け出したら,元の位置に戻る
  :
  :
    }
}

 課題2 その2

(6)正整数nをキーボードから入力し,nに応じて「*」で以下の模様を描くプログラムを作成せよ。nは79まで対応しなさい。(p02ex06.java)
検証はn=1,2,3,4,5,79で行ないなさい。

n=1

n=2

n=3

n=4

n=5

*

**
**

***
***
***

****
****
****
****

*****
*****
*****
*****
*****


(7)正整数nを入力し,nに応じて「*」で以下の模様を描くプログラムを作成せよ。nは79まで対応しなさい。(p02ex07.java)
検証はn=1,2,3,4,5,79で行ないなさい。  ヒント

n=1

n=2

n=3

n=4

n=5

*

**
*

***
**
*

****
***
**
*

*****
****
***
**
*


(8)2つの正整数rowとcolumnをキーボードから読み込み,「*」を用いて縦row個,横column個の長方形を描くプログラムを作りなさい。(p02ex08.java)
検証は以下の2例を行ないなさい。

<<実行例1>>
row = 3
column= 5
*****
*****
*****

<<実行例2>>
row = 6
column= 7
*******
*******
*******
*******
*******
*******

(9)奇数(正整数で2で割ったあまりが1のもの)nを入力し,nに応じて「*」「-」で以下の模様を描くプログラムを作りなさい。
nは79まで対応しなさい。(p02ex09.java)
検証はn=1,3,5,7,9,79で行ないなさい。 ヒント

n=1

n=3

n=5

n=7

n=9

*

-*-
***

--*--
-***-
*****

---*---
--***--
-*****-
*******

----*----
---***---
--*****--
-*******-
*********

(10)奇数(正整数で2で割ったあまりが1のもの)nを入力し,nに応じて「*」「-」で以下の模様を描くプログラムを作りなさい。nは79まで対応しなさい。 (p02ex10.java)
検証はn=1,3,5,7,9,79で行ないなさい。

n=1

n=3

n=5

n=7

n=9

*

-*-
***
-*-

--*--
-***-
*****

-***-
--*--

---*---
--***--
-*****-
*******

-*****-
--***--
---*---

----*----
---***---
--*****--
-*******-
*********

-*******-
--*****--
---***---
----*----

(11)九九の表を作りなさい。適当に空白を入れて乱れがないようにして見やすくしなさい。(p02ex11.java)
   1  2  3  4 ..
1  1  2  3  4 ..
2  2  4  6  8 ..
3  3  6  9 12 ..
4  4  8 12 16 ..
:  :  :  :  :

(12)英国には12進数の影響で九・九ではなく十二・十二までの掛算表がある。これを作りなさい。適当に空白を入れて乱れがないようにして見やすくしなさい。(p02ex12.java)

 

2.3 forループを用いた連続加算


「List 2.3.1」は1+2+3+...+100と12+22+32+...+1002を求める計算である。

List 2.3.1

/*1から100までの単純和と1から100までの平方和*/
/*Forsum.java by Kosaka*/

public class Forsum {
    public static void main(String[] args) {
        Forsum mainprg = new Forsum();
    }
   
    Forsum() {
        int i,sum,sum2;
        sum=0;  /*単純和*/
        sum2=0; /*平方和*/
        for (i=1;i<=100;i++) {
            sum=sum+i;
            sum2=sum2+i*i;
            System.out.printf("i,sum,sum2=%d %d %d\n",i,sum,sum2);
        }
        System.out.printf("1から100までの単純和と平方和=%d %d\n",sum,sum2);
    }
}

実行結果

i,sum,sum2=1 1 1
i,sum,sum2=2 3 5
i,sum,sum2=3 6 14
i,sum,sum2=4 10 30
  :
途中省略
  :
i,sum,sum2=97 4753 308945
i,sum,sum2=98 4851 318549
i,sum,sum2=99 4950 328350
i,sum,sum2=100 5050 338350
1から100までの単純和と平方和=5050 338350

変数の初期化を忘れた失敗の例 27June2003追加

forループに関する補足(疑問点と誤りの例) 14May2003追加

 課題2 その3

(13)キーボードから10この正整数値を読み込み,合計値を表示するプログラムを作りなさい。ただ し,キーボードから読み込んだ値はint型変数xにしまわれるものとし,変数はこのxと回数を数えるint型変数countと合計値をしまうint型変数 sumのみを用いることとする。(p02ex13.java)
1,2,3,4,.. ..8,9,10を入力してプログラム動作を検証しなさい。
また,11,12,13,14,.. ..18,19,20を入力してプログラム動作を検証しなさい。
レポートの実行結果には2つの例を示しなさい。

  ヒント

(14)キーボードから10この正整数値を読み込み,合計値と平均値(小数第1位まで)を表示するプログラムを作りなさい。(p02ex14.java)
1,2,3,4,.. ..,8,9,10を入力して5.5になるかどうか検証しなさい。
また11,12,13,14,.. ..,18,19,20を入力して15.5になるかどうか検証しなさい。

レポートの実行結果には2つの例を示しなさい。

  ヒント

 

2.4 whileループ

キーボードから読み込んだ正整数値を2で繰り返し割ることを考える。割り切れる回数を求めるプログラムを考えよう。
例えば正整数値12は(12→6→3)2回,2で割り切ることが出来る。16は(16→8→4→2→1)4回,9は0回である。
2で割る動作は繰り返されるが,何回繰り返されるかは,プログラミング時には決めることが出来ないため,for文では
書くことができない。
ある条件が満たされている間,特定の処理を繰り返すという表現は,while文になる。

人間なら,2通りのやり方があるだろう。
(1)1つは2での割り算を紙に書いていき,割り切れなくなったときに,それまで何回割り算を行なったかを数えればよい。
(2)もう1つは割り算を行ないながら,現在何回目の割り算かを数え,覚えておく。割り切れなくなった時,覚えていた回数が答えである。

コンピュータでこの作業を行なうときは,(2)のやり方が適している。人間が割り算回数を覚えておくことに対応させて,現在何回目の割り算かを覚えておく変数を導入し,最初に0を与え,割り算が可能だった時に1を加えればよい。
回数を数える用途に使われる変数はカウンタと呼ばれ,プログラミングでは大変重要な役割を果たす。

割り切れたかどうかは,割り算のあまりを出す演算を用いて,あまりが0であるかどうかを確かめるとよい。

   むずかしいと感じた時は自分がコンピュータになったつもりで1行1行実行し,
   各変数がどうなったか,継続条件判断は真か偽かを絶えず,判断しながら読み
   進むこと。

List 2.4.1 numberは2で割ることが何回出来るか
  薄ピンクのところは整数をキーボードから入力するためのおまじない

/*numberは2で割ることが何回出来るか*/
/*While0.java by Kosaka*/

import java.util.*;  // StringTokenizer
import java.io.*;    // BufferedReader

public class While0 {
    public static void main(String[] args) {
        While0 mainprg = new While0();
    }
   
    While0() {
        int number,n,counter;
        number=getInt("正整数を入力してください ");
        n=number;
        counter=0; /*2で割り切れた回数を覚えている変数を0にする*/
        System.out.printf("number=%d counter=%d\n",number,counter);
        while (n%2==0) { /*2で割り切れたら中に入る*/
            n=n/2; /*割り切れることがわかっているので,実際に割り算する*/
            counter++; /*割り切れたので回数を覚えている変数の値を1増やす*/
            System.out.printf("n=%d counter=%d\n",n,counter);
        }
        System.out.printf("%dは%d回,2で割ることが出来ました\n",number,counter);
    }

    private int getInt(String prompt){
        BufferedReader bffrd = new BufferedReader(new InputStreamReader(System.in));
        int ret=0;
        System.out.print(prompt);
        try {
            ret = Integer.valueOf(bffrd.readLine()).intValue();
        }
        catch(IOException e) {
            System.out.println("IO Error");
            System.exit(1);
        }
        return ret;
    }
}

実行結果 (実行例を3つ示している)

正整数を入力してください 120
number=120 counter=0
n=60 counter=1
n=30 counter=2
n=15 counter=3
120は3回,2で割ることが出来ました

正整数を入力してください 1024
number=1024 counter=0
n=512 counter=1
n=256 counter=2
n=128 counter=3
n=64 counter=4
n=32 counter=5
n=16 counter=6
n=8 counter=7
n=4 counter=8
n=2 counter=9
n=1 counter=10
1024は10回,2で割ることが出来ました

正整数を入力してください 1237
number=1237 counter=0
1237は0回,2で割ることが出来ました

説明

1.「(n%2==0)」はnを2で割ったあまりが0だったらの意味
  「=」は「右辺の計算結果を左辺の変数に代入せよ」の意味なので
  「左辺=右辺」という条件を表す時は「左辺==右辺」と書く。
  
条件の記述について

2.繰り返し処理の仕組み
    while (n%2==0) {
       
n=n/2;
        counter++;
        System.out.printf("n=%d counter=%d\n",n,counter);

    }

  この部分の制御の流れは次の順番で行なわれる。
    while  (    (1)    ) {
        (2);←← 
         : ;   

        (2);
→→→→
    }

(1)終端チェック,「n%2==0」が偽の場合は(4)へ進む
(2)処理
(3)(1)へ戻る
(4)繰り返し処理終了



3.カウンタ変数
  プログラミングでは何かの回数を数えることが必要になる場合が多い。
  そのような場合にはカウンタ変数と呼ばれる変数を用いる。このプログラム中では
  counterという変数である。この変数はnを2で割ることが出来た場合に1増加する。

************* 余談1 *************
人間が何かを数える時には頭の中にカウンタ変数を無意識に作る。
「時そば」とい落語があるが,そば屋の主人がおつりを1,2,3と勘定している
時に客から「今なんどきだい?」と時刻を聞かれ,時刻を答えた時に勘定を間違え
るという噺である。人間の頭の中にあるカウンタ変数は外乱によって変調をきたす
が,コンピュータ内のカウンタ変数はカウントアップする条件を間違えなければ,
正常に働くはずである。

************* 余談2 *************
お酒の飲み方とwhileループ
日本語での表現の例 Java言語風表現の例 Java言語のキーワードを用いた表現の例

次の1杯を飲む時は限界に
達しているかどうか良く考
えよう

まだ酔っていないと思ったら{
  次の1杯を飲む
  判断するところに戻る

while (まだ酔っていないと思う) {
  次の1杯を飲む;
}

このプログラムはどのようにして出来たのか考えてみよう。自分でこのプログラムを考える時,あるいは課題の作業中に行き詰まった時は ここ を見なさい。 26May2003追加

練習2.6

 次のプログラムの実行結果を予想しなさい。
 むずかしいと感じた時は自分がコンピュータになったつもりで1行1行実行し,
 各変数がどうなったか,継続条件判断は真か偽かを絶えず,判断しながら読み
 進むこと。

List 2.4.2

/*1000以下のフィボナッチ数列*/
/*1,1,2,3,5,8,13,21....の数列*/
/*1+1=2, 1+2=3, 2+3=5, 3+5=8, 5+8=13, 8+13=21, ...*/
/*Fibonacci.java by Kosaka*/

public class Fibonacci {
    public static void main(String[] args) {
        Fibonacci mainprg = new Fibonacci();
    }
   
    Fibonacci() {
        int fa=1,fb=1,fc;
        int counter=3;
        fc=fa+fb;
        System.out.printf("1:%d\n2:%d\n",fa,fb);
        while (fc<=1000) {
            System.out.printf("%d:%d\n",counter,fc);
            counter++;
            fa=fb;
            fb=fc;
            fc=fa+fc;
        }
    }
}

実行結果の予想1 実行結果の予想2 実行結果の予想3
1:1
2:1
3:2
4:3
5:5
6:8
7:13
8:21
9:34
10:55
11:89
12:144
13:233
14:377
15:610
16:987

1:1
2:1
3:2
4:2
5:2
6:8
7:13
8:21
9:34
10:55
11:89
12:144
13:233
 :
途中省略
 :
1000:221547

1:1
2:1
3:2
4:3
5:5
6:8
7:13
8:21
9:34
10:55
11:89
12:144
13:233
14:377
15:610
16:987
17:1597

フィボナッチ数列とは次のような数列のことです

第1項と第2項の値が1で,第3項以降の項がそれ以前の2つの項の和である数列

a1 = 1, a2 = 1, an = an-1 + an-2

 

2.5 do-whileループ

「2.4.1」の例で,「正整数を入力してください」としているが,人間が誤って負の整数を入力しても,再入力を強制するような仕組みを考えよう。人間は再入力を強制されても,何回も負の整数を入力するかもしれないので,粘り強く再入力を強制する仕組みにしよう。
 このように,何か作業があって,その結果もう一回繰り返すかどうか判断する形式の繰り返し構造ではdo-while文を使う。

List 2.5.1

/*numberは何回2で割ることが出来るか*/
/*Dowhile0.java by Kosaka*/

import java.util.*;  // StringTokenizer
import java.io.*;    // BufferedReader

public class Dowhile0 {
    public static void main(String[] args) {
        Dowhile0 mainprg = new Dowhile0();
    }
   
    Dowhile0() {
        int number,n,counter;
        do {
            number=getInt("正整数を入力してください ");
        } while (number<=0);
        n=number;
        counter=0; /*2で割り切れた回数を覚えている変数を0にする*/
        System.out.printf("number=%d counter=%d\n",number,counter);
        while (n%2==0) { /*2で割り切れたら中に入る*/
            n=n/2; /*割り切れることがわかっているので,実際に割り算する*/
            counter++; /*割り切れたので回数を覚えている変数の値を1増やす*/
            System.out.printf("n=%d counter=%d\n",n,counter);
        }
        System.out.printf("%dは%d回,2で割ることが出来ました\n",number,counter);
    }

    private int getInt(String prompt){
        BufferedReader bffrd = new BufferedReader(new InputStreamReader(System.in));
        int ret=0;
        System.out.print(prompt);
        try {
            ret = Integer.valueOf(bffrd.readLine()).intValue();
        }
        catch(IOException e) {
            System.out.println("IO Error");
            System.exit(1);
        }
        return ret;
    }
}

実行結果

正整数を入力してください -120
正整数を入力してください -120
正整数を入力してください 120
number=120 counter=0
n=60 counter=1
n=30 counter=2
n=15 counter=3
120は3回,2で割ることが出来ました

説明

繰り返し処理の仕組み
    do {
       
number=getInt("正整数を入力してください ");
    } while (number<=0);

この部分の制御の流れは次の順番で行なわれる。
    do {
        (1);←←

         : ;   ↑
        (1);
↓  ↑
    } while (   (2)  );

(1)処理
(2)終端チェック,「number<=0」が偽の場合は(4)へ進む
(3)(1)へ戻る
(4)繰り返し処理終了

注意 while(?)の直後に「;」が必要
    do {
       
number=getInt("正整数を入力してください ");
    } while (number<=0);

************* 余談 *************
お酒の飲み方とdo-whileループ
日本語での表現の例 Java言語風表現の例 Java言語のキーワードを用いた表現の例

まず1杯飲んで次の1杯を飲
む時は限界に達しているか
どうか良く考てから飲もう


  1杯を飲む
}まだ酔っていないと思ったら先頭に戻る

 do {
  次の1杯を飲む;
} while (まだ酔っていないと思う);

do-whileでお酒を飲むと,すでに出来上がっている人の場合は泥酔してしまいます。
お酒を飲む時はwhileループで飲みましょう。(成人に達してからです。)

練習2.7

次のプログラムの実行結果を予想しなさい。

List 2.5.2

/*Dowhile1.java by Kosaka*/

public class Dowhile1 {
    public static void main(String[] args) {
        Dowhile1 mainprg = new Dowhile1();
    }
   
    Dowhile1() {
        int x,y;
        x=1;
        y=0;
        do {
            y=x+10;
            x++;
        } while (y<15);
        System.out.printf("x=%d y=%d\n",x,y);
    }
}

実行結果の予想1 実行結果の予想2 実行結果の予想3
x=6 y=15 x=5 y=14 x=15 y=24

2.6 「処理の繰り返し」のまとめ

各ループの記述の特徴は次のとおりである。

ループの記述の種類 ループ回数 1回目の処理
forループ プログラミングあるいはループ起動の時点で既知 1度も処理を行なわないこともある
whileループ プログラミングあるいはループ起動の時点では未定 1度も処理を行なわないこともある
do-whileループ プログラミングあるいはループ起動の時点では未定 少なくとも1回は処理を行なう


特に,whileループとdo-whileループの違いを次の2つの例で示す。

例 List 2.5.1 より

do {
    number=getInt("正整数を入力してください ");
} while (number<=0);
この例では,必ず1回は処理を行なうはずなのでdo-whileループが使われる


例 List 2.4.1 より

while (n%2==0) {
    n=n/2;
    counter++;
   
System.out.printf("n=%d counter=%d\n",n,counter);
}
この例では,1回も処理が行なわれない可能性があるのでwhileループが使われる
(対象が奇数だと1度も2で割リきることが出来ない)


繰返し処理記述の時の考え方 ここを読んでください

2.7 追加説明

ループに関する内容で説明してなかった内容を追加説明する

 

内容

1.forループ

次のようなfor文がある
for (i=0,sum=0,sum2=0; i<100; i++)
i=0,sum=0,sum2=0 この3つがループに入る前の事前処理である。
間はカンマで区切る。

for (i=0,j=100,k=0; i<100; i++,j--,k=k+10)
i=0,j=100,k=0 この3つがループに入る前の事前処理である。
i++,j--,k=k+10 
この3つが終端処理前の処理である。
間はカンマで区切る。

2.forループとwhileループ

次の2つのループは同じ意味となるが,この場合は繰り返し回数指定ループなので
forループを推奨する。

for (i=0; i<10; i++) {
    :
}

i=0;
while (i<10) {
    :
    i++;
}

3.whileループとforループ

次の2つのループは同じ意味となるがこの場合は条件ループなので
whileループを推奨する。

while (a<b) {
    :
}

for ( ; a<b; ) {
    :
}

4.do-whileループとwhileループ

次の2つのループは同じ意味となるがこの場合は後ろ判断ループなので
do-whileループを推奨する。

do {
    処理A
} while (a<b);


処理A
while (a<b) {
    処理A
}

5.無限ループ

条件記述の部分で,Java言語の文法では,
 falseは 偽(条件が成り立っていない)
 trueは 真(条件が成り立っている)
を意味することになっている。そこで無限ループは次のように記述できる。
(無限ループは制御プログラムでよく使われる。制御は電源が切れるまで繰り返しをとめるわけには行かない)

while(true) {
    処理
    処理
    処理
}

次の例も無限ループになるが,while利用の記述の方が明確と思われる

for(; true; ) {
    処理
    処理
    処理
    処理
}

6.ループと緊急脱出

嫌われ者の「break」による脱出

繰り返し処理中に,ある条件が生じたら緊急に繰り返しから抜け出さなければならないことがある。
このような場合には

while(true) {
    処理A;
    if (脱出条件) break;
    処理B:
}

のように書くが,これは

処理A;
while(継続条件) {
    処理B;
    処理A;
}

と同じである。繰り返し処理の出口はループの先頭か最後であるスタイルが読みやすい。

前者の表現の場合,コメントをつけて次のように目立たせるのがよい。
この例ではプログラムが短いので,ご利益がわからないが,長いプログラムでは,どこで抜け出しているのかわかりにくいので,必要性がわかるであろう。

while(true) { /*★ループ脱出は途中に1か所★*/
    処理A;
    /*★ループ脱出★*/ if (脱出条件) break;
    処理B:
}

なお

while(true) {
    if (脱出条件) break;
    処理B:
}

ならば,ループに入った直後の脱出なので

while(継続条件) {
    処理B;
}

と書くべきであるし,また

while(true) {
    処理A;
    if (脱出条件) break;
}

ならば,ループの終端における脱出なので

do {
    処理A;
} while (継続条件);

と書くべきである。


 課題2

(1)x,x2,x3の表を1≦x≦100で出力するプログラムを作りなさい。 (p02ex01.java) (再掲)
変数xをカウンタとする
forを使ったプログラムとし,変数はx,x2(x2の格納用),x3(x3の格納用)の3つだけを用いなさい。x2,x3はxをもとにして作りなさい。
またprintf文はforループの前に1つ,forループの中に1つだけ使いなさい。
forループ中のprintf文は「printf("%3d %5d %7d\n",x,x2,x3);」にすること。

  x  x^2     x^3
  1    1       1
  2    4       8
  3    9      27
  4   16      64
  5   25     125
  :    :       :

(2)x,y(y= 5x),y2,y3,y4の表を1≦x≦100で出力するプログラムを作りなさい。(p02ex02.java) (再掲)
変数xをカウンタとするforを使ったプログラムとし,変数はx,y,y2(y2の格納用),y3(y3の格納用),y4(y4の格納用)の5つだけを用いなさい。yはxから算出し,y
2,y3,y4はyをもとにして算出しなさい。
またprintf文はforループの前に1つ,forループの中に1つだけ使いなさい。
forループ中のprintf文は「printf("%3d %3d %6d %9d %12d\n",x,y,y2,y3,y4);」にすること。
実行結果をよく見ると変なことに気づくかもしれない。
どうして変になるのか友人と話し合い考察しなさい。
(ヒント int型整数で扱うことのできる値には限りがある)

  x     y      y^2        y^3          y^4
  1     5       25        125          625
  2    10      100       1000        10000
  3    15      225       3375        50625
  4    20      400       8000       160000
  5    25      625      15625       390625
  6    30      900      27000       810000
  7    35     1225      42875      1500625
  :     :        :          :            :


(3)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中でxをも とにして,y1,y2,y3,y4を計算し次の表を作りなさい。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。for ループ中のprintf文は「printf("%4d %4d %4d %4d %6d\n",x,y1,y2,y3,y4);」にすること。
(p02ex03.java) (再掲)
ただし,xの範囲は1≦x≦100としなさい。
ヒント y5の計算ではxの値を1,2,3,4・・・と変化させると15*x*xの値はどのように変化するか考えなさい。

  x     y1      y2        y3          y4
  1    100       3         1           5
  2     99       6         5          20
  3     98       9         9          45
  4     97      12        13          80
  5     96      15        17         125
  6     95      18        21         180
  7     94      21        25         245
  :      :       :         :           :

(4)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中でxをもとにして,y1,y2,y3を計算し次の表を作りなさい。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。(p02ex04.java) (再掲)
ただし,xの範囲は0≦x≦100としなさい。
ヒント xの値を1,2,3,4・・・と変化させると「x%3」と「x%4」の値はどのように変化するか考えなさい。

x    y1    y2    y3
0     0     0     0
1     1     1     1
2     0     2     2
3     1     0     3
4     0     1     0
5     1     2     1
6     0     0     2
7     1     1     3
8     0     2     0
9     1     0     1

(5)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中に y1,y2,y3を作り次の表を作りなさい。y1は2回,y2は3回,y3は4回同じ値を繰り返している。printf文はforループの前に1 つ,forループの中に1つだけ使いなさい。(p02ex05.java) (再掲)
ただし,xの範囲は0≦x≦100としなさい。
ヒント xの値を1,2,3,4・・・と変化させると「x/3」と「x/4」の値はどのように変化するか考えなさい。

x    y1    y2    y3
0     0     0     0
1     0     0     0
2     1     0     0
3     1     1     0
4     2     1     1
5     2     1     1
6     3     2     1
7     3     2     1
8     4     2     2
9     4     3     2

 

(6)正整数nをキーボードから入力し,nに応じて「*」で以下の模様を描くプログラムを作成せよ。nは79まで対応しなさい。(p02ex06.java)(再掲)
検証はn=1,2,3,4,5,79で行ないなさい。

n=1

n=2

n=3

n=4

n=5

*

**
**

***
***
***

****
****
****
****

*****
*****
*****
*****
*****


(7)正整数nを入力し,nに応じて「*」で以下の模様を描くプログラムを作成せよ。nは79まで対応しなさい。(p02ex07.java)(再掲)
検証はn=1,2,3,4,5,79で行ないなさい。 ヒント

n=1

n=2

n=3

n=4

n=5

*

**
*

***
**
*

****
***
**
*

*****
****
***
**
*


(8)2つの正整数rowとcolumnをキーボードから読み込み,「*」を用いて縦row個,横column個の長方形を描くプログラムを作りなさい。(p02ex08.java)(再掲)
検証は以下の2例を行ないなさい。

<<実行例1>>
row = 3
column = 5
*****
*****
*****

<<実行例2>>
row = 6
column = 7
*******
*******
*******
*******
*******
*******

(9)奇数(正整数で2で割ったあまりが1のもの)nを入力し,nに応じて「*」「-」で以下の模様を描くプログラムを作りなさい。
nは79まで対応しなさい。(p02ex09.java)(再掲)
検証はn=1,3,5,7,9,79で行ないなさい。 ヒント

n=1

n=3

n=5

n=7

n=9

*

-*-
***

--*--
-***-
*****

---*---
--***--
-*****-
*******

----*----
---***---
--*****--
-*******-
*********

(10)奇数(正整数で2で割ったあまりが1のもの)nを入力し,nに応じて「*」「-」で以下の模様を描くプログラムを作りなさい。nは79まで対応しなさい。 (p02ex10.java)(再掲)
検証はn=1,3,5,7,9,79で行ないなさい

n=1

n=3

n=5

n=7

n=9

*

-*-
***
-*-

--*--
-***-
*****

-***-
--*--

---*---
--***--
-*****-
*******

-*****-
--***--
---*---

----*----
---***---
--*****--
-*******-
*********

-*******-
--*****--
---***---
----*----

(11)九九の表を作りなさい。適当に空白を入れて乱れがないようにして見やすくしなさい。(p02ex11.java) (再掲)
   1  2  3  4 ..
1  1  2  3  4 ..
2  2  4  6  8 ..
3  3  6  9 12 ..
4  4  8 12 16 ..
:  :  :  :  :

(12)英国には12進数の影響で九・九ではなく十二・十二までの掛算表がある。これを作りなさい。適当に空白を入れて乱れがないようにして見やすくしなさい。(p02ex12.java) (再掲)

(13)キーボードから10この正整数値を読み込み,合計値を表示するプログラムを作りなさい。ただ し,キーボードから読み込んだ値はint型変数xにしまわれるものとし,変数はこのxと回数を数えるint型変数countと合計値をしまうint型変数 sumのみを用いることとする。(p02ex13.java)
1,2,3,4,.. ..8,9,10を入力してプログラム動作を検証しなさい。
また,11,12,13,14,.. ..18,19,20を入力してプログラム動作を検証しなさい。
レポートの実行結果には2つの例を示しなさい。

  ヒント

(14)キーボードから10この正整数値を読み込み,合計値と平均値(小数第1位まで)を表示するプログラムを作りなさい。(p02ex14.java)
1,2,3,4,.. ..,8,9,10を入力して5.5になるかどうか検証しなさい。
また,11,12,13,14,.. ..,18,19,20を入力して15.5になるかどうか検証しなさい。
レポートの実行結果には2つの例を示しなさい。

  ヒント

(15)キーボードから複数個の正整数値を読み込み,合計値と平均値 (小数第1位まで)を表示するプログラムを作りなさい。ただし入力数値の個数はプログラミング時には決定していない。負整数が入力されたら入力値はもうな くなったと判断することとし,負の数は計算には使用しないこととする。またデータは少なくとも1つは入力されるものとする。(p02ex15.java)
検証は1から10までの数字すべてを与え,合計値55,平均値5.5が表示されることを確かめること。
(「1,2,3,4,5,6,7,8,9,10,-1」(-1はデータ終わりの合図)を入力して確かめなさい。)
また,1から5までの数字すべてを与え,合計値15,平均値3が表示されることを確かめること。
(「1,2,3,4,5,-1」(-1はデータ終わりの合図)を入力して確かめなさい。)
レポートの実行結果には上記2つの例を示しなさい。

  ヒント

(16)正整数を入力して,その正整数が何桁か求めるプログラムを作りなさい。ただし正整数は10億以下とする。また,プログラム1回の起動でこの 作業を何回も繰返し行なえるようにし,負の値が入力されたら直ちにプログラムが止まるようにしなさい。負の値入力後は直ちに繰り返し作業から抜け出すこと (p02ex16.java)
(ヒント10で何回割れるか考える)
検証は,1桁の数,2桁の数,..,8桁の数で行ないなさい。

 ヒント

(17)2つの正整数の最大公約数を求める算法(アルゴリズム)として有名なユークリッドの互除法により,最大公約数を求めるプログラムを作りなさい。プログラムでは2つの正整数はキーボードから入力するものとする。(p02ex17.java)
検証は以下の例についてすべて行ないなさい。

ユークリッドの互除法は次のアルゴリズムとなる。
例えば2つの正整数が72と42の場合
72%42=30 → 42%30=12 → 30%12=612%6=0.....0になった時の割る数6が最大公約数である。
最初の置き方が逆でもOKである。すなわち
42%72=4272%42=3042%30=1230%12=612%6=0.....0になった時の割る数6が最大公約数である。
例えば2つの正整数が256と72の場合
256%72=4072%40=3240%32=832%8=0....0になった時の割る数8が最大公約数である。
最初の置き方が逆でもOKである。すなわち
72%256=72256%72=4072%40=3240%32=832%8=0....0になった時の割る数8が最大公約数である。
一般に2つの正整数がaとbの場合
a%b=cb%c=dc%d=e → ・・・ → x%y=0になった時の割る数yが最大公約数である。
このアルゴリズムの表現方法はフィボナッチ数列に似ており,不要になった変数の使いまわしをする。

ヒント p,qに元の2数を入れて,このループに入り,このループから抜け出したとき,qが最大公約数となる

r=p%q;
printf("p%%q=r  %d%%%d=%d\n",p,q,r); /*途中経過を表示するため*/
while (r!=0) {
    p=q;
    q=r;
    r=p%q;
    printf("p%%q=r  %d%%%d=%d\n",p,q,r); /*途中経過を表示するため*/
}