C言語を学習する際、避けて通れないのが算術演算です。

加減乗除の四則演算は直感的で分かりやすいものですが、プログラミング特有の演算として非常に重要な役割を果たすのが「剰余演算」です。

剰余演算とは、割り算を行った際の「余り」を算出する操作を指します。

C言語では 剰余演算子「%」 を使用してこの計算を行いますが、単純な数値計算以外にも、偶数・奇数の判定やデータのループ処理など、多岐にわたるアルゴリズムで活用されます。

本記事では、C言語における余りの求め方について、基本から応用、そして注意点までを詳しく解説します。

C言語における割り算と余りの基本

C言語で数値を扱う際、整数同士の割り算と浮動小数点数を含む割り算では、その挙動が大きく異なります。

まずは、整数型を対象とした基本的な割り算と剰余演算の仕組みを整理しましょう。

算術演算子としての「%」

C言語において、余りを求めるために用意されているのが 剰余演算子(モジュロ演算子)である「%」 です。

この演算子は、左側の数値を右側の数値で割った際の「余り」を返します。

例えば、7 % 3 という式の結果は、7を3で割った商が2で余りが1となるため、1 となります。

一方で、割り算の「商」を求めたい場合には、スラッシュ / を使用します。

C言語の整数同士の演算では、割り切れない場合の小数点以下は切り捨てられるという特徴があります。

整数同士の割り算の仕組み

C言語の整数型(int型など)同士で割り算を行うと、結果も整数として返されます。

これを 「整数除算」 と呼びます。

  • 10 / 3 の結果は 3 (小数点以下は切り捨て)
  • 10 % 3 の結果は 1 (余り)

このように、商と余りを組み合わせて考えることで、元の数値を復元することができます。

具体的には、「(割られる数) = (商) * (割る数) + (余り)」 という数式が成り立ちます。

この関係性は、アルゴリズムの整合性を保つ上で非常に重要です。

剰余演算子「%」の具体的な使い方

それでは、実際にプログラムの中でどのように % 演算子を使用するのか、具体的なソースコードを見ていきましょう。

基本的なソースコード例

以下のプログラムは、ユーザーから入力された2つの整数に対して、商と余りを計算して表示するシンプルな例です。

C言語
#include <stdio.h>

int main(void) {
    int a, b;
    int quotient, remainder;

    // ユーザーからの入力を受け取る
    printf("割られる数を入力してください: ");
    scanf("%d", &a);
    printf("割る数を入力してください: ");
    scanf("%d", &b);

    // 0による割り算を防止
    if (b == 0) {
        printf("エラー:0で割ることはできません。\n");
        return 1;
    }

    // 商と余りを計算
    quotient = a / b;
    remainder = a % b;

    // 結果を出力
    printf("%d ÷ %d = %d 余り %d\n", a, b, quotient, remainder);

    return 0;
}
実行結果
割られる数を入力してください: 17
割る数を入力してください: 5
17 ÷ 5 = 3 余り 2

偶数・奇数の判定への応用

剰余演算の最も代表的な活用例が、偶数か奇数かの判定 です。

ある整数を2で割った時の余りが0であれば「偶数」、1であれば「奇数」であると判断できます。

C言語
#include <stdio.h>

int main(void) {
    int num = 15;

    if (num % 2 == 0) {
        printf("%d は偶数です。\n", num);
    } else {
        printf("%d は奇数です。\n", num);
    }

    return 0;
}
実行結果
15 は奇数です。

この手法は、例えば「表の行の色を一行おきに変える処理」や「特定の回数ごとに処理を実行する」といった場面で非常に重宝されます。

周期的な処理(ループ・配列)への応用

剰余演算は、数値を特定の範囲内で循環させたい場合にも便利です。

例えば、配列のインデックスを 0, 1, 2, 0, 1, 2… と繰り返したい場合、インデックスをインクリメントした後に 配列サイズで剰余を取る ことで簡単に実装できます。

C言語
#include <stdio.h>

int main(void) {
    int i;
    int max_index = 3;

    for (i = 0; i < 10; i++) {
        // 0, 1, 2 を繰り返す
        printf("%d ", i % max_index);
    }
    printf("\n");

    return 0;
}
実行結果
0 1 2 0 1 2 0 1 2 0

このように、剰余演算を使うことで複雑な if 文による分岐を書くことなく、簡潔に周期性を表現できます。

浮動小数点数(float/double)で余りを求める方法

C言語の % 演算子には大きな制約があります。

それは、「整数型にしか使用できない」 という点です。

float 型や double 型に対して % を使用しようとすると、コンパイルエラーが発生します。

「%」が使えない理由

C言語の設計上、% 演算子は整数演算における「余り」を定義しています。

浮動小数点数の場合、計算結果は常に精密な値(あるいは近似値)として求められるため、一般的な意味での「整数としての余り」という概念がそのままでは適用できません。

しかし、実務では「5.5を1.2で割った時の余り」が必要になるケースもあります。

fmod関数の使い方と注意点

浮動小数点数で余りを求めるには、標準ライブラリの math.h で定義されている fmod関数 を使用します。

  • プロトタイプ宣言:double fmod(double x, double y);
  • 機能:x / y の浮動小数点余りを計算します。

fmod関数のサンプルコード

C言語
#include <stdio.h>
#include <math.h> // fmodを使用するために必要

int main(void) {
    double x = 5.5;
    double y = 1.2;
    double result;

    // 浮動小数点数の剰余を計算
    result = fmod(x, y);

    printf("%f を %f で割った余りは %f です。\n", x, y, result);

    return 0;
}
実行結果
5.500000 を 1.200000 で割った余りは 0.700000 です。

fmod関数 を使用する際は、コンパイル時に数学ライブラリをリンクする必要がある場合があります(gcc等の環境では -lm オプションを付けるのが一般的です)。

剰余演算を利用する際の注意点

剰余演算は非常に便利ですが、プログラムを不安定にする落とし穴も存在します。

特に以下の3点には注意が必要です。

ゼロ除算(Division by Zero)の回避

割り算全般に言えることですが、「0で割る」操作は絶対に避けてください。

C言語において、a % 0 を実行するとプログラムは異常終了(ランタイムエラー)します。

ユーザーからの入力を直接演算に使用する場合は、必ず事前に「割る数(分母)」が0でないかをチェックするバリデーションを実装しましょう。

負の数が含まれる場合の挙動

負の数に対する剰余演算の結果は、C言語の規格(C99以降)で明確に定義されています。

「余りの符号は、割られる数(左オペランド)の符号と一致する」 というルールです。

結果理由
10 % 31両方正
-10 % 3-1割られる数が負
10 % -31割られる数が正
-10 % -3-1割られる数が負

古いコンパイラや他のプログラミング言語(Pythonなど)では、負の数の余りの扱いが異なる場合があるため、移植性の高いコードを書く際は注意が必要です。

演算子の優先順位

剰余演算子 % は、乗算 * や除算 /同じ優先順位 を持っています。

また、これらは加算 + や減算 - よりも優先されます。

例:5 + 10 % 3 この場合、先に 10 % 3 が計算されて 1 となり、その後に 5 + 1 が計算されるため、結果は 6 となります。

意図しない順序で計算されるのを防ぐため、複雑な式では括弧 () を活用しましょう。

応用編:剰余演算を活用したアルゴリズム

実務レベルで剰余演算がどのように使われるか、具体的なアルゴリズムを見ていきます。

単位の変換(秒から分・秒への変換など)

総秒数を「分」と「秒」に分解する処理は、商と余りの典型的な活用例です。

C言語
#include <stdio.h>

int main(void) {
    int total_seconds = 3661;
    int hours, minutes, seconds;

    // 1時間は3600秒
    hours = total_seconds / 3600;
    // 残りの秒数を計算
    int remaining_seconds = total_seconds % 3600;

    // 残りの秒数から分を計算
    minutes = remaining_seconds / 60;
    // 最終的な秒数を計算
    seconds = remaining_seconds % 60;

    printf("%d秒は、%d時間 %d分 %d秒です。\n", total_seconds, hours, minutes, seconds);

    return 0;
}
実行結果
3661秒は、1時間 1分 1秒です。

桁の抽出

特定の数値から「1の位」や「10の位」を取り出したい場合にも剰余が役立ちます。

  • num % 10 : 1の位を取得
  • (num / 10) % 10 : 10の位を取得

これを利用すると、数値を一桁ずつ分解して処理するアルゴリズム(各桁の和を求める、回文数判定など)が実装可能です。

商と余りを同時に求める div 関数

C言語の標準ライブラリ stdlib.h には、商と余りを一度に計算する div 関数が用意されています。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    div_t result = div(17, 5);

    printf("商: %d, 余り: %d\n", result.quot, result.rem);

    return 0;
}
実行結果
商: 3, 余り: 2

div_t という構造体に結果が格納されます。

大きな数値を扱う場合には ldiv (long型用)なども存在します。

一部のプロセッサでは、除算命令を一度実行するだけで商と余りが同時にレジスタに格納されるため、個別に /% を呼ぶよりも効率的な場合があります。

まとめ

C言語における剰余演算子 「%」 は、単に割り算の余りを出すだけでなく、プログラムの論理構造を構築するための強力なツールです。

本記事で解説した主なポイントを振り返ります:

  • 整数演算 では % を使い、商を求める / とセットで利用される。
  • 偶数・奇数判定 や、インデックスの 循環処理 に非常に有効。
  • 浮動小数点数 の余りには math.hfmod 関数を使用する。
  • ゼロ除算 は致命的なエラーになるため、事前のチェックが必須。
  • 負の数の余り は、左側の数値の符号に引きずられる(C99以降)。

これらの特性を正しく理解し、適切に使いこなすことで、より効率的でミスの少ないプログラムを書くことができるようになります。

特に単位換算や周期処理は、ゲーム開発からシステムプログラミングまで幅広く登場するため、しっかりとマスターしておきましょう。