C++11能保证余数的符号与被除数的符号相同吗?

20
在C++11中,保证(-x) % m是负数且等于(-x % m)吗?其中xm为正数。
我知道在我所知道的所有机器上都是正确的。
2个回答

11
除了Luchian的回答,以下是来自C++11标准的相关部分:
二元运算符/生成商,二元运算符%生成第一个表达式除以第二个表达式的余数。如果/或%的第二个操作数为零,则行为未定义。对于整数操作数,/运算符生成代数商,并舍去任何小数部分;如果商a/b在结果类型中可表示,则(a/b)*b + a%b等于a。
这段内容遗漏了最后一句话。因此,这部分
(a / b) * b + a % b等于a
是唯一要依赖的参考,并且这意味着,鉴于/的截断行为,a%b的符号始终与a相同。因此,如果您的实现在这方面遵循C++11标准,则负操作数的符号和值的模运算确实是完全定义的。

哦,你使用了 a/b 被舍去为零的方式。真的吗? - RiaD
2
@RiaD,它就在前一句话中:“对于整数操作数,/ 运算符产生代数商,并丢弃任何小数部分”。 - Christian Rau
哦,但我不太确定它的意思。因为在我们学校和大学里,我们把“小数部分”称为正数[0...1),而整数部分是不大于x的最大数字,即[-1.5]为-2。 - RiaD
@RiaD 我不知道它是否真的可以自由解释。你得到了 4.2,去掉小数部分(即 . 后面的数字),你就得到了 4。再拿 -4.2,同样去掉小数部分,你就得到了 -4。你所说的是 floor 函数,一种特殊的舍入方法。但标准是关于舍弃小数部分的,这并不会以任何方式改变 . 前面的数字,它只是删除 . 后面的数字。 - Christian Rau
哦,我明白了。有一个注释80,说的就是我想要的东西。 - RiaD
哦天啊和该死!我不敢相信他们弄错了。是的,我说错了,我的意思是错了。数学上和合理的方法是向下舍入,这样结果始终为正数。否则,每个实际使用负值模数的应用程序都需要进行测试。试着找到反例。我定义一个函数来封装测试,也就是返回真实的模数值,int mod(int x, int y) { int ret = x%y; if(ret<0) ret += y; return ret; } - Jive Dadson

7

5.6 乘法运算符

4) 二元 / 运算符返回商,二元 % 运算符返回第一个表达式除以第二个表达式的余数。如果 / 或 % 的第二个操作数为零,则行为未定义;否则 (a/b)*b + a%b 等于 a。 如果两个操作数都是非负数,则余数为非负数;如果不是,则余数的符号由实现定义(重点在此)

这段内容来自于 C++03。


1
我相信这在C++0x中没有改变,以维持向后兼容性。 - Patrick White
@PWhite 实际上维基百科说它已经改为定义行为了,我会在标准中找到它。 - Christian Rau
2
而向零舍入的好处当然是提问者所询问的:(-x) % m == -(x %m)(-x) / m == -(x / m)。相反,向负无穷舍入的好处是模数只有 m 种可能的值,并且这些值是模 m 的整数数学环的元素。 - Steve Jessop
@SteveJessop,顺便说一下,我并不认为(-x) % m == -(x %m)是一个很好的东西,我只是用它来解释。m可能的结果要好得多) - RiaD
如果删除粗体部分,这不意味着我们甚至不能保证如果两个操作数都是非负的,结果就是非负的吗?实际上,3%2可能会产生-1:P(没有任何关于符号的说明XD) - CoffeDeveloper
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接