I was surprised when this for
loop failed to run properly:
for (std::size_t i=2; i >= 0; --i)
I figured, okay, probably the final check is if -1 >= 0
, and since i
is not allowed to be negative, we have a problem. Presumably i
is looping around to (264 - 1).
However, this for
loop does execute:
for (std::size_t i=2; i 1 > 0; --i)
Ignoring std::size_t
for a moment; this doesn't make sense to me from a logical perspective. Both (i 1 > 0)
and (i >= 0)
will be either true or false for the exact same values of i
.
Both will be true if i = {0, 1, 2, ...}
and false if i = {-1, -2, -3, ...}
.
What is going on here?
Is it something to do with the implementation of std::size_t
, or the compiler, or am I just missing something very obvious?
CodePudding user response:
What is going on here?
std::size_t
is an unsigned integer type.
i >= 0
All unsigned integers are greater than or equal to 0. There exists no value for which this relation would be false and hence the loop cannot end.
i 1 > 0
An unsigned integer can be 0. Hence this relation can be false and the loop can end. Example:
std::size_t i = 0;
i -= 1;
assert(i 1 == 0);
The value of i
that ends the loop is congruent with -1 modulo M, where M is the number of representable values which is 2b where b is the width of the integer type in bits. That number is the greatest representable value i.e. 2b-1.
Your deduction works with whole numbers, but it doesn't work with modular arithmetic.
This is to some degree a matter of taste, but I recommend following code to loop over numbers (n..0]. It works correctly with both signed and unsigned types:
for (std::size_t i=n; i-- > 0;)
CodePudding user response:
size_t
is an unsigned type. In such types, negative values don't exist, but 0-1 is defined to be the value to which adding 1 would give 0 – the maximum representable integer value of size_t
.
So, yes:
I figured, okay, probably the final check is if -1 >= 0, and since i is not allowed to be negative, we got a problem. Presumably i is looping around to 2^64 - 1.
exactly.
for (std::size_t i=2; i 1 > 0; --i)
So, i
reaches 2⁶⁴-1, and you add 1, so you get 0
, which is not >0
, and your loop exits.
Everything's fine here!