如何理解两种符号约定
当两个数都是正数时,两种约定得到的结果完全相同;但只要涉及负数,二者就会出现分歧,如下表所示。
| a | b | 向下取整结果(符号与 b 一致) | 截断结果(符号与 a 一致) |
|---|---|---|---|
| 13 | 5 | 3 | 3(相同——两数都为正) |
| −13 | 5 | 2 | −3 |
| 13 | −5 | −2 | 3 |
| −13 | −5 | −3 | −3(相同——两数都为负) |
- 向下取整取模(本计算器默认作为主要结果展示)是纯数学与数论中最常见的约定,与 Python 内置的 % 运算符一致。
- 截断取模(作为次要结果展示)与 JavaScript、C、C++、Java 以及大多数 C 系语言内置的 % 运算符一致,其余数符号跟随被除数。
- 对零取模没有定义,本计算器不会计算这种情形;除数必须是非零的数。
什么是取模运算?
取模运算,写作 a mod b(或 a % b),求的是 a 除以 b 之后所剩的余数。例如,13 mod 5 = 3,因为 13 = 2 × 5 + 3——13 除以 5 得商 2,余 3。取模是数论(模运算、时钟运算)、计算机科学(哈希、循环索引、校验和)以及日常生活中处理余数与周期问题(例如星期几或钟表时刻)的基础运算。
在涉及负数时,定义结果符号的数学约定主要有两种被广泛使用:向下取整取模,结果的符号总是与除数 b 一致;截断取模,结果的符号总是与被除数 a 一致。这两种定义在数学上都是有效的「余数」定义,当 a 和 b 都为正数时结果完全一致,只有涉及负数时才会出现分歧。
在实践中,这种约定的选择很重要,因为不同编程语言的默认实现各不相同:Python 的 % 运算符使用向下取整取模,而 JavaScript、C、C++、Java 以及大多数 C 系语言使用截断取模(与被除数符号一致)。本计算器把两种结果都明确列出,方便直接读取所需的约定。
如何使用本取模计算器
- 输入被除数(a)——被除的那个数。
- 输入除数(b)——用来除的那个数。除数不能为 0,因为除以零(以及对零取模)没有定义。
- 查看向下取整约定的结果(符号总是与除数一致)——这是数论中最常见的数学约定。
- 如果需要匹配某种编程语言内置 % 运算符的行为,可与截断约定的结果(符号总是与被除数一致)进行比较,并查看商和完整的除法等式以了解详细过程。
向下取整与截断两种取模公式
向下取整取模把商定义为 q = ⌊a ÷ b⌋(向下取整,即向负无穷方向舍入),然后 r = a − b×q。这保证了余数 r 的符号总是与除数 b 一致(或为 0),并且当 b > 0 时满足 0 ≤ r < |b|。举例说明:13 mod 5:q = ⌊13/5⌋ = 2,r = 13 − 5×2 = 3。
被除数为负数的例子:−13 mod 5(向下取整):q = ⌊−13/5⌋ = ⌊−2.6⌋ = −3,r = −13 − 5×(−3) = −13 + 15 = 2。注意结果是正数(与正的除数一致),这与下面的截断结果不同。
截断取模把商定义为向零方向舍入,而不是向负无穷方向舍入,之后按同样方式计算余数;这保证了余数的符号总是与被除数 a 一致(或为 0)。举例说明:−13 mod 5(截断,即 JavaScript/C/Java 中 % 的结果):商把 −2.6 向零方向舍入为 −2,所以 r = −13 − 5×(−2) = −13 + 10 = −3——结果为负数,与负的被除数一致,这与同样输入下向下取整得到的 +2 不同。
常见错误
- 以为所有编程语言在处理负数时计算 a mod b 的方式都相同——JavaScript、C、C++ 和 Java 使用截断取模,而 Python 和许多数学教材使用向下取整取模,只要 a 为负,两者结果就会不同。
- 忘记向下取整的结果符号总是与除数一致,而不是与被除数一致——这与截断(JavaScript 风格)约定得到的结果恰好相反。
- 尝试计算 a mod 0——取模运算和除法一样,在除数为零时没有定义。
- 输入非整数并期望得到整数式的模运算结果——本计算器接受实数输入,并应用同样的向下取整/截断逻辑,但许多经典的模运算性质(例如时钟运算)是专门针对整数定义的。
常见问题
向下取整取模和截断取模有什么区别?
向下取整取模把商向负无穷方向舍入,因此余数总是与除数符号一致。截断取模把商向零方向舍入,因此余数总是与被除数符号一致。两数都为正时二者结果相同,只要有一个为负就会不同——例如,−13 mod 5 在向下取整约定下是 2,在截断约定下是 −3。
为什么 −13 mod 5 在不同计算器里得到的结果不一样?
这取决于使用的是哪种符号约定。向下取整取模给出 2(结果符号与正的除数一致,且满足 0 ≤ r < 5)。截断取模给出 −3(结果符号与负的被除数一致)。Python 的 % 运算符返回 2(向下取整);JavaScript、C、Java 的 % 运算符返回 −3(截断)。两者并非谁「更正确」——它们只是两种不同但同样合理的数学定义。
如何手工计算 a mod b?
用 a 除以 b 得到商,按你选定的约定对商取整(向下取整用向下舍入,截断取模用向零舍入),再用 a 减去 b 乘以这个取整后的商:余数 = a − b × 商。以 13 mod 5 为例:13 ÷ 5 = 2.6,无论哪种约定商都取整为 2,所以余数 = 13 − 5×2 = 3。
模运算和时钟运算中的「mod」是什么意思?
模运算把数值看作在达到模数后「循环归零」——最经典的例子就是 12 小时制的钟表,时间是按 mod 12(24 小时制则按 mod 24)计算的。例如,24 小时制中的 15 点对应 12 小时制表盘上的 15 mod 12 = 3 点。取模正是产生这种「循环」余数的运算。
可以对负数除数取模吗?
可以。在向下取整约定下,a mod b(b 为负)得到的余数符号与 b 一致——例如 13 mod −5 = −2,因为 13 = (−3)×(−5) + (−2)。在截断约定下,余数则与被除数符号一致:截断约定下 13 mod −5 = 3,因为商向零方向舍入为 −2,得到 13 − (−5)×(−2) = 13 − 10 = 3。
参考文献
- Rosen KH. Elementary Number Theory and Its Applications. 6th ed. Pearson, 2010. (Division algorithm and modular arithmetic.)
- Leijen D. Division and Modulus for Computer Scientists. Utrecht University Technical Report UU-CS-2001-20, 2001. (Formal comparison of flooring, truncating and Euclidean division conventions.)
- ECMA International. ECMA-262: ECMAScript Language Specification — the remainder operator (%). ecma-international.org.