トラック5・📦変数・型・演算子

整数の割り算と剰余の罠

読む目安 約12分・ゴール:整数どうしの割り算が切り捨てになる理由を理解し、平均計算などで正しく対処できる

アプリでこのトピックを学ぶ(無料・登録不要)

このトピックの要点

ここは初心者が踏む地雷の中でも、特に命中率の高い場所です。落ち着いて一度体験しておけば、二度と踏みません。

7 ÷ 2 は 3 になる

#include <stdio.h>

int main(void) {
    int a = 7;
    int b = 2;

    printf("%d\n", a / b);
    printf("%d\n", a % b);
    return 0;
}

出力は 3 と 1 です。整数どうしの / は小数点以下を切り捨てた整数を返します。3.5 が四捨五入されて4になるのではなく、容赦なく3。そして % が余りの1を返します。

7 = 2 * 3 + 1。商と余りに分ける、小学校の割り算そのものです。

事件——平均点が合わない

#include <stdio.h>

int main(void) {
    int goukei = 173;
    int ninzuu = 4;
    double heikin = goukei / ninzuu;   // 事件現場

    printf("平均 %.2f\n", heikin);
    return 0;
}

期待は 43.25、実際の出力は 平均 43.00 です。原因は代入より前にあります。goukei / ninzuu の時点で両方とも整数なので整数の割り算が行われ、43 になってから double に入っている。受け皿を double にしても、こぼれた後では遅いのです。

対処は、割る前にどちらかを小数の世界へ移すこと。

・(double)goukei / ninzuu … キャストで明示的に変換する
・goukei / 4.0 … 定数なら小数で書く

% の使いどころ

・偶数か奇数か … n % 2 が0なら偶数
・倍数の判定 … n % 3 == 0 なら3の倍数
・桁の取り出し … n % 10 で一の位、n / 10 で残り
・単位の変換 … 200分なら 200 / 60 時間と 200 % 60 分

#include <stdio.h>

int main(void) {
    int fun = 200;

    printf("%d時間%d分\n", fun / 60, fun % 60);
    return 0;
}

出力は 3時間20分。整数の割り算は欠陥ではなく、使いどころのある道具です。

罠・注意

負の数は0の方向へ切り捨て。 -7 / 2 は -3(-3.5 が -4 ではなく -3)、-7 % 2 は -1 です。C99以降、この動きが標準で決まっています。

0で割ると異常終了。 / も % も同じです。割る前に確認します。

片方が小数なら全体が小数。 7 / 2.0 は 3.5 です。定数なら 2.0 と書くだけで直ります。

師範「切り捨てられた」のではない。「最初から整数の世界で計算していた」のじゃ。世界を変えたければ、割る前に変えよ。

まとめ

整数どうしの / は切り捨て、% は余り。受け皿を double にしても、計算の時点が整数なら手遅れです。(double) を割られる側に付けるか、定数を 2.0 と書きます。負の数は0方向へ切り捨て、0除算は事故です。

アプリでこのトピックを学ぶ(無料・登録不要)

確認問題

確認問題 1

int どうしの 7 / 2 の結果はどれですか。

  1. 3.5
  2. 4
  3. 3
  4. コンパイルエラー
答えを見る

正解:C(3)

整数どうしの割り算は、小数点以下を切り捨てた整数になります。3.5 が四捨五入されて4になるのではなく、容赦なく3です。余りが欲しいときは 7 % 2 で 1 が得られます。3.5 が欲しいなら 7 / 2.0 のように、割る前にどちらかを小数にします。

確認問題 2

トレース表の空欄を埋めてください。まだ値が決まっていない欄は - と書きます。d は小数第1位まで書きます。

#include <stdio.h>

int main(void) {
    int a = 7, b = 2;
    int q = a / b;
    int r = a % b;
    double d = a / b;
    printf("%d %d %.1f\n", q, r, d);
    return 0;
}
行qrd
5?--
631-
731?
答えを見る

空欄の答え(上から順に):3、3.0

5行目は int どうしの割り算なので 3(切り捨て)。7行目は受け皿が double でも、右辺 a / b の時点で両方 int なので 3 が計算され、それが 3.0 として入ります。受け皿を変えても手遅れという、この章いちばんの罠です。3.5 にしたければ (double)a / b と、割る前に変換します。

「変数・型・演算子」の目次

  1. 変数とは名前付きの箱
  2. int型と整数の世界
  3. 浮動小数点数 float / double
  4. char型と文字コード
  5. bool型と真偽——C23標準の書き方
  6. 定数——const と constexpr
  7. 算術演算子と優先順位
  8. 整数の割り算と剰余の罠
  9. 型変換——暗黙と明示
  10. 2進数・16進数リテラル(0b / 0x / 桁区切り')
  11. sizeofとメモリ上のサイズ
  12. オーバーフローという事件

もっと先へ:ポインタ・メモリ・ファイル入出力・セキュアコーディングを含む全26トラックと、段位検定・模試のフルセットは完全版に収録しています。

完全版の販売ページは準備中です。

ほかのトラック

📚 姉妹教材:手を動かして覚える Linux 教材 — Linuxとインフラの仕組みを地図で学ぶ

Web版