2004 年度「計算機基礎論3B」 2004-10-29

(続き)

sum = sum + i」も同様。 ++, -- については K&R2 §2.8 に述べられている。

上のプログラムで入力する数を 10, 100, 1000, 10000, ... のようにだんだん大きくしてゆくと、 どこかで int 型の限界を越えて答えがおかしくなる。 その場合でもエラーメッセージなどは一切出ない。 (やってみよう。)

この例では for を使うほうが自然であろうが、 while を使って書いてみたのが次である。

#include <stdio.h>  /* ユーザが数を入力すると,1 からその数までの和を出力 */

main() {
    int i, n, sum;

    printf("いくつまで足しますか?\n");
    scanf("%d", &n);

    sum = 0;
    i = 1;

    while (i <= n) {
        sum = sum + i;
        i++;
    }
    printf("1 から %d まで足すと %d です.\n", n, sum);
}

練習問題

#include <stdio.h>

main() {
    int i;

    for (i = 0; i < 10; i++) {
        printf("i の値は %d です.\n", i);
    }
}

これを改造してみよう。

次のプログラムは、 誤差の関係で、想像されるようには動かない。 (想像してから動かしてみよ。)

#include <stdio.h>

main() {
    double x;

    for (x = 0; x < 1; x = x + 0.1) {
        printf("x の値は %f です.\n", x);
    }
}

ループ(続き)

アラレ(霰)数とは

という漸化式で定義される数列である。 この数列は、初項がいかなる自然数であってもそのうち 1, 4, 2, 1, 4, 2, ... というループに落ち着くであろうと予想されているそうだ。

次のプログラムは、ユーザが入力した数から始めて 1 になるまで、 この数列を出力する。 ここでは while を使うほうが自然であろう。

#include <stdio.h>  /* アラレ数 */

main() {
    int n;

    printf("自然数を入れてください.\n");
    scanf("%d", &n);
    while (n != 1) {
        if (n % 2 == 0) {       /* n が偶数のとき */
            n = n / 2;
        } else {                /* n が奇数のとき */
            n = 3 * n + 1;
        }
        printf("%d ", n);
    }
    printf("\n");
}

※ 入力した数が大きすぎたり、負の数を入力したりすると、 無限ループに陥ることがある。 そのばあいは Ctrl+CCtrl を押しながら C)を押す。 プログラムは Ctrl+C で中止できることが多いから、 必ず慣れておくこと。

※ ここで中カッコが入れ子になった場合のインデントのしかたを説明する。 上のプログラムの while の部分で確かめてみるとよい。

  1. { の直後で改行し、 次の行はその行の頭よりも Tab 一つ分(ここでは空白四文字分)下げて始める。
  2. } を打つときは、 対応する { の行の(空白以外の)頭の文字とそろえる。
  3. その他の行の頭は前の行とそろえる。
この方針を守っていれば、「ある中カッコとペアになる中カッコをさがす」 ことや「ある文を囲む最小の中カッコをさがす」ことはきわめて容易である。

#include <stdio.h>  /* 自然対数の底 e の計算 */

main() {
    int n;
    double sum, factorial;

    sum = 1;
    factorial = 1;

    for (n = 1; n < 24; n++) {
        factorial = factorial * n;
        sum = sum + 1 / factorial;
        printf("第 %d 項までの和は %.53f です.\n", n, sum);
    }
}
自然対数の底 e を e = 1/0! + 1/1! + 1/2! + 1/3! + ... として計算している。 C言語には階乗を表わす演算子はないので自力で計算しなければならない。 ここでは n! を計算した結果を捨てないで次の (n+1)! の計算に使っている。

factorial = factorial * n」のところでは double 型と int 型とを掛けている。 この場合、結果は double 型になる。 C言語はこのあたりが煩雑である。 K&R2 §2.7, A6 に出ているが、 とりあえずは intdouble しか使わないので 「intdouble との演算結果は double になる」 とだけ覚えておけばよい。

※ 岩波「数学辞典第3版」1434 ページによれば e = 2.7182818284590452353... であり、 上のプログラムの計算結果は途中で違っている。 コンピュータの計算は近似計算なので、 むやみに桁数を多く表示させても意味がないときもある。

「かつ」や「または」は次のように書く。 これらは forwhile の条件部にも使える。 K&R2 では §2.6 を見よ。

    if ((x > 0) && (x < 8)) {       /* 「かつ」 */
        ........
    }

    if ((x < 0) || (x > 2)) {       /* 「または」 */
        ........
    }
なお、x > 0 などを囲んでいる小カッコは実は不要である。 これについての詳細は K&R2 §2.12 を参照。

※ 「かつ」も「または」も同じ文字を二つ打つことに注意。 まちがって「&」「|」をひとつだけ書いた場合、 それらにも意味があるのでコンパイラはエラーメッセージを出さない (かもしれない)。

二重ループ

次のプログラムは九九の表を出力する for を二重に使っていること以外は、 いままでに習ったことでわかると思う。

#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");
    }
}

練習問題

全部やらなくても構いません。 むずかしさはまちまちです。


岩瀬順一