I've been brushing up on some of the more obscure corners of Java. Here's a pop quiz:
1 << 32 evaluates to:
- 0x100000000
- 0
- 1
Answers below...
A. 0x100000000
-
This value expressed in binary is 1 followed by 32 zeros. But this is the wrong answer. If you shift a byte, short, char, or int the result value is an int, and this value requires 33 bits, so it is a long. If the expression in question had been 1L << 32 this answer would be correct.
B. 0
-
Zero is what we get if we take the long value above and truncate it to fit in an int. Seems logical: the expression should shift 32 zero bits into the result, producing an int of all zeros. But this is wrong, too.
C. 1
-
This is the right answer.
The Java Language Specification specifies that the right-hand operand of the shift operators is masked so that its value is restricted to the range of meaningful values. If the left operand is a byte, short, char, then it is first promoted to an int. If the promoted left operand is an int, then all but the low 5 bits of the right operand are discarded. If the left operand is a long, then all but the low 6 bits of the right operand are discarded.
Our right operand was 32, or 00100000. When we discard all but the low 5 bits we're left with zero. So 1 << 32 is the same as 1 << 0.
I think I knew this at one time, but I would have chosen answer B.
Update
In response to a comment about Java violating the principle of least astonishment, I realized that I didn't know what the answer to this quiz was for C. I assume that Java inherits the behavior from C. I haven't written C in years, but I managed to crank out this program
int main(char **args, int argc) {
int bits = 32;
printf("%d\n", 1 << 32);
printf("%d\n", 1 << bits);
}
The compiler (gcc) issues a warning on the line containing 1 << 32.
When I run it, it prints:
0 1
So, when the compiler can tell that the shift amount is too big, it gives a warning and the expression evaluates to zero. But when the compiler can't tell, it generates code that has the same behavior as C. I think Java ought to issue the warning, but having different behavior in the two cases seems like a bad thing!




I think this is a case where Java violates the principle of least astonishment.
David,
Funny you should mention this; my brother and I based a puzzler on it last year. What does the following program print out:
public class Shifty {
public static void main(String[] args) {
int distance = 0;
while ((-1 << distance) != 0)
distance++;
System.out.println(distance);
}
}
Don't code like my brother,
Click
P.S. Sorry about the lack of formatting. I can't get html tag to work.
ARM has a novel variation on surprises in this area (at least bag in ye olde PROG26 days). MOV r0, #1 / MOV r1, #32 / MOV r0, r0, LSL r1 resulted in r0 as #0. Replace #32 with #256 and r0 would remain #1.
In C the behaviour is undefined when the shift distance is >= the width of the left hand operand (and when the shift distance is negative)
Hi David,
Your quiz is excellent. But in the gcc version 3.3.5 the program displays 1 for both printf.