#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;
}
The above code prints:
-4
7
5
-4
Can someone please explain why i % v.size()
prints 5
instead of -4
? I'm guessing it has something to do with vector.size()
, but unsure what the underlying reasoning is. Thanks in advance.
If both the divisor and dividend are negative, then both truncated division and floored division return the negative remainder.
Can a modulus be negative? % can be negative as it is the remainder operator, the remainder after division, not after Euclidean_division. Since C99 the result may be 0, negative or positive. The modulo OP wanted is a classic Euclidean modulo, not % .
Therefore, in C/C++ language we always find remainder as (a%b + b)%b (add quotient to remainder and again take remainder) to avoid negative remainder.
Modulus operator with negative numbers If we have negative numbers, the result will be based on the left operand's sign, if the left operand is positive – the result will be positive, and if the left operand is negative – the result will be negative.
The operands of %
undergo the usual arithmetic conversions to bring them to a common type, before the division is performed. If the operands were int
and size_t
, then the int
is converted to size_t
.
If size_t
is 32-bit then -4
would become 4294967292
and then the result of the expression is 4294957292 % 7
which is actually 0
.
If size_t
is 64-bit then -4
would become 18,446,744,073,709,551,612 and the result of this % 7
is 5
which you saw.
So actually we can tell from this output that your system has 64-bit size_t.
In C++ the modulus operator is defined so that the following is true for all integers except for b == 0:
(a/b)*b + a%b == a
So it is forced to be consistent with the integer division, which from C++ 11 onwards truncates to zero even for negative numbers. Hence everything is well defined even for negative numbers.
However, in your case you have an signed / unsigned division (because .size() returns unsigned) and the usual signed/unsigned rules apply. This means that in this case all arguments are converted to unsigned before the operation is carried out (see also Ruslan's comment).
So -4 is converted to unsigned (and becomes a very large number) and then modulo is carried out.
You can also see this as 5 is not a correct answer for -4 modulo 7 with any definition of integer division (3 would be correct).
Arithmetic rules with C and C++ are not intuitive.
Because v.size
return size_t
.
cout << -4 % size_t(7) << endl; // 5
Take a look modulo-operator-with-negative-values
UPD: and signed-int-modulo-unsigned-int-produces-nonsense-results
This is due to the type of v.size()
, which is an unsigned type. Due to integer promotion, this means that the result will also be treated as unsigned, despite i
being a signed type.
I am assuming you are compiling on 64 bit. This means that in addition to promotion to unsigned, the result will also be of the 64 bit type unsigned long long
. Step by step:
unsigned long long _i = (unsigned long long)-4; // 0xFFFFFFFFFFFFFFFC!
unsigned long long result = _i % (unsigned long long)7; // 5
Since presumably you want to preserve the signedness of i
, in this case it is enough to cast v.size()
to a signed type to prevent the promotion to unsigned:
i % (int)v.size()
will give -4
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With