为什么C ++在使用模数时输出负数?
数学 :
如果你有这样的等式:
x = 3 mod 7
x可以是...... -4,3,10,17 ......或者更一般地说:
x = 3 + k * 7
其中k可以是任何整数。 我不知道模数运算是为数学定义的,但是这个因素肯定是。
Python :
在Python中,当您使用具有正m
%
时,您将始终获得非负值:
#!/usr/bin/python
# -*- coding: utf-8 -*-
m = 7
for i in xrange(-8, 10 + 1):
print(i % 7)
结果是:
6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3
C ++:
#include <iostream>
using namespace std;
int main(){
int m = 7;
for(int i=-8; i <= 10; i++) {
cout << (i % m) << endl;
}
return 0;
}
会输出:
-1 0 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 0 1 2 3
ISO / IEC 14882:2003(E) - 5.6乘法运算符:
二进制/运算符产生商,二进制%运算符产生第一个表达除以第二个表达式得到的余数。 如果/或%的第二个操作数为零,则行为未定义; 否则(a / b)* b + a%b等于a。 如果两个操作数都是非负的,那么余数是非负的; 如果没有, 剩下的符号是实现定义的74) 。
和
74)根据正在进行的修改ISO C的工作,整数除法的首选算法遵循ISO Fortran标准ISO / IEC 1539:1991中定义的规则,其中商总是向零调整。
资料来源:ISO / IEC 14882:2003(E)
(我找不到ISO/IEC 1539:1991
的免费版本,有人知道从哪里得到它?)
该操作似乎是这样定义的:
问题 :
这样定义它有意义吗?
这个规范的参数是什么? 有没有一个地方制定这样的标准的人讨论它呢? 在哪里我可以读到一些关于他们为什么决定这样做的原因?
大多数情况下,当我使用模数时,我想访问数据结构的元素。 在这种情况下,我必须确保mod返回一个非负值。 所以,对于这种情况,mod总会返回一个非负值。 (另一个用法是欧几里得算法,因为在使用这个算法之前,你可以使这两个数字都是正数,所以模数的符号很重要。)
其他材料 :
请参阅维基百科,了解模数在不同语言中的长列表。
在x86(以及其他处理器体系结构)上,整数除法和模数通过一个单独的操作idiv
( div
for unsigned values)来执行,它产生商和余数(对于字大小的参数,分别在AX
和DX
)。 这用在C库函数divmod
,可以通过编译器将其优化为单条指令!
整数部分尊重两个规则:
dividend = quotient*divisor + remainder
由结果满足。 因此,当将负数除以正数时,商将是负数(或零)。
所以这种行为可以被看作是一系列本地决策的结果:
这个规范的参数是什么?
C ++的设计目标之一是有效地映射到硬件。 如果底层硬件以产生负余量的方式实现分区,那么如果您在C ++中使用%
,那么就是这样。 这就是它的全部。
有没有一个地方制定这样的标准的人讨论它呢?
你可以在comp.lang.c ++。moderated中找到有趣的讨论,在较小的程度上可以找到comp.lang.c ++
当天,设计x86指令集的人决定将整数除法舍入到零而不是舍去是正确的。 (可能一千只骆驼的跳蚤嵌入母亲的胡须中。)为了保持一些数学正确性的外观,操作符REM被发音为“剩余”,必须相应地表现出来。 不要阅读以下内容:https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_73/rzatk/REM.htm
我警告过你。 稍后有人在做C语言规范时认为它会符合编译器的要求,无论是正确的方式还是x86的方式。 然后一个做C ++规范的委员会决定用C方式来做。 然后,在这个问题发布后,C ++委员会决定以错误的方式进行标准化。 现在我们坚持下去了。 许多程序员编写了以下函数或类似的东西。 我可能至少做了十几次。
inline int mod(int a, int b) {int ret = a%b; return ret>=0? ret: ret+b; }
有你的效率。
这些天我基本上使用了下面的内容,并引入了一些type_traits的东西。(感谢Clearer的评论,给了我一个使用后期C ++的改进的想法,见下文)。
<strike>template<class T>
inline T mod(T a, T b) {
assert(b > 0);
T ret = a%b;
return (ret>=0)?(ret):(ret+b);
}</strike>
template<>
inline unsigned mod(unsigned a, unsigned b) {
assert(b > 0);
return a % b;
}
事实是:我游说帕斯卡标准委员会做出正确的方式,直到他们改变态度。 令我惊骇的是,他们以错误的方式进行了整数除法。 所以他们甚至不匹配。
编辑:清晰的给了我一个主意。 我正在研究一个新的。
#include <type_traits>
template<class T1, class T2>
inline T1 mod(T1 a, T2 b) {
assert(b > 0);
T1 ret = a % b;
if constexpr ( std::is_unsigned_v<T1>)
{
return ret;
} else {
return (ret >= 0) ? (ret) : (ret + b);
}
}
链接地址: http://www.djcxy.com/p/20793.html
上一篇: Why does C++ output negative numbers when using modulo?