我的朋友说“mod”和“remainder”之间存在差异。
如果是这样,C 和 C++ 有什么区别?'%' 在 C 中是指“mod”还是“rem”?
模数和余数之间存在差异。例如:
-21
mod4
是3
因为-21 + 4 x 6
是3
。
但-21
除以余数4
为.-5
-1
对于正值,没有区别。
'%' 在 C 中是指“mod”还是“rem”?
在 C 中,%
是余数1。
...,
/
运算符的结果是任何小数部分被丢弃的代数商...(这通常称为“向零截断”。) C11dr §6.5.5 6运算符的操作数
%
应为整数类型。C11dr §6.5.5 2运算符的结果
/
是第一个操作数除以第二个的商;%
运算符的结果是余数... C11dr §6.5.5 5
“mod”和“remainder”有什么区别?
C 没有定义“mod”或“模”运算符/函数,例如欧几里得除法或其他模中使用的整数模函数。
C 定义了余数。
让我们将每个%
运算符的“余数”与欧几里德的“mod”进行比较。
当为负时,“欧几里得模”与 C 的a%b
运算不同。a
// a % b, the remainder after an integer division that truncates toward 0.
7 % 3 --> 1
7 % -3 --> 1
-7 % 3 --> -1
-7 % -3 --> -1
欧几里得除法中的“模”或模。结果始终为 0 或正数。
7 modulo 3 --> 1
7 modulo -3 --> 1
-7 modulo 3 --> 2
-7 modulo -3 --> 2
候选模代码:
int modulo_Euclidean(int a, int b) {
int m = a % b;
if (m < 0) {
// m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
m = (b < 0) ? m - b : m + b;
}
return m;
}
关于浮点数的注意事项:double fmod(double x, double y)
,虽然叫做“fmod”,但它与欧几里德除法“mod”不同,但类似于C整数余数:
这些
fmod
函数计算 的浮点余数x/y
。C11dr §7.12.10.1 2
fmod( 7, 3) --> 1.0
fmod( 7, -3) --> 1.0
fmod(-7, 3) --> -1.0
fmod(-7, -3) --> -1.0
消歧:C 也有一个类似的命名函数double modf(double value, double *iptr)
,它将参数值分成整数和小数部分,每个部分都具有与参数相同的类型和符号。除了名称相似性之外,这与这里的“mod”讨论几乎没有关系。
[编辑 2020 年 12 月]
对于那些在所有情况下都需要适当功能的人,改进modulo_Euclidean()
了 1)检测mod(x,0)
和 2)使用modulo_Euclidean2(INT_MIN, -1)
. 受到具有完全定义行为的 4 种不同模数实现的启发。
int modulo_Euclidean2(int a, int b) {
if (b == 0) TBD_Code(); // perhaps return -1 to indicate failure?
if (b == -1) return 0; // This test needed to prevent UB of `INT_MIN % -1`.
int m = a % b;
if (m < 0) {
// m += (b < 0) ? -b : b; // avoid this form: it is UB when b == INT_MIN
m = (b < 0) ? m - b : m + b;
}
return m;
}
1在 C99 之前,C 的定义%
仍然是除法的余数,但/
允许负商向下舍入而不是“向零截断”。请参阅为什么在 C89 中得到不同的整数除法值?. 因此,对于一些 C99 之前的编译,%
代码可以像欧几里得除法“mod”一样工作。以上modulo_Euclidean()
内容也适用于这种替代的老式剩余部分。
余数的符号与除数相同,模数的符号与除数相同。
余数只是两个整数之间的算术除法后的剩余部分,而模数是余数和除数的和,当它们的符号相反时,以及当余数和除数都具有相同符号时,算术除法后的剩余部分。
余数示例:
10 % 3 = 1 [这里可除数是 10,它是正符号的,所以结果也将是正符号的]
-10 % 3 = -1 [这里可除数是-10,它是负号的,所以结果也将是负号的]
10 % -3 = 1 [这里可除数是 10,它是正符号的,所以结果也将是正符号的]
-10 % -3 = -1 [这里可除数是-10,它是负号的,所以结果也将是负号的]
模数示例:
5 % 3 = 2 [这里可除数是5,它是正符号的,所以余数也将是正符号的,除数也是正符号的。由于余数和除数的符号相同,结果将与余数相同]
-5 % 3 = 1 [这里可除数是-5,它是负号的,所以余数也将是负号的,除数是正号的。由于余数和除数的符号相反,结果将是余数和除数之和 -2 + 3 = 1]
5 % -3 = -1 [这里可除数是5,它是正符号的,所以余数也将是正符号,除数是负符号。由于余数和除数的符号相反,结果将是余数和除数之和 2 + -3 = -1]
-5 % -3 = -2 [这里可除数是-5,它是负号的,所以余数也将是负号的,除数也是负号的。由于余数和除数的符号相同,结果将与余数相同]
我希望这将清楚地区分余数和模数。
在 C 和 C++ 以及许多语言%
中,余数不是模运算符。
例如在运算-21 / 4
中整数部分是-5
,小数部分是-.25
。余数是除数的小数部分,所以我们的余数是-1
。JavaScript 使用余数运算符并确认这一点
console.log(-21 % 4 == -1);
模数运算符就像您有一个“时钟”。想象一个圆,分别在 12 点钟、3 点钟、6 点钟和 9 点钟位置有值 0、1、2 和 3。以顺时针方向步进商时间使我们得到模运算的结果,或者,在我们的示例中,逆时针方向为负商,得到 3。
注意:模数始终与除数同号,余数与商同号。当至少一个为负时,将除数和余数相加得到模数。
% is a remainder(leftover after dividend / divisor) NOT modulus.
You could write your own modulus function using the remainder(%) by the relation
((n%m)+m)%m
where `n` is the given number and `m` is the modulus
Find below the difference between the remainder and modulus values for the range n = (-7,7) and m = 3
n -7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7
-------------------------------------------------------------------------
%(-m) -1 0 -2 -1 0 -2 -1 0 1 2 0 1 2 0 1 => remainder
% m -1 0 -2 -1 0 -2 -1 0 1 2 0 1 2 0 1 => remainder
mod m 2 0 1 2 0 1 2 0 1 2 0 1 2 0 1 => ((n%m)+m)%m
mod(-m) -1 0 -2 -1 0 -2 -1 0 -2 -1 0 -2 -1 0 -2 => ((n%m)+m)%m
Tips to remember:
n%(-m) = +(remainder)
(-n)%(m) = -(remainder)
sign of 'm' doesn't matter
n mod (-m) = -(result)
(-n) mod m = +(result)
sign of 'n' doesn't matter
For +ve 'n' and '%(-m)' or '%m' or 'mod m' gives the same remainder
模数,在您所指的模算术中,是算术除法后剩余的值或剩余值。这通常称为余数。% 正式地是 C / C++ 中的余数运算符。例子:
7 % 3 = 1 // dividend % divisor = remainder
剩下要讨论的是如何处理这个 % 操作的负输入。现代 C 和 C++ 会为此运算生成一个有符号余数,其中结果的符号始终与被除数输入匹配,而不考虑除数输入的符号。
在数学中,模运算的结果是欧几里得除法的余数。然而,其他约定也是可能的。计算机和计算器有多种存储和表示数字的方式;因此,他们对模运算的定义取决于编程语言和/或底层硬件。
7 modulo 3 --> 1
7 modulo -3 --> -2
-7 modulo 3 --> 2
-7 modulo -3 --> -1