0

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?

user12208242
  • 315
  • 1
  • 11

2 Answers2

2

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.

      ...

Turing85
  • 18,217
  • 7
  • 33
  • 58
  • So does this mean that even if i am doing (short)100, it will be actually an int 100? – user12208242 Aug 18 '20 at 19:22
  • This does not attempt to answer the question, which asks "what will be the usable bits of the right operand" (not what type the result is) – Bohemian Aug 18 '20 at 19:23
  • No, if you casts a variable, the variable has the casted type. Problem is, though, that the casted value is then used in a binary numeric operation. To be more precise: the expression you posted with explicit parenthesis is `((short) 100) << 100`. Did you mean `(short) (100 << 100)`? – Turing85 Aug 18 '20 at 19:26
  • @Turing85 I got a link which states that it is not a binary numeric operation but a unary one. https://notendur.hi.is/snorri/SDK-docs/lang/lang030.htm#:~:text=5.6.-,1%20Unary%20Numeric%20Promotion,by%20a%20widening%20conversion%20(S5. – user12208242 Aug 18 '20 at 19:29
  • @user12208242 I updated my answer and clarifed what the cast actually casts. Hope this helps =) I also updated the JLS-Section to reflect the unary operator, in both JLS 8 and JLS 14 – Turing85 Aug 18 '20 at 19:53
  • "If you set cast the whole expression to, e.g. short (short s = (short) (i << 2), then there is no automatism that takes place in the compiler. " But even if you cast the whole expression to short (short)(i<<2), your short result will convert to int result as per the numeric promotion. This in turn should give us an error. So is this some kind of exception where promotion is not done or something? Seems like i drowned into another question. – user12208242 Aug 18 '20 at 20:07
  • @user12208242 Shall we continue the discussion in [chat](https://chat.stackoverflow.com/rooms/220051/room-for-turing85-and-user12208242)? – Turing85 Aug 18 '20 at 20:15
0

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.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • While this is technically true, the expression given in the question will always produce `int`s since types `< int` are widened to `int`s. – Turing85 Aug 18 '20 at 19:20
  • @Turing85 the question does not ask what the resulting type is. The question asks *what will be the usable bits of the right operand* – Bohemian Aug 18 '20 at 19:22
  • That is not fully true. the left operand is widened to `int`. Thus, the right operand is bounded by the limit of an int. – Turing85 Aug 18 '20 at 19:24
  • @Turing85 the type of the right hand operand is irrelevant. This is about how many bits of that operand are used. – Bohemian Aug 18 '20 at 19:25
  • ... and this - in return - depends on the type of the **left** operand, which is promoted to `int`. – Turing85 Aug 18 '20 at 19:27
  • @Turing85 you are totally missing the point here. The type of the right hand operand is irrelevant. The type of the left hand operand dictates how many bits of the right hand operand are used **no matter what type it is**. The question only asks **how many bits** of the right hand operand are **useable**. – Bohemian Aug 18 '20 at 19:31
  • My point is that the type of the **left** hand operator for everything`< int` **is** `int` and thus the behaviour is defined in the JLS as `5` bits =) – Turing85 Aug 18 '20 at 19:36
  • This is wrong. Section 15.19 says unary numeric promotion happens on the left operator. This means byte, short, and char are converted to int. So always 5 or 6 bits of the right-hand operator are used. – Aleksandr Dubinsky Aug 08 '21 at 15:52