【例題】1からnまでの自然数の総和を求めよう

例題として、1からnまでの自然数の総和を求めるプログラムについて考えてみましょう。

for文の解説において用いた事例なのですが、関数化や処理速度の向上などをおこなってみましょう。

動かしてみよう

サンプルコードを動かしてみましょう。

サンプルではsum関数を作成し、その機能によって総和を求めています。

解説

ではサンプルコードの要点をみてみましょう。

/* プロトタイプ宣言 */
int sum(int n);

これは関数のプロトタイプ宣言ですね。
main関数内でsum関数を用いていますが、sum関数の定義がmain関数よりも後ろで実装されているため、『sum関数っていうのがあるよ。』と事前に書いておく必要があります。(逆にいうと、main関数の前にsum関数を書くのであれば省略してよい記述です。)

また、プロトタイプ宣言からわかるとおり、sum関数は引数nを入力として持ち、演算結果を戻り値として返します。

続いてmain関数内の下記。

scanf("%d", &n);
result = sum(n);

scanfによって入力で受けとった数値を変数nに格納しています。
そして変数nを関数sumに入力し、結果を変数resultに格納しています。

sum関数の中身については、for文で説明した内容が関数化されているだけですね。

    for(int count = 1; count <= n; count++ )
    {
        result += count;
    }

カウンタ変数count が 引数n に達するまで、for文の処理を繰り返します。
またfor文内では、代入演算子+=(代入演算参照)を用いて、現在の result に count を都度積み重ねていくような処理をおこなわせています。

    return result;

そして演算した結果を return を用いて、main関数へ返しています。
main関数では受け取った結果をprintfによって、出力欄へ表示させています。

処理速度を向上させよう

さきほどのサンプルコードは、1〜nまでの総和を求めるという機能を十分に満足していました。
ただし、処理速度の面ではどうでしょうか。

たとえば、10000までの総和を演算することを想定した場合、下記のプログラムが実行されることになります。

    for(int count = 1; count <= 10000; count++ )
    {
        result += count;
    }

ソースコード上は4行程度で大したことがないように見えますが、このソースコードを実行するCPUは下記のように10000回も加算処理をおこないます。

count = 1;
 result = 0 + 1 = 1;
count = 2;
 result = 1 + 2 = 3;
count = 3;
 result = 3 + 3 = 6;
 ・・・
count = 10000
 result = 49995000+10000 = 50005000;

これでは大変ですし、時間もかかりそうですね。

ここで1つ考える必要があるのですが、1〜nまでの総和を求めるというお題が出た場合、プログラムは1〜nまでを全て足すようなアルゴリズムとしなければならないのでしょうか。

答えはNoです。

お題をそのままアルゴリズム化する必要などなく、正確な答えが求まりさえすれば何の問題もありません。
また処理速度が早いのであれば、それに越したことはありません。

ご存知の方もいると思いますが、1〜nまでの総和演算には下記の公式が存在します。

1+2+・・・+n = n(n+1)/2

では総和を求めるプログラムを上記の公式を用いて作成しなおしてみましょう。

実行してみると、最初のサンプルコードと同じ結果が得られることがわかると思います。
また、ソースコード自体もsum関数がたった1行になり、とてもシンプルになりました。
加えて、自然数nの値に関わらず加算・乗算・除算を1度おこなうだけで解が求まるアルゴリズムになりましたので、処理速度の向上も期待できます。

今後、なにかの課題を解く際には、別の解法がないか考えてみるようにしてみてください。

以上です。
ではまた。

タイトルとURLをコピーしました