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
一直被误名.
%
是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.
在gcc
C89中的实现行为一直是朝零的截断.
因此,%
在C99,C++,并在Java中,其余运营商,但并非所有的编程语言,其余操作.在Ruby和Python中,%
实际上是模运算符(整数除法是在这些语言中对负无穷大进行的).Haskhell和方案有两个独立的运营商:mod
和rem
Haskell的,并且modulo
和remainder
对方案.