Arj*_*kar 151
C99 要求何时a/b
可表示:
(a/b) * b
+ a%b
应该相等a
从逻辑上讲,这是有道理的.对?
让我们看看这导致了什么:
例A. 5/(-3)
是-1
=> (-1) * (-3)
+ 5%(-3)
=5
只有在5%(-3)
2时才会发生这种情况.
例B. (-5)/3
是-1
=> (-1) * 3
+ (-5)%3
=-5
如果这只能发生(-5)%3
是-2
oua*_*uah 131
%
C中的运算符不是模运算符,而是余数运算符.
模数和余数运算符在负值方面不同.
对于余数运算符,结果的符号与被除数的符号相同,而对于模运算符,结果的符号与除数相同.
C定义了以下%
操作a % b
:
a == (a / b * b) + a % b
Run Code Online (Sandbox Code Playgroud)
用/
截断的整数除法0
.这是朝向0
(并且不是负向无效)的截断,其将定义%
为余数运算符而不是模运算符.
小智 61
基于C99规范: a == (a / b) * b + a % b
我们可以写一个函数来计算(a % b) == a - (a / b) * b
!
int remainder(int a, int b)
{
return a - (a / b) * b;
}
Run Code Online (Sandbox Code Playgroud)
对于模运算,我们可以有以下函数(假设b> 0)
int mod(int a, int b)
{
int r = a % b;
return r < 0 ? r + b : r;
}
Run Code Online (Sandbox Code Playgroud)
我的结论是(a%b)在C中是余数运算符而非模运算符.
Uda*_*ukh 52
我认为没有必要检查数字是否为负数.
找到正模的一个简单函数就是这个 -
int modulo(int x,int N){
return (x % N + N) %N;
}
Run Code Online (Sandbox Code Playgroud)
假设N为正,这将适用于x的正值和负值.
PS也如@chux所指出的,如果你的x和N分别达到INT_MAX-1和INT_MAX,只需替换N > 0
为N + N - 1 <= INT_MAX
.
如果他们也超过了长期的限制(即接近LLONG_MAX),那么你应该分别处理正面和负面情况,如其他答案所述.
其他答案已在C99或更高版本中解释,涉及负操作数的整数除法总是截断为零.
请注意,在C89中,向上或向下的结果是实现定义的.因为在所有标准中都是(a/b) * b + a%b
等于a
,所以%
涉及负操作数的结果也是在C89中实现定义的.
根据C99 标准,第6.5.5 节乘法运算符,需要以下内容:
(a / b) * b + a % b = a
Run Code Online (Sandbox Code Playgroud)
根据 C99,余数运算结果的符号与被除数的符号相同。
让我们看一些例子(dividend / divisor
):
(-3 / 2) * 2 + -3 % 2 = -3
(-3 / 2) * 2 = -2
(-3 % 2) must be -1
Run Code Online (Sandbox Code Playgroud)
(3 / -2) * -2 + 3 % -2 = 3
(3 / -2) * -2 = 2
(3 % -2) must be 1
Run Code Online (Sandbox Code Playgroud)
(-3 / -2) * -2 + -3 % -2 = -3
(-3 / -2) * -2 = -2
(-3 % -2) must be -1
Run Code Online (Sandbox Code Playgroud)
6.5.5 乘法运算符
句法
- 乘法表达式:
cast-expression
multiplicative-expression * cast-expression
multiplicative-expression / cast-expression
multiplicative-expression % cast-expression
约束条件
- 每个操作数都应具有算术类型。%运算符的操作数应为整数类型。
语义学
通常的算术转换是对操作数执行的。
二元*运算符的结果是操作数的乘积。
/运算符的结果是第一个操作数除以第二个操作数所得的商;%运算符的结果是余数。在这两个操作中,如果第二个操作数的值为零,则行为未定义。
当整数相除时,/运算符的结果是代数商,任何小数部分都会被丢弃[1]。如果商
a/b
是可表示的,则表达式(a/b)*b + a%b
应等于a
。[1]:这通常称为“向零截断”。
模数可以为负吗?
%
可以是负数,因为它是余数运算符,除法后的余数,而不是Euclidean_division之后的余数。由于C99,结果可能为0,负数或正数。
// a % b
7 % 3 --> 1
7 % -3 --> 1
-7 % 3 --> -1
-7 % -3 --> -1
Run Code Online (Sandbox Code Playgroud)
所需的模运算OP是经典的欧几里德模,不是%
。
我每次都期待一个积极的结果。
要执行无论何时a/b
定义a,b
都定义良好的欧几里德模,它具有任何符号,并且结果永远不会为负:
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;
}
modulo_Euclidean( 7, 3) --> 1
modulo_Euclidean( 7, -3) --> 1
modulo_Euclidean(-7, 3) --> 2
modulo_Euclidean(-7, -3) --> 2
Run Code Online (Sandbox Code Playgroud)
模运算的结果取决于分子的符号,因此y和z得到 -2
这是参考
http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_14.html
整数除法
本节介绍执行整数除法的函数。这些函数在 GNU C 库中是多余的,因为在 GNU C 中“/”运算符总是向零舍入。但在其他 C 实现中,“/”可能会因负参数而以不同方式舍入。div 和 ldiv 很有用,因为它们指定如何将商舍入:朝零舍入。余数与分子符号相同。