我应该在要修复的程序中找到定义了mod
函数的函数:
int mod(int a, int b)
{
int i = a%b;
if(i<0) i+=b;
return i;
}
有人告诉我a
和b
始终为正...
嗯? if(i<0)
?
参数是that
模运算的结果是一个等价类,并且可以选择该类的任何成员作为代表
并且仅作为事后考虑
...;然而,通常的代表是最小的正残基,属于该类别的最小的非负整数,即欧几里得除法的余数。但是,其他约定也是可能的。
这意味着6 % 7
可以返回6
(到目前为止很好),但也可以返回-1
。嗯...真的吗? (让我们忽略以下事实,即所提供的实现不能处理所有情况。)
我知道在数学上模运算是这样的。但是后来有人告诉我,C %
实际上“不是实现模运算符,而是实现余数”。
那么,C如何定义%
运算符?
我只能在C-Draft中找到
/运算符的结果是第一个操作数除以第二; %运算符的结果是余数。在这两个操作中,如果第二个操作数为零,行为未定义。
这是否意味着6 % 7
始终为6
?或者也可以是-1
?
永远:
a == (a/b)*b + a%b
abs(a%b) < abs(b)
a
和b
为正,a % b
为正。C99起,
a/b == trunc(a/b)
a%b
是0
或符号为a
。认为6 % 7
可能是-1
可能是由于缺少这样的事实,即始终保证a
和b
为正,并且缺少C99中的更改。
根据标准:
[整数相除时,
/
运算符的结果为舍弃任何小数部分的代数商。如果商a / b是可表示的,表达式(a/b)*b + a%b
等于a
。[ISO / IEC 9899:2011:6.5.5]
这意味着a
的符号保留在模中。
17 % 3 -> 2
17 % -3 -> 2
-17 % 3 -> -2
-17 % -3 -> -2
因此,6%7
不能为-1
,因为提醒必须具有相同的分红符号。
这是否意味着6%7总是6?还是也可以是-1?
余数
二进制运算符%产生除法的余数第一个操作数与第二个操作数之和转换)。
[...]
当通常的算术转换后的类型是整数类型时,结果是四舍五入的代数商(不是小数)实施定义的方向(直到C99)截断为零(自C99起)
因此6 / 7
将是0
,并且6 % 7
将是6 - 0
,即6
。
关于模运算和等价类的主张很有趣,这不是它在C(和大多数其他编程语言)中的工作方式。
此外,即使是这种情况,-8
不会在相同的等效类中吗?然后if(i<0) i+=b;
无法解决问题。
但是后来有人告诉我,C%实际上“没有实现模运算符,但余数“。
好点。在我链接的文档中,它称为“剩余”。
当一个数字或另一个数字为负数时,至少有三种不同的方式定义除法和余数算法。 (有关更多详细信息,请参见this Wikipedia article-尤其是nice picture there。)
但是,如果您知道将正数除以正数,就不会有任何歧义。除法和余数的所有三个定义都表示,如果将正数除以正数,则将得到正商和正余数。
那里的三个选项中,C使用了一个称为“截断除法”的选项。但是,对于正数,这没有任何区别。 (从前,编译器是使用截断还是使用“欧几里得”分割法取决于编译器,但事情只取决于一个定义,即C标准的多个修订版。)
这是否意味着
6 % 7
始终为6
?或者也可以是-1
?
是,6 % 7
始终为6(在C中,并且在三个定义中的任何一个下)。