为什么operator%被称为"模数"运算符而不是"余数"运算符?

Cha*_*dia 22 c++ standards operators modulus

今天上班时我与我的一位同事进行了一次有趣的讨论.当他遇到以下情况时,他感到很惊讶:

assert(-1 % 10 == -1)  //Expecting 9
Run Code Online (Sandbox Code Playgroud)

因此,当他来问我这件事,我告诉他,"好了,这是有道理的.当你把-1 10,你跟-1剩余得到0.然而,他的论点是,模运算应该秉承"总是积极的"模型.我做了一点研究,发现他所指的模数看起来像这样:

设q是a和n的整数商.设r为余数.然后:

a = n*q + r

然而,使用的定义似乎是模数的Knuth版本,它是:

设q是除以n的底数.设r为余数.然后:

r = a - n*q

所以,我的问题是为什么它最终在FORTRAN标准(以及随后的C标准)中使模数运算符截断为0?把它称为"模数"而不是"余数"似乎是一种误称(在数学中,答案应该是9).这与硬件如何进行划分有关吗?

以供参考:

TLDR; 硬件是模数运算符向0截断的原因吗?

小智 16

把它称为"模数"而不是"余数"似乎是一种误称(在数学中,答案应该是9).

C将其称为%运算符,并将其结果调用为余数.C++从C复制它.两种语言都不称它为模数运算符.这也解释了为什么余数是负的:因为/运算符截断为0,并且(a / b) * b + (a % b)应该相等a.

编辑:DavidRodríguez正确地指出C++ 确实定义了一个std::modulus调用的模板类operator%.在我看来,这个班级的名字很差.挖掘一下,它继承自STL,它现在已经命名为现在.STL的下载说"STL是在SGI MIPSproTM C++ 7.0,7.1,7.2和7.2.1上开发的.",据我所知,实际上没有编译器和硬件,MIPSpro将分区传递给CPU和MIPS硬件截断为0,这意味着std::modulus一直被误名.

  • +1我刚检查了C++标准:*二进制%运算符从第一个表达式除以第二个*得到余数,所以运算符本身+1.现在另一个问题是`functional`中的函子的名称使用`operator%`,它被称为*modulus*,因此至少部分问题是开放的...... (2认同)

oua*_*uah 5

% 是C和C++中的余数运算符.

在C++标准中,它被称为%运算符,它从除法中产生余数.在C标准中,它被称为%运算符,因为C99实际上它是一个余数运算符.模数和余数运算符在负值方面不同.

%操作者在C和C++定义同a == (a / b * b) + a % b.

从C99开始,在C中将整数除法截断为0.在C89中,它是实现定义的(并且%可以是C89中的模运算符).对于整数除法,C++也会向零执行截断.

当截断朝零时,%是一个余数运算符,结果的符号是被除数的符号.当朝向负无穷大进行截断时,%是模运算符,结果的符号是除数的符号.

关于C改变了关于截断的整数除法的实现定义行为的原因,来自C委员的Doug Gwyn说:

C99强加了Fortran兼容的要求,试图吸引更多的Fortran程序员并帮助将Fortran代码转换为C.

C99 Rationale说关于截断为零整数除法:

但是,在Fortran中,结果将始终截断为零,并且数字编程社区似乎可以接受开销.因此,C99现在需要类似的行为,这应该有助于将代码从Fortran移植到C.

gccC89中的实现行为一直是朝零的截断.

因此,%在C99,C++,并在Java中,其余运营商,但并非所有的编程语言,其余操作.在Ruby和Python中,%实际上是模运算符(整数除法是在这些语言中对负无穷大进行的).Haskhell和方案有两个独立的运营商:modremHaskell的,并且moduloremainder对方案.