先頭へ戻る

計算の仕方 | Programming Place Plus C言語編 第4章

Programming Place Plus トップページC言語編

先頭へ戻る

この章の概要

この章の概要です。


計算をさせる

プログラムを書いて、コンピュータに行わせる最も代表的な仕事は「計算」でしょう。計算を行うプログラムの書き方を知っておかないと、恐らくほとんどのプログラムは書けません。

まずは最も基本的な四則演算(足し算・引き算・掛け算・割り算)をしてみましょう。

一般的には、加算(足し算)には「+」、減算(引き算)には「-」、乗算(掛け算)には「×」、除算(割り算)には「÷」を使います。この中で、「×」と「÷」については、C言語では別の記号を使います。乗算は「*」、除算は「/」です

ここまでに登場した「+」「-」「*」「/」といった、計算に使う記号類を、C言語では演算子と呼びます。「演算」とは「計算」のことです。他にも演算子はいくつもあります。

実際にこれらの演算子を使ったプログラムは次のようになります。

#include <stdio.h>

int main(void)
{
    int sum = 10 + 20;
    int sub = 10 - 20;
    int mul = 10 * 20;
    int div = 10 / 20;

    printf( "sum: %d\n", sum );
    printf( "sub: %d\n", sub );
    printf( "mul: %d\n", mul );
    printf( "div: %d\n", div );

    return 0;
}

実行結果:

sum: 30
sub: -10
mul: 200
div: 0

ここで登場する演算子は、「オペランド」「演算子」「オペランド」という並びで記述して使います。オペランドというのは、演算子の効果の対象になる値や変数のことです。オペランドと演算子の間に開ける空白は、あってもなくても問題ありません。

計算結果を使って、変数を初期化できますし、代入もできます。また、次のプログラムのように、計算結果を変数に入れずに使うことも可能です。

#include <stdio.h>

int main(void)
{
    printf( "sum: %d\n", 10 + 20 );
    printf( "sub: %d\n", 10 - 20 );
    printf( "mul: %d\n", 10 * 20 );
    printf( "div: %d\n", 10 / 20 );

    return 0;
}

実行結果:

sum: 30
sub: -10
mul: 200
div: 0

この場合、計算結果が直接、printf関数の “%d” の部分にあてはめられます。

【上級】正確に言えば、計算結果が printf関数へ渡され、printf関数の内部の処理で使用されるという流れです。関数に値を渡すという考え方については、第9章で説明します。


符号

マイナスの値(負数)を表現したいときは、数値の頭に「-」を付加します。

#include <stdio.h>

int main(void)
{
    printf( "%d\n", -10 );

    return 0;
}

実行結果:

-10

この「-」は単なるマイナスの符号のようですが、扱いとしては、単項マイナス演算子という演算子の一種です。

単項マイナス演算子は、数値の符号を反転させます。数値をマイナスにするのではないということは抑えておきましょう。たとえば、負数が入っている変数に対して単項マイナス演算子を使ったら、その結果は正の数になります。

#include <stdio.h>

int main(void)
{
    int num = -10;

    printf( "%d\n", -num );  // -10 の符号が反転して +10 になる

    return 0;
}

実行結果:

10

「+」で表現される、単項プラス演算子もあります。こちらも数値に対して使える演算子ですが、特に値を変化させません。単に「-」に対応させて存在している演算子であって、通常、使う必要はありません。

#include <stdio.h>

int main(void)
{
    int num = +10;  // + に特に意味はない。10 と同じ

    printf( "%d\n", +num );  // + に特に意味はない。num の値が出力される

    return 0;
}

実行結果:

10

【上級】単項プラス演算子、単項マイナス演算子ともに、オペランドは算術型(型の分類表)でなければなりません。オペランドには整数拡張(第21章)が行われ、結果の型は拡張後の型です。

除算の結果

先ほどのサンプルプログラムの実行結果の中で、除算の結果には注目しておくべきでしょう。「10 / 20」の結果が、「0.5」ではなく「0」となっています。

printf関数の “%d” は整数で出力を行う指示なので、実行結果が整数になるのは当然なようではありますが、仮に指定を “%f” に変えたとしても、やはり結果は 0 になります。

#include <stdio.h>

int main(void)
{
    printf( "div: %f\n", 10 / 20 );

    return 0;
}

実行結果:

div: 0.000000

このように、整数同士の除算では、結果の小数点以下は切り詰められて、整数になります。 このサンプルプログラムの場合は、「10 / 20」の結果が「0」になり、これを “%f” で出力しようとしたため、0.000000 という結果になります。

ところで、小数点以下を捨てる具体的な方法がいくつかあり得そうです。たとえば、1.5 を 1 にするのか 2 にするのか、-1.5 なら -1 なのか -2 なのかといったことです。C言語では、0 に近いほうへ切り詰められます。よって、1.5 は 1 になり、-1.5 は -1 になります。

ゼロ除算

除算に関しては注意しなければならないことがあります。C言語に限らない話ですが、多くのプログラミング言語では、何かを 0 で割る行為は禁止されています。たとえば「10 / 0」のような演算の結果は、未定義です。

未定義というのは、「どうなるか決まっていない」ということです。ですから、「多分、結果は 0 になるだろう」といった、勝手な予測をしてはいけません。C言語には、未定義とされていることがいくつかありますが、こういったプログラムを書いてはいけません。

「10 / 0」のように、はっきりと「/ 0」と書く場合には気が付きやすいですが、変数に代入された 0 をうっかり使ってしまうことがあるので、注意が必要です。次のようなプログラムは正しくありません。

#include <stdio.h>

int main(void)
{
    int num = 0;
    int ans = 10 / num;

    printf( "ans: %d\n", ans );

    return 0;
}

実行結果:

この場合、変数num には 0 が入っているため、結局、「10 / 0」という計算を行っていることになります。

ゼロ除算の結果は未定義なので、このプログラムを実行すると何が起こるか分かりません。異常停止するかもしれませんし、おかしな結果が出力されるかもしれませんし、単に 0 になるだけかもしれません(異常な動作をすると分かっていても、学習のためには、試しに実行してみて欲しいと思います。どんなことが起こるのか理解しておかないと、実際にトラブルが起きたときにパニックになるでしょうから)


少し複雑な計算

演算子は、1つの文の中で複数回使っても構いません。たとえば「10 * 2 + 5」のような式は許されています。このような場合、数学と同じで、乗算や除算の方が、加算や減算よりも優先されます。また、やはり数学と同じく、( ) で囲めば、その部分の計算を優先させられます

#include <stdio.h>

int main(void)
{
    int ans1 = 10 * 2 + 5;
    int ans2 = 10 * (2 + 5);

    printf( "ans1: %d\n", ans1 );
    printf( "ans2: %d\n", ans2 );

    return 0;
}

実行結果:

ans1: 25
ans2: 70

( ) で囲った部分が先に計算されています。( ) は複数使うこともできますし、( ) の中にさらに ( ) があっても構いませんが、{ } や [ ] のようないわゆる中括弧や大括弧は使えません

なお、1つの式の中に優先順位が同じ部分が複数ある場合、たとえば「10 * 5 + 10 / 5」のような場合に、「10 * 5」と「10 / 5」のどちらが先に計算されるかは決まっていません。左から右という規則はC言語にはないので注意しましょう。

どちらから計算されても同じように思えるかもしれませんが、違いが生まれてしまうケースがあるので、順番に規則がないことは覚えておいた方がよいでしょう。

printf などの関数でも ( ) を使っているので、ややこしく感じるかもしれません。これはある意味で正しい感覚で、実際、( ) が大量に出てくると見づらくなります。

#include <stdio.h>

int main(void)
{
    printf( "ans: %d\n", (10 + 5) / (10 - (3 + 2)) );

    return 0;
}

実行結果:

ans: 3

プログラミングの世界では、読み易さは重要視されます。自分が読みづらいと感じるようなら、他の人が見ても読みづらい可能性は高いでしょうから、改善策を探すことを心がけるべきです。たとえば、いったん、変数に計算の途中経過を入れてやるという方法が考えられます。

#include <stdio.h>

int main(void)
{
    int num1 = 10 + 5;
    int num2 = 10 - (3 + 2);
    int ans  = num1 / num2;

    printf( "ans: %d\n", ans );

    return 0;
}

実行結果:

ans: 3

無闇に変数の個数を増やすと、かえって分かりづらくなる可能性もありますが、変数には名前を付けられるので、うまくすれば、読みやすいプログラムにできます。

【上級】また、定義する変数が増えると、メモリの使用量が増えたり、実行速度に影響を与えたりする可能性があります。ただ、ほとんどの場合、大きな問題になることはありません。

剰余の求め方

四則演算のついでに、除算の余り(剰余)の求め方にも触れておきます。C言語では剰余を簡単に求められるように、専用の演算子「%」が用意されていますから、これを使うだけです。

「%」のオペランドはいずれも、整数でなければなりません。たとえば、「10.0 / 3」のような式は正しくなく、コンパイルエラーになります。

なお、「%」の演算の優先順位は「*」や「/」と同じで、「+」や「-」よりも優先されます

結果の符号については、左側のオペランドと同じになります。

また、剰余の場合も、0 で割る行為の結果は未定義なので注意してください

#include <stdio.h>

int main(void)
{
    printf( "%d\n", 10 % 3 );
    printf( "%d\n", 10 % -3 );
    printf( "%d\n", -10 % 3 );
    printf( "%d\n", -10 % -3 );

    return 0;
}

実行結果:

1
1
-1
-1


練習問題

問題① 4分31秒を、秒に変換した結果を出力するプログラムを作ってください。

問題② 502秒を、分と秒に変換した結果を出力するプログラムを作ってください。

問題③ 3÷2の結果を、1のような整数ではなく、1.5のような浮動小数点数で出力できるようにプログラムを作ってください。

問題④ 567という整数の10の位だけ(つまり6)を取り出して出力するにはどうすればいいでしょう。

問題⑤ 次のプログラムには問題があります。指摘してください。

#include <stdio.h>

int main(void)
{
    int a = 0;
    int b = 10;
    int c = 20;

    printf( "%d * %d = %d\n", a, b, a * b );
    printf( "%d / %d = %d\n", c, a, c / a );
    printf( "%d + %d = %d\n", b, c, b + c );

    return 0;
}


解答ページはこちら

参考リンク


更新履歴

’2018/6/15 第8章から練習問題②を移動してきて、練習問題⑤とした。

’2018/5/3 「剰余の求め方」の項を修正。結果の符号について追記し、サンプルプログラムもそれに合わせて変更した。

’2018/4/2 「VisualC++」という表現を「VisualStudio」に統一。

≪さらに古い更新履歴を展開する≫



前の章へ (第3章 変数)

次の章へ (第5章 コメントの書き方)

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
Twitter でツイート Twitter をフォロー LINE で送る
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー