为什么 C++ 里 7 / 2 等于 3(整数除法)
一句话:两个操作数都是整数时,C++ 做整数除法 — 小数部分直接扔掉,不四舍五入。7 / 2 是 3,-7 / 2 是 -3(向零截断),7 % 2 给余数 1。
这几乎惊到每个拿计算器思维来的人,也是新手 bug 的一大来源 — 算错的平均值、永远是 0 的百分比、差一的循环数。跑一下,逐行读:
#include <iostream>
using namespace std;
int main() {
cout << "7 / 2 = " << 7 / 2 << endl; // 3(小数被扔掉)
cout << "7 % 2 = " << 7 % 2 << endl; // 1(余数)
cout << "7.0 / 2 = " << 7.0 / 2 << endl; // 3.5(一边是 double)
int a = 7, b = 2;
cout << "(double)a/b = " << (double)a / b << endl; // 3.5(先转!)
cout << "(double)(a/b) = " << (double)(a / b) << endl; // 3(太迟:已按 int 除过)
return 0;
}
精确规则
a / b 的类型在除法开始之前就由操作数类型决定:
- int / int → int。结果向零截断:
7/2 → 3,99/100 → 0。 - 任一边是 double/float → 浮点除法。
7.0/2 → 3.5。一个小数点就够改变行为。 a % b(取模)是同一次整数除法的余数:7 % 2 → 1。只能用于整数类型。
上面演示的最后两行是面试级的细节:(double)a / b 解决问题(转换发生在除法之前),而 (double)(a / b) 转换的是已经截断过的 3 — 括号决定一切。
现代的转换写法
C 风格转换 (double)a 能用但太钝。C++ 推荐的形式明说了你要干什么:
double exact = static_cast<double>(a) / b; // 3.5
结果一样,但可搜索,也不会在你本想要别的操作时误编译。(我们的浏览器引擎覆盖教学核心,暂不支持 static_cast — 在桌面编译器上试。)
负数:向零截断,不是"向下取整"
各种语言在这件事上不一致,而这是极好的面试点。C++ 向零截断:
-7 / 2 // -3(向零;Python 会给 -4)
7 / -2 // -3
-7 % 2 // -1(余数符号随被除数)
C++ 的截断:取整数部分再定符号。Python 则向负无穷取整 — 同一个数学,不同约定。跨语言移植代码时这里会咬人。
它在真实代码里惹的三个祸
- 永远为零的平均值:
sum / count两个都是 int,count > sum时直接得0。修法:static_cast<double>(sum) / count。 - 永远为零的百分比:
x / total * 100— 除法先做,先截断。修法:100.0 * x / total(先乘)或转换。 - 差一次的循环:
for (int i = 0; i <= n; i += n/2)这类算术 — n 是奇数时,整数除法改变了步长。和循环的差一错误是一家子。
想要四舍五入?
整数除法不会舍入,但你可以让它舍:先加除数的一半(正数情形),或转成 double 加 0.5 再转回来:
int rounded = (a + b / 2) / b; // 如 7/2 -> (7+1)/2 = 4
int rounded2 = (int)(7.0 / 2 + 0.5); // 4
严肃的数值计算请直接用 <cmath> 的 std::round,别玩手工技巧。
这个主题的面试题
- "
7 / 2和7 % 2各是多少?" —3和1;接着会问负数(上文)。 - "为什么
100.0 * x / total和x / total * 100不一样?" — 求值顺序;前者从头到尾没做过 int 除 int。 - "
%能用在 double 上吗?" — 不能,只能整数(浮点用<cmath>的fmod)。 - "
i % 2有什么用?" — 判奇偶,也就是循环指南里continue那个技巧。
去练习场练手
- 把演示改成
a = 100, b = 7,先预测五行输出再运行。 - 分别用错误和正确的方法算 1、2 的平均值,对比结果。
- 用
%打印 1–20 每个数是奇还是偶(循环 + 除法一道练完)。
相关:for 与 while 循环、初学者面试题,刚起步的话看Hello World 一课。