数学:
如果您有这样的等式:
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 1539:1991
的免费版本。有人知道从哪里获取它吗?)
操作似乎是这样定义的:
问题:
这样定义它是否有意义?
此规范的参数是什么?是否存在创建此类标准的人员讨论它的地方?我可以在哪里读到他们决定这样做的原因吗?
大多数时候,当我使用modulo时,我想访问数据结构的元素。在这种情况下,我必须确保mod返回一个非负值。因此,对于这种情况,mod总是会返回一个非负值。 (另一种用法是Euclidean algorithm。在使用此算法之前,你可以使两个数字都为正数,模数的符号就很重要。)
其他材料:
有关模数在不同语言中的作用的详细列表,请参阅Wikipedia。
答案 0 :(得分:23)
在x86(和其他处理器体系结构)上,整数除法和模数由单个操作执行,idiv
(div
表示无符号值),它产生商和余数(对于字 - 大小的参数,分别在AX
和DX
中。这在C库函数divmod
中使用,可以由编译器优化为单个指令!
整数部门尊重两条规则:
dividend = quotient*divisor + remainder
。因此,当将负数除以正数时,商将为负数(或零)。
因此,这种行为可以看作是一系列地方决策的结果:
答案 1 :(得分:10)
此规范的参数是什么?
C ++的设计目标之一是有效地映射到硬件。如果底层硬件以产生负余数的方式实现除法,那么如果在C ++中使用%
,那就是你所得到的。这就是真的。
创建此类标准的人是否有讨论这个问题的地方?
你会发现有关comp.lang.c ++。moderated以及在较小程度上comp.lang.c ++
的有趣讨论。答案 2 :(得分:6)
在当天,设计x86指令集的人认为将整数除法舍入为零而不是向下舍入是正确和好的。 (可能有一千只骆驼的跳蚤在他母亲的胡须里筑巢。)为了保持一些数学正确性,操作员REM,发音为“#34;余下的&#34;”,必须相应地表现。请勿阅读: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;
}
确实如此:我游说Pascal标准委员会以正确的方式进行调整,直到他们妥协。令我恐惧的是,他们以错误的方式进行整数除法。所以他们甚至不匹配。
编辑:清洁工给了我一个主意。我正在研究一个新的。#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);
}
}