C++における割り算は、一見シンプルに見えますが、整数型か浮動小数点型か、負の数を含むかによって挙動が大きく変わります。
特に「切り捨て」という言葉は文脈によって意味が異なるため、正確な理解が不可欠です。
本記事では、C++11以降の仕様を前提に、整数除算の切り捨て動作を中心に、実例と注意点を交えて詳しく解説します。
目次
割り算の結果は「型」で決まる
C++の / 演算子は、オペランドの型によって挙動が決まります。
整数型どうしの割り算(整数除算)
int a = 7 / 3;
std::cout << a; // 2
- 小数点以下は保持されず、整数が返る
- これを 整数除算 と呼ぶ
浮動小数点型を含む割り算(実数除算)
double b = 7 / 3.0;
std::cout << b; // 2.33333...
- 少なくとも一方が
doubleやfloatの場合、実数除算になる
重要なポイント
int / int→ 整数除算int / double、double / int→ 実数除算
C++11以降の整数除算は「0方向への切り捨て」
C++11以降では、整数除算の結果は 0に向かって切り捨てる(truncation toward zero) と明確に規定されています。
| 式 | 結果 |
|---|---|
7 / 3 | 2 |
-7 / 3 | -2 |
7 / -3 | -2 |
-7 / -3 | 2 |
std::cout << -7 / 3; // -2
これは数学でいう floor(下方丸め) とは異なります。
数学的な floor との違いに注意
数学の floor は「負の無限大方向への丸め」です。
#include <cmath>
std::cout << std::floor(-7.0 / 3.0); // -3
比較すると以下のようになります。
| 処理 | 結果 |
|---|---|
| C++の整数除算 | -2 |
| floor(-7/3) | -3 |
ポイント
- C++の整数除算:0方向への切り捨て(trunc)
std::floor:下方丸め(数学的定義)
「切り捨て」という日本語が両者で混同されやすいため、0方向(trunc) と floor(下方丸め) を意識的に区別すると安全です。
型変換のタイミングによる典型的なミス
よくある誤解
double x = 7 / 3;
std::cout << x; // 2.0
これは 整数除算が先に行われている ため、結果は 2.0 になります。
正しい書き方
double x = 7.0 / 3;
// または
double x = static_cast<double>(7) / 3;
原則
- 型変換は「割り算の前」に行う
明示的に丸めたい場合の方法
下方丸め(floor)
int a = static_cast<int>(std::floor(7.0 / 3.0)); // 2
上方丸め(ceil)
int b = static_cast<int>(std::ceil(7.0 / 3.0)); // 3
四捨五入(round)
int c = static_cast<int>(std::round(7.0 / 3.0)); // 2
競技プログラミングで頻出の「切り上げ除算」
正の整数に限定する場合、次の式は非常によく使われます。
(a + b - 1) / b
例
int a = 7, b = 3;
int result = (a + b - 1) / b; // 3
前提条件(重要)
a >= 0b > 0a + b - 1が オーバーフローしない型であること
大きな数を扱う場合は long long を使うのが安全です。
負の数を含む「数学的 floor 除算」を実装する例
Python の // と同等の挙動(下方丸め)を C++ で再現する例です。
int floor_div(int a, int b) {
// 前提:b != 0
int q = a / b;
int r = a % b;
if (r != 0 && ((r > 0) != (b > 0))) {
q--;
}
return q;
}
- C++の
/と%は 0方向基準 - 余りの符号と除数の符号を見て補正する
%(剰余)との関係(C++11以降)
C++11以降、次の関係が常に成り立ちます(※ b != 0、オーバーフローしない前提)。
a == (a / b) * b + (a % b)
また、剰余 % の符号は 割られる側(a)の符号に従います。
-7 % 3 == -1
注意すべき未定義・例外ケース
b == 0の除算・剰余 → 未定義動作INT_MIN / -1→ 表現不能(未定義または例外的扱い)
これらは実務・低レイヤ処理では特に注意が必要です。
まとめ
- C++11以降の整数除算は 0方向への切り捨て
- 負の数では数学的 floor と結果が異なる
- 型変換は割り算の前に行う
- 切り上げ・切り捨ては 意図を明示したコードを書く
- 境界条件(0除算・オーバーフロー)を常に意識する
以上、C++の割り算の切り捨てについてでした。
最後までお読みいただき、ありがとうございました。
