#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
vector<int> v = {1, 2, 3, 4, 5, 6, 7};
int i = -4;
cout << i << endl;
cout << v.size() << endl;
cout << i % v.size() << endl;
cout << -4 % 7 << endl;
}
上面的代码打印:
-4
7
5
-4
[有人可以解释为什么i % v.size()
打印5
而不是-4
吗?我猜想它与vector.size()
有关,但不确定潜在的原因是什么。提前致谢。
C0]的操作数经过通常的算术转换将它们带为通用类型。如果操作数是%
和int
,则size_t
将转换为int
。
如果size_t
为32位,则size_t
将变为-4
,然后表达式的结果为4294967292
,实际上是4294957292 % 7
。
如果0
为64位,则size_t
将变为18,446,744,073,709,551,612,并且此-4
的结果为您看到的% 7
。
因此实际上我们可以从此输出中得知您的系统具有64位size_t。
从C ++ 11开始,将模运算符定义为以下条件为真:
5
因此它被定义为与整数除法一致。因此,即使对于负数,一切都定义良好。
但是,在您的情况下,您有一个带符号的/无符号的除法(因为.size()返回无符号的),并且适用通常的带符号/无符号的规则。这意味着在执行操作之前,所有参数都将转换为无符号。
因此-4转换为无符号(并且变成非常大的数字),然后进行取模。
您还可以看到,对于整数除法的任何定义(-3都是正确的),-5不是-4模7的正确答案。
C和C ++的算术规则不直观。
因为(a/b)*b + a%b == a
返回v.size
。
size_t
看看cout << -4 % size_t(7) << endl; // 5
这是由于signed-int-modulo-unsigned-int-produces-nonsense-results的类型,它是无符号类型。由于整数提升,这意味着即使v.size()
是有符号类型,结果也将被视为无符号。
我假设您正在64位上编译。这意味着除了提升为无符号外,结果还将为64位类型i
。逐步操作:
unsigned long long
unsigned long long _i = (unsigned long long)-4; // 0xFFFFFFFFFFFFFFFC!
由于可能要保留unsigned long long result = _i % (unsigned long long)7; // 5
的带正负号,在这种情况下,将i
强制转换为带正负号的类型就足够了,以防止升级为未带正负号的类型:v.size()
将给出i % (int)v.size()
。
从-4
和Usual arithmetic conversions上的cppreference开始>
否则(有符号性不同):如果无符号类型的转换等级大于或等于有符号类型的等级,则具有带符号类型的操作数将隐式转换为无符号类型。
[C++ standard是
-4
,signed
是7
,因此unsigned
首先转换为-4
,然后执行模数。
有了这个想法,如果将其分解,您将立即看到正在发生的事情:
unsigned