Reputation: 2362
Here is a Java program that left shifts the short
value of 2
. I have two questions:
Why does num << i
for values of i
between 16 and 29 produce valid results? A short
should only hold values from -32,768 to 32,767.
So I thought, maybe System.out.println
interprets num << i
as a value larger than a short
. But then why does it start producing unexpected values at num << 30
?
public class LeftShift {
public static void main(String[] args)
{
short num = 2;
for (int i = 0; i < 32; i++) {
System.out.println("Left-shifting 2 by " + i + " places yields: "
+ (num << i));
}
}
}
The output:
Left-shifting 2 by 0 places yields: 2
Left-shifting 2 by 1 places yields: 4
Left-shifting 2 by 2 places yields: 8
Left-shifting 2 by 3 places yields: 16
Left-shifting 2 by 4 places yields: 32
Left-shifting 2 by 5 places yields: 64
Left-shifting 2 by 6 places yields: 128
Left-shifting 2 by 7 places yields: 256
Left-shifting 2 by 8 places yields: 512
Left-shifting 2 by 9 places yields: 1024
Left-shifting 2 by 10 places yields: 2048
Left-shifting 2 by 11 places yields: 4096
Left-shifting 2 by 12 places yields: 8192
Left-shifting 2 by 13 places yields: 16384
Left-shifting 2 by 14 places yields: 32768
Left-shifting 2 by 15 places yields: 65536
Left-shifting 2 by 16 places yields: 131072
Left-shifting 2 by 17 places yields: 262144
Left-shifting 2 by 18 places yields: 524288
Left-shifting 2 by 19 places yields: 1048576
Left-shifting 2 by 20 places yields: 2097152
Left-shifting 2 by 21 places yields: 4194304
Left-shifting 2 by 22 places yields: 8388608
Left-shifting 2 by 23 places yields: 16777216
Left-shifting 2 by 24 places yields: 33554432
Left-shifting 2 by 25 places yields: 67108864
Left-shifting 2 by 26 places yields: 134217728
Left-shifting 2 by 27 places yields: 268435456
Left-shifting 2 by 28 places yields: 536870912
Left-shifting 2 by 29 places yields: 1073741824
Left-shifting 2 by 30 places yields: -2147483648
Left-shifting 2 by 31 places yields: 0
Upvotes: 2
Views: 5784
Reputation: 13041
Note that compound assignment operators will cast the result to the assigned type. So, modifying your example:
public static void main(String[] args) {
for (int i = 0; i < 32; i++) {
short num = 2;
num <<= i; // equivalent to num = (short)(num << i);
System.out.println("Left-shifting 2 by " + i + " places yields: " + num);
}
}
This will yield different results, maybe more what you were expecting.
Upvotes: 3
Reputation: 1107
See this SO thread.
The part relevant to this question is this quote from here:
If an integer operator has an operand of type long, then the other operand is also
converted to type long. Otherwise the operation is performed on operands of type int, if
necessary shorter operands are converted into int.
I think the idea is that these widening conversions don't lose information, and could potentially protect you in the case of an overflow. See Chapter 5 of the Java language specification to learn more about widening and narrowing conversions.
Upvotes: 1
Reputation: 86381
From the Java language specification, 15.19: "Shift operators"
The type of the shift expression is the promoted type of the left-hand operand.
The promoted type is defined by 5.6: "Numeric promotions":
Otherwise, if the operand is of compile-time type byte, short, or char, unary numeric promotion promotes it to a value of type int by a widening conversion (§5.1.2).
Upvotes: 3
Reputation: 6362
What is happening is automatic promotion of operands. In Java, the result of the (num << i)
expression in your example is of type int
. This is why the result is in the range of an int
and not a short
.
If you tried to assign (num << i)
back into a short
, you'd get a compile error, forcing you to cast back to a short
.
Upvotes: 1
Reputation: 178411
The unexpected value for 30 is an integer overflow, the MSB becomes 1 - and thus is interpeted as a negative number.
Also note that the operator << is yielding int
s (unless the argument is a long
, then it yields a long
). (In fact, the short
is being widened to an int
first, and only then the <<
is evaluated.) So the result is as expected - an int
, not a short
.
Upvotes: 2
Reputation: 198014
Because arithmetic operations on short
s yield int
s, unless you cast them back down. For example,
short value = 2;
short result = value << 31;
gives you a compile error that you need to cast it down to a short
.
This is for a couple reasons, most notably
int
short
s overflow much more often.Upvotes: 3