for ループは n 重に重ねることができる. これにより, n 個の数字の全組合せを網羅的に発生し, それぞれの場合についての計算を行うことができる.
例題 8.1 1≤a≤9, 1≤b≤9 を満たす整数 a, b の全ての組合せに対して, a*b を計算するプログラムを作成せよ.
ex81.c |
---|
#include <stdio.h> int main(void) { int a, b; for (a=1; a<=9; a++) { for (b=1; b<=9; b++) { printf("%d * %d = %d¥n", a, b, a*b); } } return 0; } |
実行例
$ ./a 1 * 1 = 1 1 * 2 = 2 1 * 3 = 3 … 1 * 9 = 9 2 * 1 = 2 2 * 2 = 4 2 * 3 = 6 … 2 * 9 = 18 3 * 1 = 3 … 9 * 7 = 63 9 * 8 = 72 9 * 9 = 81 |
例題 8.2 3 つのサイコロ a, b, c を振った時の目の和を全ての場合について計算するプログラムを作成せよ.
ex82.c |
---|
#include <stdio.h> int main(void) { int a, b, c; for (a=1; a<=6; a++) { for (b=1; b<=6; b++) { for (c=1; c<=6; c++) { printf("%d + %d + %d = %d¥n", a, b, c, a+b+c); } } } return 0; } |
実行例
$ ./a 1 + 1 + 1 = 3 1 + 1 + 2 = 4 1 + 1 + 3 = 5 … 中略 … 6 + 6 + 4 = 16 6 + 6 + 5 = 17 6 + 6 + 6 = 18 |
課題 8.1
1 以上 5 以下の 2 つの整数 x, y の全ての組合せについて,
(0,0) と (x,y) の距離 (x2+y2の平方根)
を計算して表示するプログラム distall2.c を作成せよ.
課題 8.2
1 以上 3 以下の 3 つの整数 x, y, z の全ての組合せについて,
x, y, z の相加平均を計算して表示するプログラム aveall3.c を作成せよ.
もし小数点以下が出なかったら, 何かを忘れている
( C3 の「3. 整数除算と実数除算」参照)
多重ループを用いると, ある条件を満たす数の組合せを網羅的な探索により発見することができる.
例題 8.3 10 以下の 3 つの自然数 (x,y,z) で, 2x<y かつ x2+3y=2z を満たすものを求めよ.
ex83.c |
---|
#include <stdio.h> int main(void) { int x, y, z; for (x=1; x<=10; x++) { for (y=1; y<=10; y++) { for (z=1; z<=10; z++) { /* 3 重ループで全組合せを調べる */ if (2*x<y && x*x+3*y==2*z) { /* 条件を満たせば表示 */ printf("(x,y,z)=(%d,%d,%d)¥n",x,y,z); } } } } return 0; } |
実行例
$ ./a (x,y,z)=(1,3,5) (x,y,z)=(1,5,8) |
【注意】
課題 8.3
自然数 p, a, b (ただし p は素数とする) を入力し,
0≤x<p, 0≤y<p を満たす自然数 x, y の組合せの中で,
ax2+by2 = 1 mod p を満たすものを全て求めるプログラム
ieq.c を作成せよ.
次のような出力が得られることを確認せよ (表示形式は各自工夫せよ).
$ ./a p a b = 5 3 2 x=1, y=2 x=1, y=3 x=4, y=2 x=4, y=3 |
課題 8.4
50円切手が 5 枚, 80円切手が 4 枚, 120円切手が 3 枚ある.
キーボードから目標金額 t を入力し,
金額の合計が t になるような切手の枚数の全ての組合せを求めるプログラム
stamp.c を作成せよ.
次のような出力が得られることを確認せよ (表示形式は各自工夫せよ).
$ ./a 目標金額 = 310 50円3枚, 80円2枚, 120円0枚で 310 円になります |
for 文の「継続条件」を工夫することにより, 計算結果に合わせて繰り返し回数を変更できる.
例題 8.4
数列 ai=1/ir の i=1 から n までの和を Si とする
(つまり, Sn = 1/1r + 1/2r + 1/3r + … + 1/nr である).
実数 r を入力し, Si が初めて 2 を超える i を求めるプログラムを作成せよ.
とりあえず, i=1, 2, …, 100 について ai と Si を計算するプログラムを作ってみる.
#include <stdio.h> #include <math.h> int main(void) { double r; int i; double ai; double Si; printf("r = "); scanf("%lf", &r); Si = 0; // 数列の和 Si の初期値 for (i=1; i<=100; i++) { // とりあえず i=100 まで計算してみる ai = (double) 1 / pow(i,r); // ai = 1/ir Si = Si + ai; // 数列の和 printf("i=%d ai=%f Si=%f¥n", i, ai, Si); } return 0; } |
r = 1 の場合の実行結果は次のようになる.
$ ./a r = 1 i=1 ai=1.000000 Si=1.000000 i=2 ai=0.500000 Si=1.500000 i=3 ai=0.333333 Si=1.833333 i=4 ai=0.250000 Si=2.083333 i=5 ai=0.200000 Si=2.283333 i=6 ai=0.166667 Si=2.450000 ... i=99 ai=0.010101 Si=5.177378 i=100 ai=0.010000 Si=5.187378 |
r = 1.7 の場合の実行結果は次のようになる.
$ ./a r = 1.7 i=1 ai=1.000000 Si=1.000000 i=2 ai=0.307786 Si=1.307786 i=3 ai=0.154488 Si=1.462274 i=4 ai=0.094732 Si=1.557006 i=5 ai=0.064826 Si=1.621832 ... i=97 ai=0.000419 Si=1.996400 i=98 ai=0.000412 Si=1.996812 i=99 ai=0.000405 Si=1.997217 i=100 ai=0.000398 Si=1.997615 |
このような場合, 固定回数を繰り返すのではなく,
ある条件 (ここでは Si≤2) が成り立つ間だけ繰り返すようにできると良い.
これは, for の「継続条件」を書き換えれば, 容易に実現できる.
ただし, 条件が永遠に成り立たない可能性がある場合は,
無限ループを防ぐために, 繰り返し回数に && で継続条件を追加する方が良い.
ex84.c |
---|
#include <stdio.h> #include <math.h> int main(void) { double r; int i; double ai; double Si; printf("r = "); scanf("%lf", &r); Si = 0; // 数列の和 Si の初期値 for (i=1; i<=10000 && Si<=2; i++) { // 1万回以内か, Siが2を越えない間 ai = (double) 1 / pow(i,r); // ai = 1/ir Si = Si + ai; // 数列の和 printf("i=%d ai=%f Si=%f¥n", i, ai, Si); } printf("求める i は %d¥n", i-1); // 求める答えの出力 return 0; } |
実行結果 (r=1 のとき)
$ ./a r = 1 i=1 ai=1.000000 Si=1.000000 i=2 ai=0.500000 Si=1.500000 i=3 ai=0.333333 Si=1.833333 i=4 ai=0.250000 Si=2.083333 求める i は 4 |
実行結果 (r=1.7 のとき)
$ ./a r = 1.7 i=1 ai=1.000000 Si=1.000000 i=2 ai=0.307786 Si=1.307786 i=3 ai=0.154488 Si=1.462274 i=4 ai=0.094732 Si=1.557006 i=5 ai=0.064826 Si=1.621832 ... i=105 ai=0.000366 Si=1.999509 i=106 ai=0.000361 Si=1.999869 i=107 ai=0.000355 Si=2.000224 求める i は 107 |
r = 1.8 のときは, 実行が i=10000 で打ち切られる.
課題 8.5
実数 x を入力し, x の平方根 r をニュートン法により求めるプログラム
newton2.c を作成せよ.
r の結果は小数点以下10桁まで出力すること.
(ニュートン法による平方根の計算法)
次のような結果が得られることを確認せよ
$ ./a x = 2 r = 1.5000000000, r*r = 2.2500000000 r = 1.4166666667, r*r = 2.0069444444 r = 1.4142156863, r*r = 2.0000060073 r = 1.4142135624, r*r = 2.0000000000 |
$ ./a x = 12345 r = 6173.0000000000, r*r = 38105929.0000000000 r = 3087.4999190021, r*r = 9532655.7498380095 r = 1545.7491498369, r*r = 2389340.4342215010 r = 776.8677842957, r*r = 603523.5542765057 r = 396.3792595897, r*r = 157116.5174329132 r = 213.7618370955, r*r = 45694.1229984419 r = 135.7565124511, r*r = 18429.8306728807 r = 113.3456882371, r*r = 12847.2450419486 r = 111.1301428125, r*r = 12349.9086415286 r = 111.1080577085, r*r = 12345.0004877518 r = 111.1080555135, r*r = 12345.0000000000 |
科目名: コンピュータ演習A 課題: C8 番号: 9999 氏名: 関学 太郎 作成: 20oo年oo月oo日 ------------------------------------------------------------- [課題 8.1] 〜を作成した. 実行結果は下記の通りである. (Cygwinの実行結果を貼り付ける) 〜で苦労した, 〜を工夫した, 等 ------------------------------------------------------------- ([課題 8.2] 以降も同様) ------------------------------------------------------------- [感想] (今回の課題に関する感想を書く) |