Basic arithmetic operations on int - Java - java

I recently noticed an idiosyncrasy of Java regarding basic arithmetic operations in Java. With the following code
byte a = 3;
byte b = 4;
byte c = a * b;
I get a "type mismatch" compilation error...
Are basic arithmetic operations in Java (+, -, *, /) only performed on primitive data types of int and higher order (long, double, etc.), whereas arithmetic operations on byte and short are first cast to int and then evaluated?

Operations on byte, char and short are widened to int unless the compiler can determine the value is in range.
final byte a = 3, b = 4;
byte c = a * b; // compiles
final byte a = 3, b = 40;
byte c = a * b; // compiles
final int a = 3, b = 4;
byte c = a * b; // compiles !!
but
byte a = 3, b = 4;
byte c = a * b; // doesn't compile as the result of this will be `int` at runtime.
final byte a = 30, b = 40;
byte c = a * b; // doesn't compile as the value is too large, will be an `int`
BTW This compiles even though it results in an overflow. :]
final int a = 300000, b = 400000;
int c = a * b; // compiles but overflows, is not made a `long`

The result of integer operations is either int or long. This is spelled out in the JLS:
4.2.2. Integer Operations
The numerical operators, which result in a value of type int or long:
The unary plus and minus operators + and - (§15.15.3, §15.15.4)
The multiplicative operators *, /, and % (§15.17)
The additive operators + and - (§15.18)
...
Also:
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:
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.
...
Binary numeric promotion is performed on the operands of certain operators:
The multiplicative operators *, / and % (§15.17)
The addition and subtraction operators for numeric types + and - (§15.18.2)
The numerical comparison operators <, <=, >, and >= (§15.20.1)
The numerical equality operators == and != (§15.21.1)
The integer bitwise operators &, ^, and | (§15.22.1)
In certain cases, the conditional operator ? : (§15.25)

Related

Adding Byte and Short [duplicate]

The rules for promotion is "when operands are of different types, automatic binary numeric promotion occurs with the smaller operand type being converted to the larger". But the operands are of same type for example,
byte=byte+byte // Compile time error... found int..
So why is it so?
There's no + operator for byte. Instead, both operands are promoted to int, so you've got
byte = byte + byte
... becomes (widening to find + operator) ...
byte = int + int
... becomes (result of + operator) ...
byte = int
... which then fails because there's no implicit conversion from int to byte. You need to cast:
byte a = 1;
byte b = 2;
byte c = (byte) (a + b);
Here are the actual rules for numeric promotion, from section 5.6.2 of the JLS:
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, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
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.
You were provided with correct answer about automatic promotion to 'int'.
There is one more note about that - compound assignment operators behave as they have an implicit type case. Example:
byte b1 = 1;
byte b2 = 2;
b1 = b1 + b2; // compilation fails
b1 += b2; // compilation successful
I would like to talk about Promotion in general
Java can evaluate only arithmetic expressions in which the operands’ types are identical
For example, in an expression containing int and double values, the int values are promoted to double values for use in the expression.
in another word
double someVar = 1 / 2;// someVar = 0
but
double someVar = (double)1 / 2;// someVar = 0.5
why?
we use the (double) cast operator to create a temporary
floating-point copy of its operand "1" (it's called explicit conversion)
The calculation now consists of a floating-point value (the temporary double copy of 1) divided by the integer 2
according to the above statement, Java performs an operation called promotion (or implicit conversion), so the int values are promoted to double values for use in the expression => the integer 2 is promoted to double
the expression became double someVar = 1.0 / 2.0; // someVar= 0.5
hope this is helpful, even if it is out of the core of the question
To understand this you should refer the 2 things:
Implicit Casting:
byte (8 bit) -> short (16 bit) -> int (32 bit) -> float (32 bit) -> double (64 bit)
char (16 bit) -> int (32 bit)
Arithmetic Operator Rules
Operator Precedence Rule : This rule states that Group of (*,/, %) will be evaluated first. Then Group of (+,-) operator will be evaluated. From a same Group of Operators, calculate from the left.
Operand Promotion Rule : This rule states that Operands having data type smaller than int will be promoted to int. order of promotion (byte->short->int, char->int)
Same Type Operand Rule: This rule states that if both operands are int,long,float,double then the same type is carried to the result type.
i.e. long+long => long , float + float => float, int+int => int
Mix Type Operand Rule : Follow the order of Promotion (int->long->float->double) if any of the operand is from the above order then the smaller will be promoted to the bigger one and result will be calculated in bigger type.
i.e. long + double => double , int + long => long
From this SO question, and above answers due to + arithmetic operator, both operands are converted to type int.
byte b1 = 1;
byte b2 = 2;
byte b3 = b1 + b2; // compile time error
In above code, value of b1 and b2 will be resolved at runtime, so compiler will convert both to int before resolving the value.
But if we consider the following code,
final byte b1 = 1;
final byte b2 = 2;
int b3 = b1 + b2; // constant expression, value resolved at compile time
b1 and b2 are final variables and values will be resolved at compile time so compilation won't fail.

Type promotion in Java [duplicate]

This question already has answers here:
Multiplying two bytes
(2 answers)
Closed 4 years ago.
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?
(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:
If any operand is of a reference type, it is subjected to unboxing conversion (§5.1.8).
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.
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
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.
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!!

Largest Java Short (32767) plus 1 not turning negative?

recently I learned about the two's compliment method of representing both positive and negative integers in the base two system. I then tried to see this in action using java with the following short code:
int a=2147483647;
System.out.println("a: "+a);
System.out.println("a+1: "+(a+1));
short b=32767;
System.out.println("b: "+b);
System.out.println("b+1: "+(b+1));
Which outputs:
a: 2147483647
a+1: -2147483648
b: 32767
b+1: 32768
Which confuses me because I would think that b+1, being represented in binary as 011111111111111, would turn into 1000000000000000, or in decimal, -32768. What's going on?
Although b is a short, the expression (b + 1) is an int. The right operand is an int, the left operand is promoted to an int, and the expression is the promoted type of the operands.
From the Java Language Specification, 5.6.2. Binary Numeric Promotion:
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.
Note that this last promotion occurs even if both operands are of short type. You can't avoid promotion to an int with (b + (short) 1).
From 15.18.2. Additive Operators (+ and -) for Numeric Types
The type of an additive expression on numeric operands is the promoted type of its operands.
No need for confusion, try this:
short b = 32767;
short c = b + 1;
What do you get? Right, you get:
error: incompatible types: possible lossy conversion from int to short
short c = b + 1;
So, what happens at your line?
System.out.println("b+1: "+(b+1));?
Well, b+1 is too big for short, as you said correctly, but here you add an int to it, making the result an int as well. And 32768 is a valid int.
As others already pointed out, if you explicitly cast it down to (short) you get what you asked for.
On the other hand that does not work for short c = b + 1; as here the declared type is a short, while the actual type is an int.
short c = (short) (b + 1); solves that "problem"
doing + automatically promotes short to int. Do this and you will see the overflow.
System.out.println("b+1: "+(short)(b+1)); //-32768
From the Java Language Specification, 5.6.2. Binary Numeric Promotion:
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.
Notice the last rule, so essentially that means that even if they are both shorts, they will be promoted to int, this can't be avoided.
you could:
short b= 32767;
short d= 12;
System.out.println("b+1: "+ (d+b)); // 32779
And the answer would still be valid.
1 is an int literal. When you compute b+1, you in fact promote b to an int and then add 1, resulting in 32768, which is a perfectly legal int value. If you cast it down to a short again, you'll see the overflow you're expecting (-32768):
System.out.println("b+1: " + (short)(b + 1));
As others have noted, addition promotes the operands to int.
Note that the += operator automatically does the casting back to short:
short b=32767;
System.out.println(b + 1); // 32768, because of integer promotion.
b += 1; // Equivalent to b = (short)(b + 1);
System.out.println(b); // -32768
b++;/++b; would yield the same result as b += 1.

Basic java logic expression is incorrect [duplicate]

I have seen it discussed somewhere that the following code results in obj being a Double, but that it prints 200.0 from the left hand side.
Object obj = true ? new Integer(200) : new Double(0.0);
System.out.println(obj);
Result: 200.0
However, if you put a different object in the right hand side, e.g. BigDecimal, the type of obj is Integer as it should be.
Object obj = true ? new Integer(200) : new BigDecimal(0.0);
System.out.println(obj);
Result: 200
I presume that the reason for this is something to do with casting the left hand side to a double in the same way that it happens for integer/double comparisons and calculations, but here the left and right sides do not interact in this way.
Why does this happen?
You need to read section 15.25 of the Java Language Specification.
In particular:
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
If one of the operands is of type byte or Byte and the other is of type short or Short, then the type of the conditional expression is short.
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression of type int whose value is representable in type T, then > - the type of the conditional expression is T.
If one of the operands is of type Byte and the other operand is a constant expression of type int whose value is representable in type byte, then the type of the conditional expression is byte.
If one of the operands is of type Short and the other operand is a constant expression of type int whose value is representable in type short, then the type of the conditional expression is short.
If one of the operands is of type; Character and the other operand is a constant expression of type int whose value is representable in type char, then the type of the conditional expression is char.
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion (§5.1.8) and value set conversion (§5.1.13).
So binary numeric promotion is applied, which starts with:
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, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double, the other is converted to double.
That's exactly what happens here - the parameter types are converted to int and double respectively, the second operand (the third in the original expression) is then of type double, so the overall result type is double.
Numeric conversion in the conditional operator ? :
In the conditional operator a?b:c, if both b and c are different numeric types, the following conversion rules are applied at compile time to make their types equal, in order:
The types are converted to their corresponding primitive ones, which is called unboxing.
If one operand were a constant int (not Integer before unboxing) whose value is representable in the other type, the int operand is converted into the other type.
Otherwise the smaller type is converted into the next greater one until both operands have the same type. The conversion orders are:
byte -> short -> int -> long -> float -> double
char -> int -> long -> float -> double
Eventually the whole conditional expression gets the type of its second and third operands.
Examples:
If you combine char with short, the expression becomes int.
If you combine Integer with Integer, the expression becomes Integer.
If you combine final int i = 5 with a Character, the expression becomes char.
If you combine short with float, the expression becomes float.
In the question's example, 200 is converted from Integer into double, 0.0 is unboxed from Double into double and the whole conditional expression becomes becomes double which is eventually boxed into Double because obj is of type Object.
Example:
public static void main(String[] args) {
int i = 10;
int i2 = 10;
long l = 100;
byte b = 10;
char c = 'A';
Long result;
// combine int with int result is int compiler error
// result = true ? i : i2; // combine int with int, the expression becomes int
//result = true ? b : c; // combine byte with char, the expression becomes int
//combine int with long result will be long
result = true ? l : i; // success - > combine long with int, the expression becomes long
result = true ? i : l; // success - > combine int with long, the expression becomes long
result = true ? b : l; // success - > combine byte with long, the expression becomes long
result = true ? c : l; // success - > char long with long, the expression becomes long
Integer intResult;
intResult = true ? b : c; // combine char with byte, the expression becomes int.
// intResult = true ? l : c; // fail combine long with char, the expression becomes long.
}

Why does the ternary operator unexpectedly cast integers?

I have seen it discussed somewhere that the following code results in obj being a Double, but that it prints 200.0 from the left hand side.
Object obj = true ? new Integer(200) : new Double(0.0);
System.out.println(obj);
Result: 200.0
However, if you put a different object in the right hand side, e.g. BigDecimal, the type of obj is Integer as it should be.
Object obj = true ? new Integer(200) : new BigDecimal(0.0);
System.out.println(obj);
Result: 200
I presume that the reason for this is something to do with casting the left hand side to a double in the same way that it happens for integer/double comparisons and calculations, but here the left and right sides do not interact in this way.
Why does this happen?
You need to read section 15.25 of the Java Language Specification.
In particular:
Otherwise, if the second and third operands have types that are convertible (§5.1.8) to numeric types, then there are several cases:
If one of the operands is of type byte or Byte and the other is of type short or Short, then the type of the conditional expression is short.
If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression of type int whose value is representable in type T, then > - the type of the conditional expression is T.
If one of the operands is of type Byte and the other operand is a constant expression of type int whose value is representable in type byte, then the type of the conditional expression is byte.
If one of the operands is of type Short and the other operand is a constant expression of type int whose value is representable in type short, then the type of the conditional expression is short.
If one of the operands is of type; Character and the other operand is a constant expression of type int whose value is representable in type char, then the type of the conditional expression is char.
Otherwise, binary numeric promotion (§5.6.2) is applied to the operand types, and the type of the conditional expression is the promoted type of the second and third operands. Note that binary numeric promotion performs unboxing conversion (§5.1.8) and value set conversion (§5.1.13).
So binary numeric promotion is applied, which starts with:
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, using widening conversion (§5.1.2) to convert operands as necessary:
If any of the operands is of a reference type, unboxing conversion (§5.1.8) is performed. Then:
If either operand is of type double, the other is converted to double.
That's exactly what happens here - the parameter types are converted to int and double respectively, the second operand (the third in the original expression) is then of type double, so the overall result type is double.
Numeric conversion in the conditional operator ? :
In the conditional operator a?b:c, if both b and c are different numeric types, the following conversion rules are applied at compile time to make their types equal, in order:
The types are converted to their corresponding primitive ones, which is called unboxing.
If one operand were a constant int (not Integer before unboxing) whose value is representable in the other type, the int operand is converted into the other type.
Otherwise the smaller type is converted into the next greater one until both operands have the same type. The conversion orders are:
byte -> short -> int -> long -> float -> double
char -> int -> long -> float -> double
Eventually the whole conditional expression gets the type of its second and third operands.
Examples:
If you combine char with short, the expression becomes int.
If you combine Integer with Integer, the expression becomes Integer.
If you combine final int i = 5 with a Character, the expression becomes char.
If you combine short with float, the expression becomes float.
In the question's example, 200 is converted from Integer into double, 0.0 is unboxed from Double into double and the whole conditional expression becomes becomes double which is eventually boxed into Double because obj is of type Object.
Example:
public static void main(String[] args) {
int i = 10;
int i2 = 10;
long l = 100;
byte b = 10;
char c = 'A';
Long result;
// combine int with int result is int compiler error
// result = true ? i : i2; // combine int with int, the expression becomes int
//result = true ? b : c; // combine byte with char, the expression becomes int
//combine int with long result will be long
result = true ? l : i; // success - > combine long with int, the expression becomes long
result = true ? i : l; // success - > combine int with long, the expression becomes long
result = true ? b : l; // success - > combine byte with long, the expression becomes long
result = true ? c : l; // success - > char long with long, the expression becomes long
Integer intResult;
intResult = true ? b : c; // combine char with byte, the expression becomes int.
// intResult = true ? l : c; // fail combine long with char, the expression becomes long.
}

Categories

Resources