写代码时,明明只是加减乘除几个整数,结果却跑出负数、0、甚至完全离谱的值——这种问题不罕见,但排查起来常让人抓耳挠腮。不是逻辑错了,也不是变量没初始化,而是整数运算本身在底层悄悄越界、截断、溢出了。
一、整数溢出:最常见也最容易被忽略
比如在 C/C++ 或 Java 中,int 通常是 32 位有符号类型,取值范围是 -2147483648 到 2147483647。一旦超出,就会“绕圈”:
int a = 2147483647;
int b = a + 1; // 结果不是 2147483648,而是 -2147483648Python 看似没这问题(它自动转长整型),但如果你用的是 numpy 数组或调用 C 扩展,照样会溢出。比如:
import numpy as np
a = np.array([2147483647], dtype=np.int32)
b = a + 1 # 输出:[-2147483648]二、除零错误:看似低级,实则高频
整数除法中,除以 0 不是返回 NaN,而是直接崩溃或抛异常:
int result = 100 / 0; // C/C++:运行时 SIGFPE;Java:ArithmeticException更隐蔽的是变量参与除法前没校验,比如计算平均值时 count 为 0,或者循环中动态生成分母,稍不留神就中招。
三、截断式除法:Python 和 C 的“默契误会”
Python 3 中 // 是向下取整除法,而 C/C++/Java 对负数做整数除法是向零截断。结果不同:
// C 语言
printf("%d\n", -7 / 3); // 输出 -2
# Python
print(-7 // 3) # 输出 -3跨语言对接或移植算法时,这类差异会导致数值偏差,尤其在坐标计算、分页索引、哈希分布等场景里,差 1 就可能漏数据或越界。
四、类型隐式转换:混用 int 和 unsigned int
C/C++ 中,当有符号 int 和无符号 unsigned int 运算时,编译器会把 int 转成 unsigned int——负数立刻变成巨大正数:
unsigned int u = 10;
int s = -5;
if (s < u) {
printf("true");
} else {
printf("false"); // 实际输出 false!因为 -5 被转成 4294967291}这个判断逻辑看着天经地义,执行起来却完全反直觉。
五、位移操作越界:左移不一定等于乘 2
对 int 左移超过位宽,行为未定义(C/C++)或直接静默截断(某些平台):
int x = 1;
int y = x << 32; // 在 32 位系统上,结果不可靠,可能为 0、1 或随机值Java 会自动对位移量取模(x << 32 等价于 x << 0),但这也容易让人误以为安全,实际掩盖了逻辑错误。