情報学部 菅沼ホーム 全体目次 演習解答例 付録 索引

第5章 制御文

  1. 5.1 分岐
    1. 5.1.1 if 文
      1. (プログラム例 5.1 ) 円周と面積の計算
      2. (プログラム例 5.2 ) 坪・m2 間の単位変換
      3. (プログラム例 5.3 ) 3 つのデータの最大値と最小値
      4. (プログラム例 5.4 ) データの比較
    2. 5.1.2 switch 文
      1. (プログラム例 5.5 ) データの比較( switch 文)
    3. 5.1.3 goto 文
      1. (プログラム例 5.6 ) 入力の繰り返し( goto )
  2. 5.2 繰り返し
    1. 5.2.1 繰り返し文
      1. (プログラム例 5.7 ) 平均値の計算
      2. (プログラム例 5.8 ) ファイル入出力
      3. (プログラム例 5.9 ) for 文のネスト
      4. (プログラム例 5.10 ) 入力の繰り返し( do-while )
      5. (プログラム例 5.11 ) 最大値(初期設定)
      6. (プログラム例 5.12 ) for 文,while 文,do while 文の比較
    2. 5.2.2 繰り返しの中断
      1. 5.2.2.1 break 文
        1. (プログラム例 5.13 ) 繰り返しの中断( break )
      2. 5.2.2.2 continue 文
        1. (プログラム例 5.14 ) 繰り返しの中断( continue )
  3. 演習問題5

5.1 分岐

  以上見てきたプログラムは,すべて最初から順番に実行するタイプのものだけでした.しかし,プログラムによっては,必ずしも上から順に実行するだけでなく,その実行順序を変化させたい場合があります.そのような目的のために使用される文を制御文と言います.本章では,主な制御文について説明します.

5.1.1 if 文

  if 文は,そのときの状況により実行の順序を変化させるための文であり,その一般的形式は以下の通りです.
if (論理式) {
	文1(複数の文も可)
}
else {
	文2(複数の文も可)
}
・・・・・・		
  この文の実行は以下のようにして行われます.まず,論理式が評価され,その結果が真であれば,文1が実行され,次に,「・・・」以降に書かれた文が実行されます.この場合は,文2は実行されないことになります.また,偽である場合は,文1は実行されず,文2が実行された後,真の場合と同様,「・・・」以降に書かれた文が実行されます.なお,if 文において,真に対応する部分(文1)は必ず必要ですが,偽に対応する部分( else 以下)は,必ずしも必要ありません.

  また,次の例のように,文1や文2の中にも if 文を書くことができます( if 文のネストと呼びます).同様に,その内部に書かれた if 文の中にも,さらに,if 文を書くことも可能です.
if (論理式1) {
	・・・・・・
	if (論理式2) {
		・・・・・・
	}
	else {
		・・・・・・
	}
	・・・・・・
}
else {
	・・・・・・
}
		
  プログラムを読み易くするため,if 文内に含まれる文は,次の例のように,何列か段を下げて(字下げを行って)書くようにして下さい.字下げは,プログラムの詳細を見なくても,その構造がわかるようにするためのものです.if 文の場合,条件が満足された場合どこからどこまでが実行されるのかが,一目でわかるように行います.例えば,下の例の場合,a と b が等しい場合,2 行目から 7 行目が実行され,また,等しくない場合,10 行目と 11 行目が実行されることが一目でわかります.また,13 行目と 14 行目は,if 文に関係なく常に実行されることも明確になります.

01	if (a == b) {
02		max = y;
03		min = z;
04		if (min < 0.0) {
05			min = 0.0;
06			a   = b;
07		}
08	}
09	else {
10		max = s;
11		min = g;
12	}
13	x = 9;
14	y = 10;
		

(プログラム例 5.1 ) 円周と面積の計算 円周と面積の計算 ( A ~ F の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  このプログラムでは,半径を入力した後,その値の妥当性(正の値であること)をチェックし( 22 行目),正の場合は目的の計算を行い,それ以外の場合は何も行わず終了しています.従って,else に対応する部分がありません.プログラムを使う人と作る人は常に同じであるとは限りません.場合によっては,プログラム作成者が予期しないデータが入力され,とんでもない結果が生じる場合がよく起こります.従って,できる限り,入力データ値等の妥当性をチェックすることをすすめます.

(プログラム)
/******************************/
/* 円周と面積の計算           */
/*      coded by Y.Suganuma   */
/******************************/
#include <stdio.h>

int main()
{
/*
     πの値
*/
	double pi = 3.141593;
/*
     半径の入力
*/
	double r;
	printf("円の半径は? ");
	scanf("%lf", &r);
/*
     計算と出力
*/
	if (r > 0.0) {
		double enshu = 2.0 * pi * r;
		double men   = pi * r * r;
		printf("円周=%f   面積=%f\n", enshu, men);
	}

	return 0;
}
			

  if ブロックが出てきましたので,上に示したプログラムに基づき,以前述べた型宣言文の位置についてもう一度述べておきます.変数 r に対する型宣言は 18 行目より前であれば,どこでも構いません.その有効範囲は,プログラムの終わりまでになります.変数 pi を使用しているのは,23 行目ですので,それより前であればどこでも構いません.22 行目より前で宣言すれば,その有効範囲はプログラムの終わりまでになりますが,22 行目の後ろで宣言すれば,変数 enshu や men と同じく,その有効範囲は if ブロックの内部( 25 行目まで)になりますので,27 行目以降において,変数 pi,enshu,men を参照すると未定義であるというエラーになってしまいます.

(プログラム例 5.2 ) 坪・m2 間の単位変換 ( A ~ C の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次に,面積に関するデータの単位変換をするプログラムについて考えてみます.つまり,与えられたデータが坪単位なら m2 に,m2 単位なら坪に変換するプログラムです.単にデータを与えただけでは,そのデータが坪単位か m2 単位かがわかりませんので,このプログラムでは変数 sw に値を入力することによって識別しています.変数 sw の値が 0 ならば m2 から坪に,1 ならば(実行上は,0 以外であれば)坪から m2 に変換します.

(プログラム)
/****************************/
/* 坪と㎡の間の単位変換     */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>

int main()
{
/*
		  データの入力
*/
	int sw;
	printf("変換方向(0:坪→㎡,1:㎡→坪)は? ");
	scanf("%d", &sw);
	double x;
	printf("変換するデータは? ");
	scanf("%lf", &x);
/*
		  変換と出力
*/
	if (sw == 0) {             /* 坪から㎡ */
		double y = 3.3 * x;
		printf("   xは %f ㎡\n", y);
	}
	else {				   /* ㎡から坪 */
		double y = x / 3.3;
		printf("   xは %f 坪\n", y);
	}

	return 0;
}
			

(プログラム例 5.3 ) 3 つのデータの最大値と最小値 ( A ~ J ,及び,K ~ N の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次のプログラムでは,与えられた 3 つのデータの最大値と最小値を出力しています.この例により,if 文のネスト構造,及び,字下げの方法を理解して下さい.また,このプログラムの 25 ~ 28 行目等に示すように,if の後や else の後に続く文が 1 文だけである場合は,それらを囲む「{」と「}」は必要ありません(もちろん,付けても構いません).ただし,次のプログラム
if (論理式1) {
	if (論理式2)
		文1;
}
else
	文2;		
を,{ } を記述せず,
if (論理式1)
	if (論理式2)
		文1;
else
	文2;		
のように書くと,if 文
if (論理式) {
	文1(複数の文も可)
}
else {
	文2(複数の文も可)
}		
を 1 文とみなすため,
if (論理式1)
	if (論理式2)
		文1;
	else
		文2;		
と解釈されてしまいますので気をつけて下さい.なぜなら,コンパイラが,else に対する if は,else に最も近い if と判断するからです.このような紛らわしさを除くためには,多少余分であっても,{ } を付加した方が良いかもしれません.

  また,この最大値と最小値の問題を
if (a > b && c > a) {
	amax = c;
	amin = b;
}
if (a > b && c < b) {
	amax = a;
	amin = c;
}
・・・・・		
のように,else 文を使用しないで書く人がいますが,余分な比較演算を行うことになり,あまり感心できません.また,変数 amin や amax を if ブロック内で型宣言しても良さそうに見えますが,この例の場合,50 行目でこれらの変数を参照しているため,17 行目以前に行う必要がある点に注意してください.

(プログラム)
/**************************************/
/* 3つのデータの最大値と最小値の計算 */
/*      coded by Y.Suganuma           */
/**************************************/
#include <stdio.h>

int main()
{
	double a, b, c, amin, amax;
/*
     データの入力
*/
	printf("3つのデータを入力して下さい ");
	scanf("%lf %lf %lf", &a, &b, &c);
/*
     a>bの場合
*/
	if (a > b) {
		if (c > a) {
			amax = c;
			amin = b;
		}
		else {
			amax = a;
			if (c < b)
				amin = c;
			else
				amin = b;
		}
	}
/*
     a≦bの場合
*/
	else {
		if (c > b) {
			amax = c;
			amin = a;
		}
		else {
			amax = b;
			if (c < a)
				amin = c;
			else
				amin = a;
		}
	}
/*
     出力
*/
	printf("最大値=%f  最小値=%f\n", amax, amin);

	return 0;
}
			

  データの数が増えた場合,上の方法は非常に面倒になります.以下のように書いた方がより一般的であり,また,理解し易いと思います.

(プログラム)
#include <stdio.h>

int main()
{
	double a, b, c;
/*
	 データの入力
*/
	printf("3つのデータを入力して下さい ");
	scanf("%lf %lf %lf", &a, &b, &c);
/*
	 初期設定
*/
	double amax = a;
	double amin = a;
/*
	 残りの2つのデータと比較する
*/
	if (b > amax)
		amax = b;
	else {
		if (b < amin)
			amin = b;
	}

	if (c > amax)
		amax = c;
	else {
		if (c < amin)
			amin = c;
	}
/*
	 出力
*/
	printf("最大値=%f  最小値=%f\n", amax, amin);

	return 0;
}
			

(プログラム例 5.4 ) データの比較 ( A ~ E,及び,F ~ J の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次のプログラムは,入力されたデータを x,y,および,z に代入されている値と比較し,そのどれと等しいかを出力しています.

(プログラム)
/****************************/
/* データの比較             */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>

int main()
{
/*
	 データの入力
*/
	int data;
	printf("データを入力して下さい ");
	scanf("%d", &data);
/*
	 判定と出力
*/
	int x = 10, y = 20, z = 30;
	if (data == x)
		printf("xと等しい\n");
	else {
		if (data == y)
			printf("yと等しい\n");
		else {
			if (data == z)
				printf("zと等しい\n");
			else
				printf("いずれとも等しくない\n");
		}
	}

	return 0;
}
			

  この例ではそれほどではありませんが,一般に,if 文のネストが深くなるとプログラムが見にくくなります.そのような意味で,この例のような場合は,「else if」の構文を利用して,以下のように書いた方がすっきりします.

(プログラム)
/****************************/
/* データの比較             */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>

int main()
{
/*
	 データの入力
*/
	int data;
	printf("データを入力して下さい ");
	scanf("%d", &data);
/*
	 判定と出力
*/
	int x = 10, y = 20, z = 30;
	if (data == x)
		printf("xと等しい\n");
	else if (data == y)
		printf("yと等しい\n");
	else if (data == z)
		printf("zと等しい\n");
	else
		printf("いずれとも等しくない\n");

	return 0;
}
			

---------------------(C++11)if 文-------------------------

  C++11 以降では,以下に示すような形式も可能です.
if (初期化 論理式) {
	文1(複数の文も可)
}
else {
	文2(複数の文も可)
}		
具体的には,例えば,以下に示すような記述方法です.このような記述を行いますと,変数 k の有効範囲は if 文内に限られます.従来の方法で記述すれば,コメント部分のようになり,変数 k の有効範囲は,型宣言を行った以降となり,if 文内だけには限定されません.確かに,新たな方法によって記述が簡単になる場合もありますが,「読みやすく,理解しやすい」プログラムを書くという原則から外れる場合も多く,使用は避けた方が良いと思います.
//int k = y / x;
//if (k > 1) {
if (int k = y / x; k > 1) {
	文1(複数の文も可)
}
else {
	文2(複数の文も可)
}		

----------------------(C++11)if 文終わり--------------------

5.1.2 switch 文

  switch 文の一般形式は以下の通りです.
switch (式) {
	[case 定数式1 :]
		[文1]
	[case 定数式2 :]
		[文2]
	 ・・・・・
	[default :]
		[文n]
}		
  まず,式が評価されます.その値が定数式の値のいずれかに等しければ,それ以降の文が実行されます.もちろん,文 i は,複数の文でも構いません.いずれの定数式の値にも一致しない場合,もし,default キーワードの項があればそれ以降が実行され,そうでなければ,何も実行されず switch 文以降の文が実行されます.

(プログラム例 5.5 ) データの比較( switch 文) 

  次のプログラムは,入力されたデータを x,y,および,z に代入されている値と比較し,そのどれと等しいかを出力しています.プログラムの中に,break 文が使用されていますが,break 文はその文に至った時点で強制的に switch 文を抜け出すための文です.このプログラムに対して,20 を入力すると,

yと等しい

と出力されますが,もし,break 文が全くない場合は,この出力文以降がすべて実行されるため,

yと等しい
zと等しい
いずれとも等しくない

のすべての文が出力されてしまいます.

  このプログラムのように,if 文を使用して変数 sw に値を代入することなしに,
switch (data) {
	case x :
		printf("xと等しい\n");
		break;
	case y :
		printf("yと等しい\n");
		break;
	case z :
		printf("zと等しい\n");
		break;
	default :
		printf("いずれとも等しくない\n");
}
		
のように書ければ良いのですが,case の後には定数式しか許されていないため,不可能です.もちろん,この例の場合には,x,y,および,z に代入されている値を case の後に直接書けば可能ですが,これらの変数に何が代入されているのかが分からないようなときには,採用できない方法です.

(プログラム)
/****************************/
/* データの比較             */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>

int main()
{
/*
	 データの入力と判定準備
*/
	int data;
	printf("データを入力して下さい ");
	scanf("%d", &data);

	int sw, x = 10, y = 20, z = 30;
	if (data == x)
		sw = 0;
	else {
		if (data == y)
			sw = 1;
		else
			sw = (data == z) ? 2 : 3;
	}
/*
	 判定と出力
*/
	switch (sw) {
		case 0 :
			printf("xと等しい\n");
			break;
		case 1 :
			printf("yと等しい\n");
			break;
		case 2 :
			printf("zと等しい\n");
			break;
		default :
			printf("いずれとも等しくない\n");
	}

	return 0;
}
			

---------------------(C++11)switch 文-------------------------

  C++11 以降では,以下に示すような形式も可能です.
switch (初期化 式) {
	[case 定数式1 :]
		[文1]
	[case 定数式2 :]
		[文2]
	 ・・・・・
	[default :]
		[文n]
}		
具体的には,例えば,以下に示すような記述方法です.このような記述を行いますと,変数 k の有効範囲は switch 文内に限られます.従来の方法で記述すれば,コメント部分のようになり,変数 k の有効範囲は,型宣言を行った以降となり,switch 文内だけには限定されません.確かに,新たな方法によって記述が簡単になる場合もありますが,「読みやすく,理解しやすい」プログラムを書くという原則から外れる場合も多く,使用は避けた方が良いと思います.
//int k = y / x;
//switch (3 * k) {
switch (int k = y / x; 3 * k) {
	case 0:
		printf("0\n");
		break;
	case 3:
		printf("3\n");
		break;
	default:
		printf("other\n");
}
		

----------------------(C++11)switch 文終わり--------------------

5.1.3 goto 文

  goto 文は,goto の後ろに書かれたラベルが付けられた箇所に無条件に移動するための文です.ただ,この文を頻繁に使用すると,分かり難いプログラムの原因になります.goto 文を使用した方が読み易いという特別の事情がない限り,使用しない方が良いと思います.goto 文を全く使用しなくても,同等のプログラムは必ず書けるはずです.
goto ラベル;
 ・・・
ラベル: ・・・
     ・・・		

(プログラム例 5.6 ) 入力の繰り返し( goto )

  次のプログラムでは,要求にあったデータが入力されるまで,再入力を促しています.また,要求通りのデータの場合は,和を求め出力しています.このプログラムは,次節で述べる繰り返し文を使用すれば,goto 文を使用せずに書くことができます.

/**********************************/
/* 正しいデータの再入力(goto文) */
/*      coded by Y.Suganuma       */
/**********************************/
#include <stdio.h>

int main()
{
	int x, y;

	again: printf("2つの正のデータを入力して下さい ");
		   scanf("%d %d", &x, &y);

	if (x < 0 || y < 0)     /* いずれかが負 */
		goto again;
	else     /* 両方とも 0 以上 */
		printf("和は=%d\n", x+y);

	return 0;
}
		

5.2 繰り返し

5.2.1 繰り返し文

  プログラムによっては,同じ手順を何回も繰り返して行いたいような場合がよく起こります.for 文は,その様なときに使用します.例えば,5 つのデータを読み込みその和を計算する場合,前節までの方法を使用すれば次のようになります.

#include <stdio.h>
int main()
{
	double data;
	double sum = 0.0;
	scanf("%lf", &data);
	sum += data;
	scanf("%lf", &data);
	sum += data;
	scanf("%lf", &data);
	sum += data;
	scanf("%lf", &data);
	sum += data;
	scanf("%lf", &data);
	sum += data;
	printf("和=%f\n", sum);
	return 0;
}
		

  しかし,5 つ程度のデータであれば,上の方法でも可能ですが,データの数が多くなると困難になります.そこで,このプログラムは,for 文を使用することによって,次のようにより簡単に書くことができます.

#include <stdio.h>
int main()
{
	double sum = 0.0;
	int i1;
	for (i1 = 0; i1 < 5; i1++) {
//	for (int i1 = 0; i1 < 5; i1++) {   // C++ の場合は,上 2 行の代わりにこの行でも良い
//	                                   // 以下に示す例題においても同様
		double data;
		scanf("%lf", &data);
		sum += data;
	}
	printf("和=%f\n", sum);
	return 0;
}
		

  for 文の一般的形式は以下の通りです.
for (式1; 式2; 式3) {
	文(複数の文も可)
}
・・・・・		
  for 文に入ると,まず,式 1 が実行されます.式 1 は,通常,for 文の繰り返し回数を制御するため等の初期設定を行う式であり,for 文の最初に 1 回だけ実行されます.次に,式 2 (論理式)の値が評価され,もし真であれば文が実行されます.そして,式 3 が実行されます.再び,式 2 が評価され,その値が真である限り,文と式 3 の実行が繰り返されます.式 2 の値が偽になると,文と式 3 は実行されず,「・・・」以下の文が実行されることになります( for 文の外に出る).

  for 文において,式 1 と式 3 を省略することは可能(「;」は省略できない)ですが,通常,式 2 を省略することはできません(省略すると,無限ループになってしまう).

  for 文と同様な機能を持つ文として,while 文do while 文があります.while 文,及び,do-while 文の一般形式は以下の通りです.なお,C++11 以降においては,範囲 for 文を使用することが可能ですが,その説明は,「配列」に対する説明の中で行います.
<while文>
	while (式) {
		文(複数の文も可)
	}
	 ・・・・・		
<do while文>
	do {
		文(複数の文も可)
	} while (式) ;
	 ・・・・・		
  while 文では,式(論理式)の値が真である限り,文の実行が繰り返されることになります.while 文と do while 文の違いは,式の評価が,文を実行する最初に行われるか,または,後で行われるかの違いです.do while 文では,式の評価が後で行われるため,do while 文の開始時に式が偽であっても,文が少なくとも 1 回は実行されることになります.

  先に述べた for 文は,while 文を使用して,次のように書くこともできます.どちらの表現方法を使用するかは趣味の問題ですが,問題に応じて,理解しやすいプログラムになると思われる方を使用して下さい.
式1;
while (式2) {
	文(複数の文も可)
	式3;
}		
  このように,for 文,while 文,及び,do while 文はほぼ等価ですので,以下の説明では,基本的に,for 文を使用して説明を行います( while 文や do while 文に対しても同様の議論が成立します).

  if 文と同様,for 文の中が 1 文だけの場合は,{ } を省略可能です.また,次の例のように,for 文の中に別の for 文を書くこともできます( for 文のネスト).
for (式1; 式2; 式3) {
	・・・・・
	for (式4; 式5; 式6) {
		・・・・・
	}
	・・・・・
}		
  また,if 文と同じように,プログラムを読み易くするため,for 文内の文は,次の例のように,何列か段を下げて(字下げをして)書くようにして下さい.なお,この例は, C++ の仕様に従って記述しています( 02 行目,04 行目).if 文の場合と同様,01 行目で型宣言された変数 x,y,sum の有効範囲は 01 行目以降,02 行目で型宣言された変数 i1 の有効範囲は 02 行目~ 10 行目,03 行目で型宣言された変数 a の有効範囲は 03 行目~ 09 行目,04 行目で型宣言された変数 i2 の有効範囲は 04 行目~ 08 行目,05 行目で型宣言された変数 y の有効範囲は 05 行目~ 07 行目となります.
01  int x = 10, y = 20, sum;
02  for (int i1 = 0; i1 < 10; i1 = i1+1) {   // C では許されない
03  	int a = x;
04  	for (int i2 = 0; i2 < 5; i2 = i2+1) {   // C では許されない
05  		int y  = a / 50;
06  		a     += y;
07  		・・・・・・・・
08  	}
09  	sum = a / y;
10  }
		
(プログラム例 5.7 ) 平均値の計算 ( A ~ J ,及び,K ~ U の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  以下に,n 人の英語と数学の点数から,それらの平均点を計算するプログラムを,for 文を使用して書いた例を示します.

(プログラム)
/****************************/
/* 平均値の計算             */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>

int main()
{
/*
         初期設定
*/
	double sum1 = 0.0;
	double sum2 = 0.0;
/*
         データの数の読み込み
*/
	int n;
	printf("人数は? ");
	scanf("%d", &n);
/*
         データの読み込み
*/
	int i1;
	for (i1 = 0; i1 < n; i1++) {
		double x, y;
		printf("英語と数学の点は? ");
		scanf("%lf %lf", &x, &y);
		sum1 += x;
		sum2 += y;
	}
/*
         結果の計算と出力
*/
	if (n <= 0)                    /* 0で割るのを防ぐ */
		printf("データがない!\n");
	else {
		double mean1 = sum1 / n;
		double mean2 = sum2 / n;
		printf("   英語=%f 数学=%f\n", mean1, mean2);
	}

	return 0;
}
			
12,13 行目

  変数 sum1 と sum2 に対する初期設定を行っています.これらの変数は,28 及び 29 行目から明らかなように,各科目の合計点を求めるためのものです.通常,プログラム内で宣言された変数の値は,何らかの形で代入が行われない限り,どのような値になっているかは不明です.もし,これらの変数に 0 以外の値が入っていると,誤った合計計算を行うことになります.そこで,必ず,このような初期設定が必要になります.

  また,これらの文は,sum1 = 0 というように書いても正しく実行されます.しかし,変数 sum1 の型は double であるということを常に意識し,誤った型変換等を行わないためにも,0.0 というように,対応する正しい定数表現で記述した方が良いと思います.

24 行目

  この for 文によって,まず,変数 i1 が 0 に初期設定され,25 から 29 行目までの文が,条件「 i1 < n 」が満足される間繰り返されます.25 から 29 行目が実行される毎に,式 i1++ によって,変数 i1 の値が 1 づつ増加しますので,結局,25 から 29 行目の文が n 回繰り返されることになります.

28,29 行目

  平均点を求めるため,入力された英語及び数学の点を,変数 sum1 及び sum2 に加えています.

34 行目

  もし,人数 n が 0 以下の場合,37,38 行目で行っている平均を求める操作が無意味なものになりますので,この if 文によってそのような場合を除外しています.特に,n の値が 0 の場合は,0 で割ることになり,プログラムの実行が停止してしまいます.このように,0 で割る可能性があるような場合は,0 でないことをチェックしておいた方がよいと思います.

  参考のため,上のプログラムを while 文を使用して書き直したものを以下に示します.どちらのプログラムも正しく動作しますが,このように繰り返し回数が明確になっているような場合は,for 文を使用した方が理解しやすいのではないかと思います(好みにもよりますが).

(プログラム)
/****************************/
/* 平均値の計算             */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>

int main()
{
/*
         初期設定
*/
	double sum1 = 0.0;
	double sum2 = 0.0;
/*
         データの数の読み込み
*/
	int n;
	printf("人数は? ");
	scanf("%d", &n);
/*
         データの読み込み
*/
	int i1 = 0;

	while (i1 < n) {
		double x, y;
		printf("英語と数学の点は? ");
		scanf("%lf %lf", &x, &y);
		sum1 += x;
		sum2 += y;
		i1++;
	}
/*
         結果の計算と出力
*/
	if (n <= 0)
		printf("データがない!\n");
	else {
		double mean1 = sum1 / n;
		double mean2 = sum2 / n;
		printf("   英語=%f 数学=%f\n", mean1, mean2);
	}

	return 0;
}
			

(プログラム例 5.8 ) ファイル入出力 ( A ~ C の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  上の例では,平均を計算する人数があらかじめ分かっていました.しかし,英語と数学の点がファイルに保存されており,その人数(データの数)が分からないような場合はどのようにしたらよいでしょうか.次のプログラムはそのような場合の例です.今,ファイル「input」に英語と数学の点が,

23 45
34 99
・・・・・

のような形で,任意の数だけ保存されているものとします.そして,結果もファイル「output」に保存するものとします.

(プログラム)
/************************************/
/* ファイル入出力(平均値の計算後) */
/*      coded by Y.Suganuma         */
/************************************/
#include <stdio.h>

int main()
{
/*
         初期設定
*/
	double sum1 = 0.0;
	double sum2 = 0.0;
	int n       = 0;
/*
         データの読み込み
*/
	FILE *in = fopen("input","r");

	double x, y;
	while (EOF != fscanf(in,"%lf %lf",&x,&y)) {
		sum1 += x;
		sum2 += y;
		n++;
	}

	fclose(in);
/*
         結果の計算と出力
*/
	if (n <= 0)
		printf("データがない!\n");
	else {
		FILE *out    = fopen("output", "w");
		double mean1 = sum1 / n;
		double mean2 = sum2 / n;
		fprintf(out, "人数 %d 英語=%f 数学=%f\n", n, mean1, mean2);
		fclose(out);
	}

	return 0;
}
			
14 行目

  変数 n はデータの数(人数)を数えるためのカウンタです.一組のデータを読む度に,24 行目において 1 づつ増加させています.そのため,必ず,初期設定が必要です.

18 行目

  fopen は,ファイルから読んだり,ファイルに書いたりするための準備を行う関数です.この行では,ファイル input からの入力( "r" の指定)の準備を行っています.この関数の左辺にくる変数( in や out )に対しては,必ず,「 FILE *in 」のような型宣言が必要になります.

21 行目

  ここでは,繰り返し制御のため,while 文を使用しています.この例の場合は,while 文の方が for 文より好ましいと思います.while 文の中の式の意味は,関数 fscanf の値が EOF でない限り,22~24 行目の文を繰り返すことを意味しています.EOF とは「 End of File 」のことであり,関数 fscanf の値が EOF であるということは,「データを読もうとしたが既にデータがなかった」ということを意味しています.従って,この while 文によって,データが存在する間,そのデータを読み込み,22~24 行目の処理が行われます.

  また,fscanf は,ファイルからデータを読み込むための関数です.カッコの中の最初に 18 行目の fopen で使用した変数が来る以外,基本的に,関数 scanf と同じです.

27 行目

  入力データを読み終え,ファイルを必要としなくなったのでその終了処理を行って(ファイルを閉じる,fclose )います.プログラムの実行が終了すると使用していたファイルはすべて自動的に閉じられるため,このプログラムでは必要性は少ないですが,一般的に,使用し終わったら閉じておいた方が良いと思います.

34, 37, 38 行目

  出力ファイルに対する,入力ファイルと同様な処理です( fopen において,出力ファイル名 "output" と "w" を指定).fprintf は,ファイルからデータを読み込むための関数です.カッコの中の最初に 34 行目の fopen で使用した変数が来る以外,基本的に,関数 printf と同じです.

  参考のため,cin や cout の相当する機能を使用してファイル入出力を行うプログラムの例を書いておきます.行っている内容は,上記のプログラムと全く同じです.詳細については,16.3 節を参照してください.

/************************************/
/* ファイル入出力(平均値の計算後) */
/*      coded by Y.Suganuma         */
/************************************/
#include <iostream>
#include <fstream>

int main()
{
/*
		 データの読み込み
*/
	std::ifstream in("input");

	double sum1 = 0.0, sum2 = 0.0;
	int n = 0;
	while (!in.eof()) {
		double x, y;
		in >> x >> y;
		sum1 += x;
		sum2 += y;
		n++;
	}

	in.close();
/*
		 結果の計算と出力
*/
	if (n <= 0)
		std::cout << "データがない!\n";
	else {
		std::ofstream out("output");
		double mean1 = sum1 / n;
		double mean2 = sum2 / n;
		out << "人数 " << n << " 英語=" << mean1 << " 数学=" << mean2 << std::endl;
		out.close();
	}

	return 0;
}
		

(プログラム例 5.9 ) for 文のネスト ( A ~ F の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次に,for 文のネストの例を示します.今,ある学年に,n クラスあったとします.そして,各クラスには m 人(クラス毎に異なる)の生徒がおり,全員に対しある試験を実施したとします.このとき,平均値が最も高いクラス番号( 1 クラスだけであるとします)とその平均値を出力するプログラムは,例えば,以下のようになります.この例により,for 文のネスト,変数の初期設定等を理解して下さい.

(プログラム)
/************************************/
/* クラス平均と最も良いクラスの出力 */
/*      coded by Y.Suganuma         */
/************************************/
#include <stdio.h>

int main()
{
/*
          データの入力と平均値の計算
*/
	int n;
	printf("クラスの数は? ");
	scanf("%d", &n);

	double max;
	int i1, max_c;
	for (i1 = 0; i1 < n; i1++) {      /* クラスの数だけ繰り返す */

		int m;
		printf("%d 番目のクラスの人数は ", i1+1);
		scanf("%d", &m);

		double mean = 0.0;                /* この初期設定はここで必要 */

		int i2;
		for (i2 = 0; i2 < m; i2++) {   /* クラスの人数だけ繰り返す */
			double x;
			printf("     %d 番目の人の点は? ", i2+1);
			scanf("%lf", &x);
			mean += x;
		}

		mean /= m;

		if (i1 == 0 || mean > max) {
			max   = mean;
			max_c = i1 + 1;
		}
	}
/*
          結果の出力
*/
	printf("最大平均値はクラス %d の %f 点\n", max_c, max);

	return 0;
}
			
18 行目

  この for 文により,クラスの数だけ,19~39 行目までを繰り返します.

24 行目

  変数 mean は,各クラスの平均点を計算するための変数ですので,この位置で初期設定が必要です.また,このプログラムは,メッセージレベルの設定にもよりますが,gcc においてコンパイルすると,変数 max および max_c に対して,初期設定がされていないかもしれないという警告メッセージが出力されます.しかし,36 行目からも明らかなように,初期設定を必要としません.警告メッセージを消したい場合は,16,17 行目において,max および max_c に適当な値を設定しておいてください.

27 行目

  この for 文により,各クラスの人数だけ,28~31 行目までを繰り返します.

34 行目

  平均値の計算です./= という演算子を思い出してください.

36~39 行目

  変数 i1 の値が 0 ( 1 番目のクラスであることを示す),または,上で計算した変数 mean の値(現在のクラスの平均値)が,変数 max の値より大きいときは,変数 max の値を変数 mean の値で置き換え,かつ,そのクラス番号( i1 + 1 )を変数 max_c に保存します.36 行目において,if 文の中は「 mean > max 」だけで良さそうですが,そのようにすると問題が起こります.なぜなら,変数 max には,当初何が入っているか分からないからです.そこで,最初に計算したクラスに対しては,無条件に,そのクラス番号と平均値を保存することがこの if 文の目的です.勿論,この例の場合は,16,17 行目において,max と max_c の初期設定を行っておけば,if 文の中は「 mean > max 」だけで良くなります.

(プログラム例 5.10 ) 入力の繰り返し( do while ) ( A ~ D の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  プログラム例 5.6 では goto 文を使用して繰り返しの処理を行っていましたが,goto 文を使用せず,do while 文を使用して,次のように書くことができます.このプログラムでは,要求にあったデータ(正のデータ)が入力されるまで,再入力を促しています.また,要求通りのデータの場合は,和を求め出力しています.繰り返し回数が未定であり,かつ,入力終了後に繰り返し判定を行いたいため,do while 文を使用しています.もちろん,for 文や while 文を使用して書くことも可能です.少なくとも,このようなケースに対して goto 文を使うべきではないと思います.

(プログラム)
/*************************************/
/* 正しいデータの再入力(do-while文)*/
/*      coded by Y.Suganuma          */
/*************************************/
#include <stdio.h>

int main()
{
	int x, y;

	do {
		printf("2つの正のデータを入力して下さい ");
		scanf("%d %d", &x, &y);
	} while (x <= 0 || y <= 0);

	printf("和は=%d\n", x+y);

	return 0;
}
			

(プログラム例 5.11 ) 最大値(初期設定) ( A ~ D の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  最大値を求める基本的なアルゴリズムは以下の通りです.まず,最大値を保存する変数,例えば max を適当な値で初期設定しておきます.次に,最大値を求めるデータ群の中の各データと max に代入されている値とを比較し,もし,比較したデータの方が max に代入されている値より大きければ,そのデータを max に代入します.これをすべてのデータに対して繰り返せば最大値が求まることになります.つまり,以下のようにプログラムすればよいわけです(データの数は 5 とし,各データはキーボードから入力されるものとしています).

/****************************/
/* 最大値の計算             */
/*      coded by Y.Suganuma */
/****************************/
#include <stdio.h>

int main()
{
	int n = 5, i1, max = 0;

	for (i1 = 0; i1 < n; i1++) {
		int x;
		printf("データを入力してください ");
		scanf("%d", &x);
		if (x > max)
			max = x;
	}

	printf("   最大値=%d\n", max);

	return 0;
}
		

  上のプログラムに問題は全くなさそうに見えます.しかし,負のデータだけを入力した場合について考えてみてください.最大値は 0 であるという答えが得られるはずです.明らかに,誤っています.なぜなら,変数 max に初期設定すべき値は,求めるべき最大値より必ず小さくなければならないからです.しかし,求めるべき最大値は不明です.どのようにしたら良いでしょうか.一つの方法は,以下のプログラムのように,最初のデータを max に代入しておく方法です.

#include <stdio.h>

int main()
{
	int n = 5, i1, max;

	printf("データを入力してください ");
	scanf("%d", &max);		/* 最初のデータでmaxを初期化 */

	for (i1 = 1; i1 < n; i1++) {	   /* i1を1から始める */
		int x;
		printf("データを入力してください ");
		scanf("%d", &x);
		if (x > max)
			max = x;
	}

	printf("   最大値=%d\n", max);

	return 0;
}
		

  上のプログラムは,どのようなデータを与えても,正しく最大値を出力してくれるはずです.それでは,問題を少し変えて,「与えられたデータの内,負のデータの最大値を求めよ」というようにしたらどうでしょうか.max とデータを比較している部分を,
if (x < 0 && x > max)		
のように変えてやればうまくいくように思われるかもしれません.たしかに,最初のデータが負であるときは正しく動きます.しかし,そうでないときは誤った最大値を出力してしまいます.これを回避する一つの方法は,以下のプログラムのように,変数 max が初期化されたか否かを示す指標(変数 sw )を設けてやることです.

(プログラム)
#include <stdio.h>
int main()
{
	int n = 5, i1, max, sw = 0, x;   /* maxに対する初期設定は不要 */

	for (i1 = 0; i1 < n; i1++) {
		printf("データを入力してください ");
		scanf("%d", &x);
		if (x < 0 && (sw == 0 || x > max)) {
			max = x;
			sw  = 1;
		}
	}

	printf("   最大値=%d\n", max);

	return 0;
}
			

(プログラム例 5.12 ) for 文,while 文,do while 文の比較 

  次の 3 つのプログラムは,for 文( 001 行目~ 028 行目),while 文( 029 行目~ 058 行目),及び,do while 文( 059 行目~ 104 行目)を使用して,同じ内容の処理を行っています.(1)においては,0 以上の数値が入力されるまで,入力データを要求し続けます.(2)においては,(1)で入力された数 no だけ「 * 」を出力すると共に,1 から no までの和を求めています.no の値が 0 の場合は,和だけが出力されます.この例では,for 文における i の初期値を 1 に設定していますが,コメント( 011,013 行目)に示したような形式でも構いません.(3)においては,データとして 0 を入力するまでの複数のデータの和を求めています.

  do while 文を使用した場合,一見,// によってコメント化した方法( 069 行目~ 076 行目,090 行目~ 094 行目)で良さそうですが,do 以下の内容が必ず 1 回は実行されるため,(2)に対しては,no の値が 0 の場合でも * が 1 個出力されてしまい,また,(3)に対しては,最初のデータとして 0 を入力しても,再度,「データ?」という入力促進メッセージが出力されてしまいます.

/*
	for 文
*/
001	#include <stdio.h>
002	int main()
003	{
004				// (1)入力
005		int i, no = -1, sum1 = 0, sum2 = 0;
006		for (; no < 0; ) {
007			printf("0以上の整数を入力してください ");
008			scanf("%d", &no);
009		}
010				// (2)*と和1
011		for (i = 1; i <= no; i++) {   // for (i = 0; i < no; i++) {
012			printf("*");
013			sum1 += i;   // sum1 += (i + 1);
014		}
015		if (no > 0)
016			printf("\n");
017		printf("sum1 = %d\n", sum1);
018				// (3)和2
019		printf("データ? ");
020		scanf("%d", &i);
021		for (; i != 0; ) {
022			sum2 += i;
023			printf("データ? ");
024			scanf("%d", &i);
025		}
026		printf("sum2 = %d\n", sum2);
027		return 0;
028	}
/*
	while 文
*/
029	#include <stdio.h>
030	int main()
031	{
032				// (1)入力
033		int i, no = -1, sum1 = 0, sum2 = 0;
034		while (no < 0) {
035			printf("0以上の整数を入力してください ");
036			scanf("%d", &no);
037		}
038				// (2)*と和1
039		i = 1;
040		while (i <= no) {
041			printf("*");
042			sum1 += i;
043			i++;
044		}
045		if (no > 0)
046			printf("\n");
047		printf("sum1 = %d\n", sum1);
048				// (3)和2
049		printf("データ? ");
050		scanf("%d", &i);
051		while (i != 0) {
052			sum2 += i;
053			printf("データ? ");
054			scanf("%d", &i);
055		}
056		printf("sum2 = %d\n", sum2);
057		return 0;
058	}
/*
	do while文
*/
059	#include <stdio.h>
060	int main()
061	{
062				// (1)入力
063		int i, no = -1, sum1 = 0, sum2 = 0;   // noに対する初期設定は必要なし
064		do {
065			printf("0以上の整数を入力してください ");
066			scanf("%d", &no);
067		} while (no < 0);
068				// (2)*と和1
069	//	i = 1;
070	//	do {
071	//		printf("*");
072	//		sum1 += i;
073	//		i++;
074	//	} while (i <= no);
075	//	if (no > 0)
076	//		printf("\n");
077		if (no > 0) {
078			i = 1;
079			do {
080				printf("*");
081				sum1 += i;
082				i++;
083			} while (i <= no);
084			printf("\n");
085		}
086		printf("sum1 = %d\n", sum1);
087				// (3)和2
088		printf("データ? ");
089		scanf("%d", &i);
090	//	do {
091	//		sum2 += i;
092	//		printf("データ? ");
093	//		scanf("%d", &i);
094	//	} while (i != 0);
095		if (i != 0) {
096			do {
097				sum2 += i;
098				printf("データ? ");
099				scanf("%d", &i);
100			} while (i != 0);
101		}
102		printf("sum2 = %d\n", sum2);
103		return 0;
104	}
		

5.2.2 繰り返しの中断

  通常,繰り返し文は,繰り返し条件が成立しなくなるまで続けられますが,場合によっては,繰り返しの途中でループの外へ出たい場合があります.この節では,そのような場合に使用する文について解説します.

5.2.2.1 break 文

  break 文は,break を囲んでいる最も内側の for 文,while 文,または,do while 文を終了させ,それらの次の文に制御を移します.また,switch においても,しばしば使用されます.

(プログラム例 5.13 ) 繰り返しの中断( break ) ( A ~ D の部分を可能な限り一つの変数,定数,演算子等で,埋めてください.その際,文字を削除してから,正しい答えを半角文字で,かつ,余分なスペースを入れないで入力してください.)

  次のプログラムは,n 個のデータの和を求めるプログラムですが,負のデータが入力されると,その時点で for ループの外に出ます.

/**********************************/
/* データの和(負のデータで終了) */
/*      coded by Y.Suganuma       */
/**********************************/
#include <stdio.h>

int main()
{
/*
	 データ数の入力
*/
	int n;
	printf("データ数は? ");
	scanf("%d", &n);
/*
	 和の計算
*/
	int i1, sum = 0;
	for (i1 = 0; i1 < n; i1++) {
		int x;
		printf("   データを入力して下さい ");
		scanf("%d", &x);
		if (x < 0)
			break;
		else
			sum += x;
	}
/*
	 出力
*/
	printf("和=%d\n", sum);

	return 0;
}
		

  上のプログラムは,break 文を使用せず,以下に示すような方法で書くことも可能です.この方法では,i1 が n より小さく,かつ,x の値が 0 以上の場合に繰り返しが継続されます.つまり,i1 が n 以上,または,x の値が負になるとループの外に出ます.多重ルールの外側に一度で出たいような場合に有効です.

(プログラム)
#include <stdio.h>

int main()
{
/*
	 データ数の入力
*/
	int n;
	printf("データ数は? ");
	scanf("%d", &n);
/*
	 和の計算
*/
	int i1, x = 0, sum = 0;
	for (i1 = 0; i1 < n && x >= 0; i1++) {
		printf("   データを入力して下さい ");
		scanf("%d", &x);
		if (x >= 0)
			sum += x;
	}
/*
	 出力
*/
	printf("和=%d\n", sum);

	return 0;
}
			

5.2.2.2 continue 文

  continue 文は,for 文,while 文,または,do while 文本体の残りを実行せずに,次の繰り返しを実行します.break 文と似ていますが,continue 文では,break のように現在の繰り返し自身を終了させるわけではありません.

(プログラム例 5.14 ) 繰り返しの中断( continue )

  次のプログラムは,n 個のデータの和を求めるプログラムですが,負のデータが入力された場合はそのデータを除外します.

/**********************************/
/* データの和(負のデータを除外) */
/*      coded by Y.Suganuma       */
/**********************************/
#include <stdio.h>

int main()
{
/*
	 データ数の入力
*/
	int n;
	printf("データ数は? ");
	scanf("%d", &n);
/*
	 和の計算
*/
	int i1, sum = 0;
	for (i1 = 0; i1 < n; i1++) {
		int x;
		printf("   データを入力して下さい ");
		scanf("%d", &x);
		if (x < 0)
			continue;
		sum += x;
	}
/*
	 出力
*/
	printf("和=%d\n", sum);

	return 0;
}
		

演習問題5

[問1]年齢を読み込み,20 歳以上なら「大人」,そうでなければ「子供」と出力するプログラムを書け.

[問2]一つの整数データを読み込み,その値がゼロなら「0」,正なら「正」,それ以外なら「負」と出力するプログラムを,if 文を使用して書け.

[問3]試験の点数を読み込み,その点数が
60 点未満なら「不可」
60 点以上で 70 点未満なら「可」
70 点以上で 80 点未満なら「良」
80 点以上なら「優」
と出力するプログラムを書け

[問4]時間と分の変換を行うプログラムを書け.つまり,1 時間 20 分なら 80 分,また,90 分なら 1 時間 30 分に変換する.

[問5]閏年の判定を行うプログラムを書け.閏年は,年号が 4 で割り切れ,100 で割り切れない年である.ただし,400 で割り切れる年は含む.

[問6]1 度,2 度,・・・,及び,90 度に対し,各角度とその正弦の値(関数 sin )を出力するプログラムを書け(注:ヘッダファイル math.h も必要).

[問7]次の式の値を計算し,出力するプログラムを書け
(1)1.02+・・・+500.02
(2)1/1 + 1/2 + 1/3 + ・・・ + 1/20

[問8] n(入力)個のデータを読み込み,100 以上のデータ,及び,100 未満のデータの和をそれぞれ求めるプログラムを書け.

[問9]与えられた n 個のデータ内にある正の数と負の数の個数を出力するプログラムを書け.

[問10] n 個の抵抗(入力)を直列または並列に接続したときの合成抵抗を計算するプログラムを書け.例えば,n が 2 の場合,抵抗 R1 及び 抵抗 R2 を直列または並列結合したときの合成抵抗 R は,各々,以下のようになる

  

[問11] n の値を読み込んだ後,n! を計算し出力するプログラムを書け.

[問12] n,r の値を読み込んだ後,nr( = n! / (r! (n - r)!) )を計算するプログラムを書け.

[問13]正の整数値 n を読み込み,偶数の時はその値を 2 で割り,また,奇数の時はその値を 3 倍したものに 1 を加えるという処理を n の値が 1 になるまで繰り返すためのプログラムを書け.ただし,1 回の演算を行う毎に現在の n の値を表示するものとする.

[問14]n(入力)人の試験の点を入力した後,不可,可,良,及び,優の割合(%)を計算し,出力するプログラムを書け.ただし,
不可: 50 点未満
可 : 50 点から 60 点未満
良 : 60 点から 80 点未満
優 : 80 点以上
とする.

[問15] n 人に給与を支払うものとする.n 及び各人の給与の額をファイルから読み込み,すべての人に給与を釣り銭がないように支払うために必要な 10,000 円札,5,000 円札,1,000 円札,500 円硬貨,及び,100 円硬貨の合計枚数を出力するプログラムを書け.ただし,給与の最小単位は 100 円であるものとする.

[問16]九九の表を出力するプログラムを書け.

[問17]正の整数を入力し,それを各桁毎に分解し,それらの数字を正順及び逆順に,間に 1 つ以上の空白をあけて出力するプログラムを書け.例えば,12345 と入力したら,次のように出力することになる.ただし,整数の桁数は最大 9 桁であるとする.
1 2 3 4 5
5 4 3 2 1

[問18]整数型データの中で 1 になっているビットの数を出力するプログラムを書け.

[問19]複数個(未知)の実数データをファイルから読み込み,その最大値と最小値を出力するプログラムを書け.

[問20]ある学年に n(入力)クラスあり,各クラスには m(入力,クラス毎に異なる)人の生徒がいるものとする.全員に対しある試験を実施したとき,学年で最高点をとった生徒の点数及びその生徒が属するクラス番号を出力するプログラムを書け(最高点の生徒は一人だけであるとする).

[問21]ニュートン法により次式の根を求めるためのプログラムを書け.
f(x) = ex - 3x = 0
ただし,ニュートン法とは,関数 f(x) が単調連続で変曲点が無く,かつ,微分可能であるとき利用できる方法であり,根の適当な初期値 x0 から始めて,反復公式
xn+1 = xn - f(xn) / f'(xn)
を繰り返すことによって非線形方程式の解を求める方法である.この方法の幾何学的意味は右図に示すとおりである.収束判定の条件としては,
|xn+1 - xn| < ε
|f(xn+1) - f(xn)| < ε
|f(xn)| < ε
などがある.

[問22]二分法により次式の根を求めるためのプログラムを書け.
f(x) = ex - 3x = 0
ただし,二分法は,関数 f(x) が区間 [a, b] で連続で,かつ,根が1つだけ存在するとき利用できる方法である.従って,f(a)f(b) < 0 となる.区間 [a, b] の中点 c を
c = 0.5 * (a + b)
で求め,f(c) の値を計算し,f(a)f(c) < 0 なら
b = c,f(b) = f(c)
そうでなければ
a = c,f(a) = f(c)
と置き換え,根の存在区間を半分に縮小する.この操作を,
|b - a| < ε
が満足されるまで繰り返すことによって解を求める.

[問23]台形則により次の関数の任意区間の積分値を計算するプログラムを書け.
f(x) = (2π)-0.5-x*x/2
ただし,台形則は,積分区間[x1, x2]をn個の,幅
h = (x2 - x1) / n
の小区間に分け,各区間の面積を右図のような台形で近似して,積分値を計算する方法である.従って,積分値Sは次のように書ける.
S = 0.5h{f(x1) + 2(f(x1+h) + f(x1+2h) + ・・・ + f(x2-h)) + f(x2)}

情報学部 菅沼ホーム 全体目次 演習解答例 付録 索引