为什么负数不等于向量大小的模数?

问题描述 投票:9回答:5
#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()有关,但不确定潜在的原因是什么。提前致谢。

c++ modulus integer-promotion
5个回答
17
投票
在执行除法之前,

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。


4
投票

从C ++ 11开始,将模运算符定义为以下条件为真:

5

因此它被定义为与整数除法一致。因此,即使对于负数,一切都定义良好。

但是,在您的情况下,您有一个带符号的/无符号的除法(因为.size()返回无符号的),并且适用通常的带符号/无符号的规则。这意味着在执行操作之前,所有参数都将转换为无符号。

因此-4转换为无符号(并且变成非常大的数字),然后进行取模。

您还可以看到,对于整数除法的任何定义(-3都是正确的),-5不是-4模7的正确答案。

C和C ++的算术规则不直观。


2
投票

因为(a/b)*b + a%b == a 返回v.size

size_t

看看cout << -4 % size_t(7) << endl; // 5

UPD:和modulo-operator-with-negative-values


2
投票

这是由于signed-int-modulo-unsigned-int-produces-nonsense-results的类型,它是无符号类型。由于整数提升,这意味着即使v.size()是有符号类型,结果也将被视为无符号。

我假设您正在64位上编译。这意味着除了提升为无符号外,结果还将为64位类型i。逐步操作:

  1. unsigned long long
  2. 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()


1
投票

-4Usual arithmetic conversions上的cppreference开始>

否则(有符号性不同):如果无符号类型的转换等级大于或等于有符号类型的等级,则具有带符号类型的操作数将隐式转换为无符号类型。

[C++ standard-4signed7,因此unsigned首先转换为-4,然后执行模数。

有了这个想法,如果将其分解,您将立即看到正在发生的事情:

unsigned    
© www.soinside.com 2019 - 2024. All rights reserved.