0
votes

The JLS says that

The type of the shift expression is the promoted type of the left-hand operand.

If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.

If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.

So if I explicitly make a byte and a short operand using the cast operator like (byte)100<<100 and (short)100<<100, what will be the usable bits of the right operand?

Edit: Does an operand undergo a numeric promotion (unary/binary) if it has already been converted to a different (smaller) type using a casting operator? If this is the case, how would you explain the expression having byte variables b1 = (byte)(b2 + b3) because after the cast conversion, the byte result will probably convert to int as per the numeric promotion?

2

2 Answers

2
votes

The Java 8 JLS also states in §5.6.1:

5.6.1. Unary Numeric Promotion

Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type:

...

  • Otherwise, if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).

...

Thus, if we take the following expression:

int i = ...
short s = (short) i << 2;

Will result in a compiler error:

Main.java:4: error: incompatible types: possible lossy conversion from int to short
short s = (short) i << 2;

Ideone demo

This is due to the fact that the cast binds to the first argument of the shift, not the whole expression. Here is the whole expression with explicit parenthesis:

short s = ((byte) i) << 2;

Whereas

int i = ...;
int j = (short) i << 2;

Will successfully compile.

Ideone demo

So the effective bits to use for anything < int is the same as for int (5 bits) since they are upcasted to int automatically.

If you cast the result of the whole expression to, e.g. short (short s = (short) (i << 2), then there is no automatism that takes place in the compiler. But Bohemian's answer gives a logical bound as to what bits of the right hand operator will effectively influence the value after the cast.


In newer JLS versions, the section has been reworded. For example, in Java 14 JLS, §5.6 we find (the section is shortened for breviety, I recommend reading the whole paragraph to get the full context):

5.6. Numeric Contexts

Numeric contexts apply to the operands of arithmetic operators, array creation and access expressions, conditional expressions, and the result expressions of switch expressions.

An expression appears in a numeric arithmetic context if the expression is one of the following:

...

  • An operand of a shift operator <<, >>, or >>> (§15.19). Operands of these shift operators are treated separately rather than as a group. A long shift distance (right operand) does not promote the value being shifted (left operand) to long.

...

Numeric promotion determines the promoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:

...

  1. Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:

    ...

    • Otherwise, none of the expressions are of type double, float, or long. In this case, the kind of context determines how the promoted type is chosen.

      In a numeric arithmetic context or a numeric array context, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.

      In a numeric choice context, the following rules apply:

      ...

      • Otherwise, the promoted type is int, and all the expressions that are not of type int undergo widening primitive conversion to int.

      ...

0
votes

The number of bits of the maximum usable shift distance is given by log2n, where n is the number of bits used to represent values of the left hand type.

byte has 8 bits. log28 is 3. So only the right most 3 bits are used, giving a shift value in the range 0-7.

short has 16 bits. log216 is 4. So only the right most 4 bits are used, giving a shift value in the range 0-15.