(20.1) アラレ(霰)数とは、
(20.2) 次のプログラムは、ユーザが入力した数から始めて 1 になるまで、 この数列を出力する。 for の小カッコの中は二つのセミコロンで三つに区切られるが、 何もない部分は空白にしておくことができる。 下の例では継続条件しかない。 (こういった場合、while を使うほうがはるかに自然である。)
#include <stdio.h> /* アラレ数 */ main() { int n; printf("自然数を入れてください.\n"); scanf("%d", &n); for ( ; n > 1; ) { if (n % 2 == 0) { /* n が偶数のとき */ n = n / 2; } else { /* n が奇数のとき */ n = 3 * n + 1; } printf("%d ", n); } printf("\n"); }
(20.3) この例では中カッコが入れ子になっている。 その場合のインデントの(一つの)やり方は以下の通りである。 上のプログラムで確かめよ。
(20.4)
自然対数の底 e を e = 1/0! + 1/1! + 1/2! + 1/3! + ...
として計算するプログラムである。
階乗は、C言語には用意されていないので、自力で計算しなければならない。
#include <stdio.h> /* 自然対数の底 e の計算 */ main() { int n; double sum, factorial; sum = 1; factorial = 1; for (n = 1; n < 23; n++) { factorial = factorial * n; sum = sum + 1 / factorial; printf("第 %2d 項までの和は %.53f です.\n", n, sum); } }
(20.5) int 型と double 型をいっしょに使うときはこのように宣言する。 順序は逆でも構わない。 %2d は「二ケタの幅で表示せよ」の意味、 %.53f は「小数点以下 53 ケタで表示せよ」の意味である。 このプログラムでは double 型と int 型との間で四則演算を行なっている。 その場合、結果は double 型になる。 くわしくは K&R2 §2.7, A6 を参照のこと。
(20.6) ※ センターの linux 上のCコンパイラでは、 第 3 項までの和 1+1+1/2+1/6 = 2+2/3 の小数点以下十数ケタ目ですでに違っている。 よって、 上のプログラムの計算結果は小数点以下十数ケタ目あたりまでしか信頼できない。 コンピュータの計算は近似計算なので、 むやみに桁数を多く表示させても意味がないときがある。 53 ケタ目まで表示させたのはそのことを知ってもらうためにすぎない。 (岩波「数学辞典第3版」1434 ページによれば e = 2.7182818284590452353... である。)
(20.7) ※ 計算は第 22 項までで打ち切っているが、これは試行錯誤をくり返しながら決めたもの。 「収束したら打ち切る」とすることもできなくはないが。
(20.8) 「かつ」や「または」は次のように書く。 これらは for の継続条件にも使える。 K&R2 では §2.6 を見よ。
if ((x > 0) && (x < 8)) { /* 「かつ」 */ ........ } if ((x < 0) || (x > 2)) { /* 「または」 */ ........ }x > 0 などを囲んでいる小カッコは実は不要である。 これについての詳細は K&R2 §2.12 を参照。 「0 < x < 8」はC言語でも意味のある式だが、 数学とは意味が異なるので上の意味では使えない。
(20.9) 「かつ」も「または」も同じ文字を二つ打つことに注意。 まちがって「&」「|」をひとつだけ書いた場合、 それらにも意味があるのでコンパイラはエラーメッセージを出さない (かもしれない)。
(21.1) 次のプログラムは九九の表を出力する。 for を二重に使っていること以外は、 いままでに習ったことでわかると思う。
(21.2) 二重ループについて説明する。 まず外側のループから始まる。 最初は i が 1 で、 外側のループの中カッコにはいる。 するとそこに内側のループがあり、 j が 1 から 9 までこの内側のループを回る。 それが済んで改行を出力すると外側のループの中カッコの中がおわる。 そこで外側のループの再初期化にゆき、 i が 1 だけ増えて 2 になる。 これを i が 9 になるまでくり返す。
#include <stdio.h> main() { int i, j; for (i = 1; i <= 9; i++) { for (j = 1; j <= 9; j++) { printf(" %d", i*j); } printf("\n"); } }
(21.3) 次は、素因数分解のプログラム。 三重ループになっている。 素因数が見つかるまで 2, 3, 4, ... と順に割ってみる素朴なやり方なので、 素因数分解される数が一億ぐらいになるとちょっと時間がかかる場合がある。 (これは、ここまでの知識だけを使って“強引に”書いてみたプログラムなので、 あまりうまくないと思う。 読んで理解できなくても心配する必要はないし、 まねするのがいいかどうかもわからない。)
#include <stdio.h> #define FROM 1 /* この数から */ #define TO 100 /* この数まで */ main() { int n, m, p, i; for (n = FROM; n <= TO; n++) { /* n を素因数分解する */ printf("%d =", n); for (m = n; m != 1; m = m/p) { /* m を割る最小の素数を p に入れる */ p = 0; /* 0 は「まだはいっていない」の印 */ for (i = 2; p == 0; i++) { /* 2, 3, 4, ... と順に割ってゆく */ if (m % i == 0) { /* 割り切れたら */ p = i; /* p に格納 */ } } printf(" %d", p); } printf("\n"); } }
全部やらなくても構いません。 むずかしさはまちまちです。
1 から 1 まで足すと 1 です. 1 から 2 まで足すと 3 です. .... 1 から 10 まで足すと 55 です.と出力されるようにせよ。
ツルとカメを合わせて何匹いますか? 5 足は何本ですか? 16 ツル 0 匹、カメ 5 匹のとき足は 20 本で、これは答えではありません。 ツル 1 匹、カメ 4 匹のとき足は 18 本で、これは答えではありません。 ツル 2 匹、カメ 3 匹のとき足は 16 本で、これが答えです。 ツル 3 匹、カメ 2 匹のとき足は 14 本で、これは答えではありません。 ツル 4 匹、カメ 1 匹のとき足は 12 本で、これは答えではありません。 ツル 5 匹、カメ 0 匹のとき足は 10 本で、これは答えではありません。
| 1 2 ... 9 ---+--------...---- 1 | 2 | : : 9 |のように被乗数・乗数を左と上に出力するようにしてみよ。
0 は偶数です. 1 が奇数です. 2 は偶数です. ... 9 は奇数です. 10 は偶数です.のように出力されるプログラムを書け。
for (i = 0; i < 10000; i++) { for (j = 0; j < 10000; j++) { sum = sum + (i + j); /* 意味のない適当な計算 */ } }はどのくらい時間がかかるか? 回数を変えていろいろ調べてみよ。