热门问题
时间线
聊天
视角
模除
来自维基百科,自由的百科全书
Remove ads
Remove ads
模除(英语:modulo 有时也称作 modulus),又称模数、取模、取模运算等,它得出一个数除以另一个数的余数。给定两个正数:被除数和除数,(通常缩写为),得到的是使用欧几里得除法时的余数。所得之数被称为的小数部份。

举个例子:计算表达式得到,因为的商为而余数为;而得到,因为的商为而余数为;做除法不能整除时得到是有理数,平常使用的计算器采用了有限个数位的十进制表示法,它以小数点分隔整数部份和小数部份,比如。
虽然通常情况下模除的被除数和除数都是整数,但许多计算系统允许其他类型的数值运算,比如对浮点数取模。在所有计算系统中当被除数和除数都是正数时,结果的余数的范围为;而经常是未定义的,在编程语言里可能会导致除以零错误。当被除数或除数为负数时,不同的编程语言对结果有不同的处理。
Remove ads
各种定义
在数学中,取模运算的结果就是欧几里德除法的余数。当然也有许多其他的定义方式。计算机和计算器有许多种表示和储存数字的方法,因此在不同的硬件环境下、不同的编程语言中,取模运算有着不同的定义。
几乎所有的计算系统中,除以得到商和余数均满足以下式子:
即使如此,当余数非时,余数的符号仍然是有歧义的:余数非时,它的符号有两种选择,一个是正号而另一个是负号[a]。通常情况下,在数论中总是选择正余数。但在编程中,选择余数的符号依赖于编程语言和被除数或除数的符号。在编程语言所定义的整数模除中,ISO/IEC标准Pascal[1]和ALGOL 68[2],在计算出的余数r
为负数时,返回正数作为结果[b];另一些编程语言如ISO/IEC C90,当被除数或除数是负数时,C90标准并没有做具体的规定,而是留给编译器去定义并实现[3]。在大多数系统中是未定义的,虽然有些系统定义它就等于。更多详情参见后续章节表格。
- 很多取模的实现都使用了“截断除法”(英语:truncated division),商经由截尾函数来定义,商向零取整,结果等于普通除法所得的小数靠近方向的第一个整数:
余数和被除数符号一致:
- 高德纳定义的“下取整除法”(英语:floored division)[4],商经由下取整函数来定义,商总是向负无穷取整,即使商已经是负数:
余数和除数符号一致:
- Raymond T. Boute使用的欧几里得除法定义中[5],要求满足,在这种情况下:
这里的是符号函数,余数总是非负数:
- Common Lisp的
round
函数和IEEE 754使用“修约除法”(英语:rounded division),商经由修约函数(约半成偶)来定义为:当商为偶数时,余数范围是;当商为奇数时,余数范围是:
- Common Lisp的
ceiling
函数使用“上取整除法”(英语:ceiling division),商经由上取整函数定义为:余数与除数有相反的符号:
Remove ads
记号
一些计算器有取模mod()按钮,很多编程语言里也有类似的函数,通常像mod(a, n)
这样。有些语言也支持在表达式内使用%
、mod
或Mod
作为取模或取余操作符,比如a % n
或a mod n
。
在一些没有mod()函数的环境中或许可使用等价的:a - (n * int(a/n))
。这里的int()
函数事实上等价于截断函数。
性质及恒等式
一些取模操作,经过分解和展开可以等同于其他数学运算。这在密码学的证明中十分有用,例如:迪菲-赫尔曼密钥交换。
Remove ads
编程语言实现
此外,很多计算机系统提供divmod
功能,它同时产生商和余数。例子x86架构的IDIV
指令,C编程语言的div()
函数,和Python的divmod()
函数。
Remove ads
常见错误
当取模的结果与被除数符号相同时,可能会导致意想不到的错误。
举个例子:如果需要判断一个整数是否为奇数,有人可能会测试这个数除 2 的余数是否为 1:
bool is_odd(int n) {
return n % 2 == 1;
}
但在一个取模结果与被除数符号相同的编程语言里,这样做是错的。因为当被除数 n 是奇数且为负数时, 得到 −1,此时函数返回“假”。
一种正确的实现是测试取模结果是否为 0,因为余数为 0 时没有符号的问题:
bool is_odd(int n) {
return n % 2 != 0;
}
或者考虑余数的符号,有两种情况:余数可能为 1 或 -1。
bool is_odd(int n) {
return n % 2 == 1 || n % 2 == -1;
}
Remove ads
性能问题
可以通过依次计算带余数的除法实现取模操作。特殊情况下,如某些硬件上,存在更快的实现。 例如:2 的 n 次幂的模,可以通过逐位与运算实现:
x % 2n == x & (2n - 1)
例子,假定 x 为正数:
x % 2 == x & 1
x % 4 == x & 3
x % 8 == x & 7
在进行位操作比取模操作效率更高的设备或软件环境中,以上形式的取模运算速度更快。[56]
编译器可以自动识别出对 2 的 n 次幂取模的表达式,自动将其优化为 expression & (constant-1)
。这样可以在兼顾效率的情况下写出更整洁的代码。这个优化在取模结果与被除数符号一致的语言中(包括 C 语言)不能使用,除非被除数是无符号整数。这是因为如果被除数是负数,则结果也是负数,但 expression & (constant-1)
总是正数,进行这样的优化就会导致错误,无符号整数则没有这个问题。
Remove ads
用途
参见
- 模 (消歧义)和模 (术语) —— “模数(Modulo)”这个词的许多用法,都是 1801 年卡尔·弗里德里希·高斯引入模算数时产生的。
- 模幂运算
- 同馀
脚注
参考文献
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads