計算数学演習第4回

今日の演習

今日は以下の内容で演習を行います。
前回に引き続き重要な内容なので、集中して取り組んでください。

  • 繰り返し文(for文)

今日の目標

  • 繰り返し文(for文)の使い方を覚える
  • 繰り返し文を用いて初歩的な数学の問題を解く

繰り返し文

コンピューターは繰り返し処理が得意です。
人間のように飽きてしまうことなく、黙々と処理を繰り返してくれます。
例えば、画面に Hello! を10回表示したい場合、これまでの知識では次のプログラムとなります。

#include <stdio.h>
 
int main() {
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    printf("Hello!\n");
    
    return 0;
}

10回程度であれば、これでも良いかも知れませんが、100回表示せよとなると、
これではどうしようもありません(根気が必要です)。そこで、繰り返し文が登場します。

for 文

繰り返し文には for while があります。
まずは for 文を使ったプログラムを見てみましょう。
繰り返し文を使うと、先ほどのプログラムは次のようになります。
ファイル名を for-1.c として打ち込み、コンパイルし実行してください。

for-1.c

#include <stdio.h>
 
int main() {
    int i;
    
    for (i = 1; i <= 10; i++) {
        printf("Hello!\n");
    }
    
    return 0;
}

上のプログラムで、繰り返し文と呼ばれるのは

for (i = 1; i <= 10; i++) {
    printf("Hello!\n");
}

の部分です。
このように書くことで { } で囲まれたブロック文が10回繰り返され、先のプログラムと同様の結果が得られます。

 途中 i++ というものがありますが、これは i = i + 1 と同様であると思ってください。
i = i + 1 と書く場合、= が代入をあらわすことを思い出せば、左辺の i に i + 1 の結果を代入すると読め納得できます。(等号だと勘違いすると変なことになります。)

 for 文の括弧( )の中にはセミコロン ; で区切られた3つの式があります。
一般的には、セミコロンで区切られた三つの式は以下のように呼ばれています。
for (初期化式; 条件式; 変化式)
通常、for 文の中にあらわれる変数は整数型です(実数型の場合もあります)。

  • はじめの式(初期化式)は、 i = 1 となっています。ここで通常初期設定を行います。
    つまり、i の初期値を 1 と設定しています
  • 2つめの式(条件式)は、先ほどの条件分岐のところで現れた条件式と同じです。
    この場合 i <= 10 が真である間、ブロック文を繰り返せということを示しています。
  • 3つめの式(変化式)は、繰り返しの度に実行される式で i++ によって i が毎回1ずつ増えます。

結果、この for (i = 1; i <= 10; i++) は
「はじめに i を 1 とし、i が 10 以下である間ブロック文を繰り返し、繰り返しの度に i を1 ずつふやせ。」
と読むことができます。
繰り返しが少ない例について、実際どういう処理が行われているかを下に示します。

例えば、1~100までの間の数を表示するには次のようなプログラムになります。

for-1a.c

#include <stdio.h>
 
int main() {
    int i;
 
    for (i = 1; i <= 100; i++) {
        printf("%d\n", i);
    }
    
    return 0;
}

また、2~100までの間の偶数を表示するには次のようなプログラムになります。

for-1b.c

#include <stdio.h>
 
int main() {
    int i;
 
    for (i = 2; i <= 100; i = i + 2) {
        printf("%d\n", i);
    }
    
    return 0;
}

余裕があれば、同じ結果を出す他のパターンも考えてみてください。
ここでは、初期値を i = 2 とし、毎回の i の増やし方は i = i + 2 と2つずつ増やしています。
また、処理は i <= 100 が満たされている間繰り返されますから、2~100までの間の偶数が表示されます。

余談:変数の増やし方・減らし方

i++のように、次のような更新方法があります。

表記 同じ表現 意味
i++ i=i+1 iを1増やす
i-- i=i-1 iを1減らす
i+=a i=i+a iをa増やす
i-=a i=i-a iをa減らす
i*=a i=i*a iにaをかける
i/=a i=i/a iをaで割る
++i i=i+1 処理を行ってからiを1増やす
--i i=i-1 処理を行ってからiを1減らす

i++++iの違いは、次のようなプログラムを実行してみるとわかりやすいでしょう。

koushin_i.c

#include <stdio.h>

int main() {
    int i;

    // 初期化
    i = 1;
    printf("i = %d(初期化)\n", i);
    
    // Case 1: 表示の後に直接iを更新
    printf("i = %d(この後にiで1足す)\n", i);
    i = i + 1;
    
    // Case 2: 表示の前に直接iを更新
    i = i + 1;
    printf("i = %d(この前でiに1足す)\n", i);

    // 初期化
    i = 1;
    printf("i = %d(初期化)\n", i);

    // Case 1': 表示の後にiを更新
    printf("i = %d(この後でiに1足す)\n", i++);

    // Case 2': 表示の前にiを更新
    printf("i = %d(この前でiに1足す)\n", ++i);

    return 0;
}
    

 

プログラムの停止の仕方とファイルの消し方

プログラムは正しく動作し、正しく停止することが重要ですが、停止しないプログラムを書くのは大変簡単です。
停止しないプログラムはたいていの場合、プログラミングミスが原因です。
例えば、次のプログラムは停止しません。for-2.c として打ち込み実行してみてください。

for-2.c

#include <stdio.h>
 
int main() {
    int i;
    
    for (i = 1; i >= 1; i++)
    {
        printf("Hello!\n");
    }
    
    return 0;
}

条件式 i >= 1 が真でありつづけるため停止しないわけです。(無限ループと呼ばれます。)
(後に述べる扱える数値の大きさを超えるとおかしなことになるので、そこで停止する可能性はありますが・・。)
今後、色々なプログラムを作ってもらいますが、何らかのプログラミングミスで停止しないプログラムになっていて、それを実行してしまった場合は、
Ctrl + c  (Ctrl キーを押しながら c のキーを押す)
によって強制的に終了させることができます。覚えておいてください。
また、エラーのあるプログラムによっては core というファイル名のファイルを作成してしまう場合があります。
このファイルは、当面不要なので、消してしまいましょう(ファイルサイズが大きいので)。
以前、0 での割り算を行うプログラムを実行した人は、多分この core ファイルができているはずです。
次のサンプルプログラムは1~5までの和と積を計算し表示します。
ファイル名を for-3.c として打ち込み実行してください。

for-3.c

#include <stdio.h>
 
int main() {
    /* 変数の宣言 */
    int i, wa, seki;
    
    /* 変数の初期化(下の説明参照) */
    wa = 0;
    seki = 1;
    
    /* 繰り返し文:i が 1 から 5 になるまで繰り返し */
    for (i = 1; i <= 5; i++)
    {
        /* wa の計算:(古い)wa に i を加えた値を, wa に代入 */
        wa = wa + i;
        /* seki の計算:(古い)seki に i 掛けた値を, seki に代入 */
        seki = seki * i;
    }
    
    /* 結果を表示 */
    printf("和=%d\n", wa);
    printf("積=%d\n", seki);
    
    return 0;
}

このプログラムは大変短く簡単ですが、実はこのプログラムは数値計算プログラムの基本形と呼べるものです。
流れは、

  1. 利用する変数の初期化を行い
  2. 繰り返し文をもちいて
  3. 何らかの計算を繰り返し
  4. 結果を表示する

となっています。
このプログラムをよく見て、これまでの内容を疑問なく理解できているか確認してください。
(よく分からない人は必ず質問すること。)
変数は利用する前に必ず初期化(適切な値の代入)を行って下さい。
変数は用意した直後の内容は不定です。
つまり、なんらかの値を代入する前にその変数の保持している値が 0 である保証はありません。
例えば、先の和と積を求めるプログラムで wa =0, seki = 1 を忘れると思ってもいない結果になる可能性があります。
i に関しては for 文の中でまず i = 1 と初期化されるのでこの場合問題ありません。

また,先ほどの i = i+1 同様, wa = wa + i, seki = seki * i と書く場合、= が代入をあらわすことを思い出せば、左辺の wa (seki) に wa + i (seki * i) の結果を代入すると読め納得できます。
(等号だと勘違いす
ると変なことになります。)

課題1

for-3.c を改良して, 自然数 n を入力すると 1 ~ n までの和と積を表示するプログラムを作成せよ。
(注意:あまり大きな n を入力すると、特に積の値がコンピューターで扱える範囲を超えてしまうので、正確な値がでてこなくなります。それほど大きくない n で試してください。)

課題2

実数 a, 自然数 n を入力すると an を計算し表示するプログラムを作成せよ。
(注意:あまり大きな n を入力すると、特に積の値がコンピューターで扱える範囲を超えてしまうので、正確な値がでてこなくなります. それほど大きくない n で試してください。)

課題3

実数 a, 自然数 n を入力すると a + a2 + a3 + … + an を計算し表示するプログラムを作成せよ。

課題4

自然数 n を入力すると n 以下の 3 の倍数と 7 の倍数を表示するプログラムを作成せよ。(for 文と if 文を使う )

課題5

自然数 n を入力すると n が素数がどうか判定するプログラムを作成せよ。
以下、難しめの問題

課題6

三桁以下の(10進数の)自然数を入力したら、その数を二進数で表示するプログラムを作成せよ(for文を使って)
例: 三桁以下の自然数を入力してください:231 その数を二進数であらわすと11100111です。

課題7

7のn乗をAnとあらわすとする。下三桁が(943)となる最小のAnのnを求めよ。そのようなnが存在しない場合は、そのように出力せよ。
ヒント:条件をみたすnが存在しない場合は、943を含まない集合で閉じている(循環している)ことになる。つまり、少なくともn=〇までに943がでなければ、条件をみたすnが存在しないと言って良い。

intで扱える整数は、-2147483648から2147483647であることに注意。変数の値が2147483647を超えないように工夫しつつ、下三桁の値を調べていくこと。

課題8

自然数Mのn乗をMnとあらわすとする。三桁以下の自然数Mの入力を促し下二桁が(16)となる最小のMnのnを求めよ。そのようなnが存在しない場合は、そのように出力せよ。

課題9

xy平面上の曲線1:y=x*x と 曲線2:y=3+xはx>0の範囲で交点を一つもつ。
この交点のx座標を近似的に求めるプログラムを作成せよ。
ただし、正しい解とのずれは0.01以下であることが好ましい。
(ヒント:求め方は自由だが、xを少しずつ増やしていき、曲線1、曲線2の上下が入れ替わる場所を近似的に見つければ良い)

今日学んだ事

  • 繰り返し文の書き方

Department of Mathematical and Life Sciences, Graduate School of Integrated Sciences for Life, Hiroshima University