为什么 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 的类型在除法开始之前就由操作数类型决定:

上面演示的最后两行是面试级的细节:(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 则向负无穷取整 — 同一个数学,不同约定。跨语言移植代码时这里会咬人。

它在真实代码里惹的三个祸

  1. 永远为零的平均值:sum / count 两个都是 int,count > sum 时直接得 0。修法:static_cast<double>(sum) / count。
  2. 永远为零的百分比:x / total * 100 — 除法先做,先截断。修法:100.0 * x / total(先乘)或转换。
  3. 差一次的循环: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,别玩手工技巧。

这个主题的面试题

  1. "7 / 2 和 7 % 2 各是多少?" — 3 和 1;接着会问负数(上文)。
  2. "为什么 100.0 * x / total 和 x / total * 100 不一样?" — 求值顺序;前者从头到尾没做过 int 除 int。
  3. "% 能用在 double 上吗?" — 不能,只能整数(浮点用 <cmath> 的 fmod)。
  4. "i % 2 有什么用?" — 判奇偶,也就是循环指南里 continue 那个技巧。

去练习场练手

  1. 把演示改成 a = 100, b = 7,先预测五行输出再运行。
  2. 分别用错误和正确的方法算 1、2 的平均值,对比结果。
  3. 用 % 打印 1–20 每个数是奇还是偶(循环 + 除法一道练完)。

相关:for 与 while 循环、初学者面试题,刚起步的话看Hello World 一课。