If you're doing this to learn about programming, you can do a bit of programming to help you confirm the answer:
#include <iostream>
int abs(int x) { return x >= 0 ? x : -x; }
int main()
{
for (int i = -128; i <= 127; ++i)
{
char x = i;
char y;
if (x > 0)
y = x;
else
y = -x;
if (!(y >= 0 && abs(y) == abs(x)))
std::cout << "failed for " << i << " (y " << (int)y << ")\n";
}
}
Running this you'll see if fails for x
-128 (where y
is -128). This is due to the asymmetry in 2's complement notation: -128 can be represented in an 8-bit char, but 128 can not (only 127).
So for 1, and assuming 2's complement integers, the precondition is that x
is not the lowest representable value in your bit width. Of course, there's nothing in the question that says x and y are even ints, so it's all a bit tentative.
If x
and y
were floats or doubles say, then in the normal IEEE representations there's a sign bit that can be toggled without affecting the mantissa or exponent, allowing a "clean" change of sign. That said, there are also corner cases with "not a number" (NaN) and (positive and minus) infinity sentinel values, which it would be wise to check either experimentally and/or by studying the representations and behavioural specifications....
Describe why [{ y >= 0 && |y| == |x| }] is better for verifying the code than just { y >= 0}.
A vague question, as we've no certainty about what the code's trying to achieve, and our reasoning about that comes circularly from the assertion that the former post-condition is better than the latter. Still, they're fishing for an answer like: the former also ensures the absolute magnitude of y
survives whatever the sign change made by the code does to x
.
In practice for our 2's complement integers the magnitude did always match afterwards - it was the sign part of the post-condition that flagged the corner case. But, it's still reassuring to have that extra insight into what's expected.