InvalidBrainException
InvalidBrainException

Reputation: 2362

Bit shifting in Java

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

Answers (6)

Nathan Ryan
Nathan Ryan

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

dshapiro
dshapiro

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

Andy Thomas
Andy Thomas

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

Peter
Peter

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

amit
amit

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 ints (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

Louis Wasserman
Louis Wasserman

Reputation: 198014

Because arithmetic operations on shorts yield ints, 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

  • the bytecode language doesn't really deal with any types smaller than int
  • otherwise operations on shorts overflow much more often.
  • to better model most hardware, which usually doesn't do operations on sub-32-bit values

Upvotes: 3

Related Questions