
很多刚接触 Python 的小伙伴都会踩这个经典大坑:
7 // 2 得到 3,看着很正常;但 7 // 2,直觉会觉得是 -3,结果 Python 直接输出 -4。
这不是 Bug,也不是 Python 设计失误。Python 的 // 是向下取整(floor 地板除),不是大家熟悉的向零取整。这套规则和取模 % 绑定在一起,是一套自洽、优雅的数学设计。
01
SECTION 01
01 现场复现,一眼看懂两种取整区别
直接跑代码对比,差异一目了然:
python
7 // 2 # 3
-7 // 2 # -4 ← 重点:不是 -3!
int(-7 / 2) # -3 向零取整:直接砍掉小数部分
import math
math.floor(-7 / 2) # -4 Python // 的真实行为:向下取整
简单区分:
- 向零取整 trunc:朝着 0 的方向截断小数。-3.5 → -3
- 向下取整 floor:往数值更小的方向取整。-3.5 → -4
正数场景下两者结果一模一样,负数才会暴露分歧,这也是这个坑隐蔽的地方。
02
SECTION 02
02 整除和取模是绑定的:余数符号跟着除数走
Python 有一条铁律,永远成立:
*`a == (a // b) b + (a % b)`**
整除和取余不能单独设计,必须满足这个恒等式,整套逻辑才不会割裂。
我们代入 -7, 2 验证:
python
-7 // 2 # -4
-7 % 2 # 1
-4 * 2 + 1 # -7 ✔ 等式成立
✅ 核心结论:Python 中余数的符号永远和除数保持一致
除数是正数,余数一定 ≥0;除数是负数,余数一定 ≤0。
对比 C / Java 的行为:
C、Java 采用向零取整,余数符号跟随被除数,-7 % 2 结果是 -1。
这也是后端、算法同学跨语言对接时最高发的翻车点。
03
SECTION 03
03 为什么 Python 执意选择 floor 地板除?——为了数学一致性
核心优势:*取模结果天然落在 [0, |b|) 区间,周期性运算不用额外写 if 判断*
像时钟、环形数组下标、循环队列、周期映射这类场景,负数输入也能顺滑进入循环,不会跑出异常值。
举个周期为7的例子:
python
for i in range(-14, 14):
print(i % 7)
输出稳定循环:0,1,2,3,4,5,6,负数也遵守同一套周期。
如果是 C/Java 那套语义:-1 % 7 = -1,负数取模直接跳出 0~6 的区间。
想拿到合法下标,代码里必须额外加一层特判修正负数,冗余又容易漏写边界。
Python 的方案,牺牲了一部分人的直觉,收获了干净统一的周期数学性质。
04
SECTION 04
04 实战避坑:这几个场景一定要留意
① 分页、数量计算
-1 // 10 结果是 -1,不是预期的 0。
如果业务里存在负数输入(偏移量、补偿值),计算页数、分片号时,记得提前用 max() 钳制下界。
② 除数本身是负数
a // b 的取整方向会跟着除数符号翻转。
如果业务意图是「单纯截断小数、向零靠拢」,不要依赖 //,优先显式写:
int(a / b):向零截断
math.trunc(a / b):和 int 行为一致,语义更清晰
math.floor():显式向下取整,明确告诉阅读者你要地板除
③ 跨语言对接(Python ↔ Java / Go / C++)
分片路由、哈希取模、ID 分桶、一致性哈希场景最容易踩雷。
同样的取模表达式,两边结果不一致,优先排查:是不是整除/取模语义不一样!
05
SECTION 05
05 一张对比表快速记忆
|
表达式 |
Python(floor 地板除) |
C/Java(向零取整) |
核心差异 |
|
7 // 2 |
3 |
3 |
正数无差别 |
|
-7 // 2 |
-4 |
-3 |
向下取整 VS 向零截断 |
|
-7 % 2 |
1 |
-1 |
余数跟除数 VS 余数跟被除数 |
一句话总结:
// 不是简单的“除法取整数部分”,在 Python 里它是地板除;% 也不是我们口算里的余数,它是配套 floor 语义的模运算。
分清两种取整,写环形逻辑、分页、跨语言对接的时候,就能避开这个隐蔽但杀伤力很强的坑。
以上就是“Python 整除坑:-7 // 2 为什么是 -4 而不是 -3?”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14637/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料