15

I have a problem with the below Java statements:

byte b = 10;
byte r = (byte) (b * b); // Giving correct result
byte r = (byte) b * b; // Giving error " POSSIBLE LOSS OF PRECISION"

Why is it mandatory to give parentheses to b * b?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
praveen padala
  • 186
  • 1
  • 1
  • 8
  • 10
    `(byte) b * b` makes a `byte * int`, which will return an `int` that you then attempt to assign to a `byte` – ernest_k Jan 16 '19 at 08:13
  • Interestingly if you were doing `b *= b;`, that would compile as in that case the language specification requires an implicit casting to the original type. – Gábor Bakos Jan 16 '19 at 08:15
  • 1
    @ernest_k I admit I haven't looked at the spec for a while, but does byte * byte always return an int? – Powerlord Jan 16 '19 at 08:19
  • @Powerlord It does indeed always produce an `int`. [This](https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2) is the only spec I found for it. If you look at the [bytecode list](https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings), you'll also see that there are no instructions for arithmetic for `byte`s; so it has to use `imul` – TiiJ7 Jan 16 '19 at 08:25
  • @Powerlord Yes, `byte*byte` reurns `int`, that's why the second line needs a cast. – ernest_k Jan 16 '19 at 08:25
  • @Powerlord Yes, according to [jls8 §4.2.2](https://docs.oracle.com/javase/specs/jls/se8/jls8.pdf) a multiplicative operator on an integral type will result in a value of either `int` or `long`. The same error like in the question will happen for multiplying `char` or `short` aswell – Mark Jan 16 '19 at 08:27
  • 1
    Might also be useful to check [What is the priority of casting in java?](https://stackoverflow.com/questions/23464036/what-is-the-priority-of-casting-in-java) – ernest_k Jan 16 '19 at 08:27
  • 7
    Fun fact: making `b` `final` allows it to compile. – Andy Turner Jan 16 '19 at 08:42
  • @AndyTurner I think that is because the constant folding allows to optimize and figure out that the result fits in a byte too, no need to widen to int. – Gábor Bakos Jan 16 '19 at 09:03

4 Answers4

25

(byte) b * b casts the value of the first b to byte (which is redundant since it was already byte), and multiples it by the value of the second b. Multiplying two bytes promotes them to int first, since there is no * operator for bytes. Therefore the result is int, and cannot be assigned to a byte variable.

On the other hand, (byte)(b * b) casts the int multiplication result to byte, which can be assigned to a byte variable.

This is covered in the JLS in 5.6.2. Binary Numeric Promotion:

When an operator applies binary numeric promotion to a pair of operands, each of which must denote a value that is convertible to a numeric type, the following rules apply, in order:

  1. If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).

  2. Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

    • If either operand is of type double, the other is converted to double.

    • Otherwise, if either operand is of type float, the other is converted to float.

    • Otherwise, if either operand is of type long, the other is converted to long.

    • Otherwise, both operands are converted to type int.

Eran
  • 387,369
  • 54
  • 702
  • 768
6

Casting problem

byte r = (byte) (b * b);

It casts the (byte) type to the result of (b * b)

byte r = (byte) b * b;

It casts the (byte) type to the first b only, therefore it will become ((byte) b) * b

letsintegreat
  • 3,328
  • 4
  • 18
  • 39
Cyrus Leung
  • 106
  • 5
2

By the precedence rule you are casting only the first b to byte instead of the whole result.

And Java follow some rules, as you can see here

All integer values (byte, short and int) in an arithmetic operations (+, , *, /, %) are converted to int type before the arithmetic operation in performed. However, if one of the values in an arithmetic operation (+, , *, /, %) is long, then all values are converted to long type before the arithmetic operation in performed.

So, by just casting the first b you are doing this:

byte = byte * integer

Hence:

byte = integer

Thus, raised error.

letsintegreat
  • 3,328
  • 4
  • 18
  • 39
israelss
  • 322
  • 3
  • 6
0

Variables of type byte must be [-128,127], that is why the compiler must not accept any operation, b*b;b+b;b-b;b/b without a cast on the result of operation, like: (byte)(b*b).

In the code below, when you change the result type to int it compiles.

 byte b=10;
    byte c=(byte)b*b;      //incompatible but correct when c is int
    byte d=((byte)b)*b;      //incompatible but correct when d is int
    byte r=(byte)(b*b); 
    byte t= b*b;             //incompatible but correct when t is int
    byte e=(byte)b/b;      //incompatible but correct when e is int
    byte f=((byte)b)/b;      //incompatible but correct when f is int
    byte o=(byte)(b/b); 
    byte w=b/b;             //incompatible but correct when w is int
    byte g=(byte)b+b;      //incompatible but correct when g is int
    byte p=((byte)b)+b;      //incompatible but correct when p is int
    byte q=(byte)(b+b);
    byte x=b+b;             //incompatible but correct when x is int
    byte h=(byte)b-b;      //incompatible but correct when h is int
    byte v=((byte)b)-b;      //incompatible but correct when v is int
    byte s=(byte)(b-b);
    byte y=b-b;               //incompatible but correct when y is int
    byte k=(byte)b;
    byte u=b;   

NOTE

As @andy Truner pointed out in comments, when b is final, all the previous instructions compile!!, except for the following set up:

   final byte fn=-120;
    byte z=fn-b;               //this does not compile even when both final, because the result would be -130, out of the byte type interval!!
TiyebM
  • 2,684
  • 3
  • 40
  • 66