Reputation: 331
I'm on the Hardware/Software interface course hosted on Coursera, from where i'm sure you've seen a fair few of these questions..
One of the assignments is to determine whether 2's complement integer x can fit into n-bits, using only a subset of operators, etc. I'm doing well, but came across 2 separate approaches, and hit the whiteboard with them both to understand them fully. Then came the confusion.
The function returns 1 if possible to fit, 0 if not.
int fooBar(int x, int n) {
return !(((x << (32-n)) >> (32-n)) ^x);
}
Executed with positive integer
fooBar(5,3) == 0
Correctly calculates that 5 cannot be represented as a 2's complement 3 bit integer.
Executed with a negative integer
fooBar(-4,3) == 1
Correctly calculates that -4 can be represented as a 2's complement 3 bit integer.
Method 1 Analysis
x=5, n=3
00000000000000000000000000011101 32 - n == 29
10100000000000000000000000000000 x<<29
00000000000000000000000000000101 >> 29
00000000000000000000000000000101 5
XOR
00000000000000000000000000000101 5
--------------------------------
00000000000000000000000000000000 0
00000000000000000000000000000001 !0 == answer, 1.
As you can see, this returns 0, as in, no 5 may not be represented as a 2's complement integer within 3 bits.
int fooBar(int x, int n) {
return !((x & ~(1 << (32-n))) ^x);
}
Executed with positive integer
fooBar(5,3) == 1
False positive.
Executed with negative integer
fooBar(-4,3) == 0
False negative.
Method 2 Analysis
x=5, n=3
00000000000000000000000000011101 32 - n == 29
11011111111111111111111111111111 ~(1<<29)
AND
00000000000000000000000000000101 5
--------------------------------
00000000000000000000000000000101 5
00000000000000000000000000000101 5
XOR
00000000000000000000000000000101 5
--------------------------------
00000000000000000000000000000000 0
00000000000000000000000000000001 !0 == answer, 1.
I am compiling with:
gcc version 4.7.2 (Debian 4.7.2-5)
Question
I'm at a loss as to explain the difference in output, when the analysis shows that everything is identical at the bit level, so any hints/tips as to where I can look to shed light on this for myself is highly appreciated.
Thank you for your time!
sc.
Upvotes: 4
Views: 169
Reputation: 183873
In method 1, you write
10100000000000000000000000000000 x<<29
00000000000000000000000000000101 >> 29
but that is not correct (note that your analysis would mean fooBar(5,3) == 1
).
First, the result of 5 << 29
causes overflow for signed 32-bit (or smaller) int
s, which is undefined behaviour.
Next, the result, if the shift creates the indicated bit pattern (as it usually does), would be negative.
Right-shifting negative integers is implementation-defined, common is an arithmetic right shift, that would sign-extend, and here result in
11111111111111111111111111111101 >> 29
which, when xor-ed with 5 gives a non-zero result (and then applying !
produces 0).
Method 2 doesn't work at all, because, leaving aside undefined behaviour for some inputs, all it does is check whether the (32-n)
-th bit is set.
Upvotes: 3