I have just created a simple java program by using datatype short.
The program looks like this:
class test
{
public static void main(String arg[])
{
short x=1;
short x_square=x*x;
}
}
This program throws an error:
java:6: possible loss of precision
found : int
required: short
How compiler founds int? There is no int variable in this program all variable are declared as short.
During arithmetic operation the integer types are always treated as int primitive in Java if none of them is of type long. Small integer types are promoted to int and the result of the operation is int. Hence x*x is type casted as int and you are trying to assign it to short. You need an explicit cast to short for this narrowing conversion .
short x_square=(short)(x*x);
Follow the JLS 4.2.2
If an integer operator other than a shift operator has at least one operand of type long, then the operation is carried out using 64-bit precision, and the result of the numerical operator is of type long. If the other operand is not long, it is first widened (§5.1.5) to type long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and the result of the numerical operator is of type int. If either operand is not an int, it is first widened to type int by numeric promotion.
From the specification :
If an integer operator other than a shift operator has at least one
operand of type long, then the operation is carried out using 64-bit
precision, and the result of the numerical operator is of type long.
If the other operand is not long, it is first widened (§5.1.5) to type
long by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit precision, and
the result of the numerical operator is of type int. If either operand
is not an int, it is first widened to type int by numeric promotion.
Adding a short and a short makes an int. If you want to store the result in a variable of type int, you must cast it.
Because the multiplication of two shorts returns an int in java. To get rid of this error you need to have explicit type casting :
short x_square=(short)x*x;
Or, You can also do the following:
short x_square = x;
x_square *= x_square;
Try casting it: short x_square=(short)(x*x)
Related
when exactly does the widening primitive conversion happen in the program?
If I got an expression:
long l = 3L;
double d = 5.2L + l;
are 5.2L and l converted into double and then calculated, or is the calculation happening in long, with the result being converted to double afterwards?
The statement a = b + c consists of 2 operations:
Additive Operator +
JLS §15.18.2. Additive Operators (+ and -) for Numeric Types says:
Binary numeric promotion is performed on the operands (§5.6.2).
JLS §5.6.2. Binary Numeric Promotion says:
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.
Assignment Operator =
JLS §5.2. Assignment Contexts says:
Assignment contexts allow the value of an expression to be assigned (§15.26) to a variable; the type of the expression must be converted to the type of the variable.
Assignment contexts allow the use of one of the following:
an identity conversion (§5.1.1)
a widening primitive conversion (§5.1.2)
...
JLS §5.1.2. Widening Primitive Conversion says:
19 specific conversions on primitive types are called the widening primitive conversions:
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
To re-cap, first the + operator causes the two operands to be widened to int, long, float, or double, whichever first covers both operands. The result of the + operator may then be further widened to fit the variable of the assignment.
Your original code
long l = 3L;
double d = 5.2L + l;
will not compile because 5.2L is not a valid literal.
In answer to your further questions:
which case would happen, if it was 5L instead?
In that case you would be adding two longs, and the result would be a long. That long would be converted to a double if you store it in a double variable.
And what would happen if there was an integer involved?
If you add an int and a long, you get a long. If you are assigning that to a double variable, it will subsequently be converted to a double.
byte a=10;
byte b=20;
b=a+b;
In this case, I need to explicitly convert a+b to byte like this :
b=(byte)(a+b);
It's the same with short :
short x=23;
short y=24;
Otherwise it gives an error.
But in case of integers, it's not required to convert explicitly :
int p=7788;
int q=7668;
p=p+q;
This will work just fine.
Why is that?
We don't need to explicitly cast even in the case of long as well.
If you look at the JLS 4.2.2 Integer Operations, it states that the result of a numerical operation between two integral operands is an int or a long. Since there's no implicit cast from an int to byte or a short, you need an explicit cast.
If you refer to JLS Sec 15.18.2, which deals with addition of numeric types, it says:
Binary numeric promotion is performed on the operands (§5.6.2).
...
The type of an additive expression on numeric operands is the promoted type of its operands.
JLS Sec 5.6.2 describes binary numeric promotion:
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.
So, in the case of int and long (where both operands are of that type), binary numeric promotion is a no-op: the operands remain int and long respectively, and the result of the addition is int and long respectively, meaning the result can be assigned to variables of that type.
In the case of byte and short, binary numeric promotion causes both of those to be widened to int to perform the addition, and the result of the addition is int; you have to explicitly cast back again to the narrower type, because not all int values fit into a byte or short.
There are 2 exceptions to this requirement to do an explicit narrowing cast.
Firstly, compound assignments: this would have worked:
b += a;
because, as stated in JLS Sec 15.26.2:
A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.
In other words: the compiler inserts the cast for you:
b = (byte) ((b) + (a));
Secondly, if the operands have constant values, and the result of the addition is known to fit into the range of the narrower type, and you are doing the assignment at the variable declaration.
For example:
final byte a=10; // final is necessary for a and b to be constant expressions.
final byte b=20;
byte c = a + b;
This requires no cast.
With addition in java, java will promote the smaller data type to the larger one. And when the data type is smaller than int it will promote both the operant to int. Take a look at: Promotion in Java?
This question already has answers here:
char and int in Java
(2 answers)
Closed 4 years ago.
While creating an array, we can pass short, char, byte, int. So, [why] is int[] a = new int['a'] valid? It doesn't throw a compile time error.
What does an array declaration in this form mean?
From JLS Sec 15.10.1:
The type of each dimension expression within a DimExpr must be a type that is convertible (§5.1.8) to an integral type, or a compile-time error occurs.
Each dimension expression undergoes unary numeric promotion (§5.6.1). The promoted type must be int, or a compile-time error occurs.
And from JLS Sec 5.6.1:
If the operand is of compile-time type Byte, Short, Character, or Integer, it is subjected to unboxing conversion (§5.1.8). The result is then promoted to a value of type int by a widening primitive conversion (§5.1.2) or an identity conversion (§5.1.1).
and
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).
So, any of Byte, Short, Character, Integer, byte, short, char or int are acceptable.
Hence 'a', a char literal, is allowed, and is promoted to the int value 97.
Like most times with this kind of questions, the answer lies in the Java Language Specification:
§ 5.1.2. Widening Primitive Conversion
19 specific conversions on primitive types are called the widening primitive conversions:
byte to short, int, long, float, or double
short to int, long, float, or double
char to int, long, float, or double
int to long, float, or double
long to float or double
float to double
(Emphasis mine)
It may or may not be intuitive, but a char is actually an integral type, and the Java rules specify that primitive integral types may be converted to an integral type with a lower or higher-capacity. In this case, it's called a widening primitive conversion.
Andy's answer provides more references to the Java Language Specification, and explicitly states that an expression as in your question is valid.
According to the JLS §15.10.1 Array Creation Expressions,
The type of each dimension expression within a DimExpr must be a type
that is convertible (§5.1.8) to an integral type, or a compile-time
error occurs.
Each dimension expression undergoes unary numeric
promotion (§5.6.1). The promoted type must be int, or a compile-time
error occurs.
Here, unary numeric promotion occurs. Here is an excerpt from §5.6.1:
...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).
Therefore, new int['a'] is valid.
If you are wondering how exactly is a char converted to an int, here is the relevant bits from §5.1.2:
A widening conversion of a char to an integral type T zero-extends the representation of the char value to fill the wider format.
Also note that characters are all encoded as integers.
In java char is integer type (hello C++). This code do same int[] a = new int[97];
a is a char type and it is implicitly casted to an integer with value 97 (ASCII representation, see details here). Therefore you are creating an array of length 97.
If you declare variables of type byte or short and attempt to perform arithmetic operations on these, you receive the error "Type mismatch: cannot convert int to short" (or correspondingly "Type mismatch: cannot convert int to byte").
byte a = 23;
byte b = 34;
byte c = a + b;
In this example, the compile error is on the third line.
Although the arithmetic operators are defined to operate on any numeric type, according the Java language specification (5.6.2 Binary Numeric Promotion), operands of type byte and short are automatically promoted to int before being handed to the operators.
To perform arithmetic operations on variables of type byte or short, you must enclose the expression in parentheses (inside of which operations will be carried out as type int), and then cast the result back to the desired type.
byte a = 23;
byte b = 34;
byte c = (byte) (a + b);
Here's a follow-on question to the real Java gurus: why? The types byte and short are perfectly fine numeric types. Why does Java not allow direct arithmetic operations on these types? (The answer is not "loss of precision", as there is no apparent reason to convert to int in the first place.)
Update: jrudolph suggests that this behavior is based on the operations available in the JVM, specifically, that only full- and double-word operators are implemented. Hence, to operator on bytes and shorts, they must be converted to int.
The answer to your follow-up question is here:
operands of type byte and short are automatically promoted to int before being handed to the operators
So, in your example, a and b are both converted to an int before being handed to the + operator. The result of adding two ints together is also an int. Trying to then assign that int to a byte value causes the error because there is a potential loss of precision. By explicitly casting the result you are telling the compiler "I know what I am doing".
I think, the matter is, that the JVM supports only two types of stack values: word sized and double word sized.
Then they probably decided that they would need only one operation that works on word sized integers on the stack. So there's only iadd, imul and so on at bytecode level (and no operators for bytes and shorts).
So you get an int value as the result of these operations which Java can't safely convert back to the smaller byte and short data types. So they force you to cast to narrow the value back down to byte/short.
But in the end you are right: This behaviour is not consistent to the behaviour of ints, for example. You can without problem add two ints and get no error if the result overflows.
The Java language always promotes arguments of arithmetic operators to int, long, float or double. So take the expression:
a + b
where a and b are of type byte. This is shorthand for:
(int)a + (int)b
This expression is of type int. It clearly makes sense to give an error when assigning an int value to a byte variable.
Why would the language be defined in this way? Suppose a was 60 and b was 70, then a+b is -126 - integer overflow. As part of a more complicated expression that was expected to result in an int, this may become a difficult bug. Restrict use of byte and short to array storage, constants for file formats/network protocols and puzzlers.
There is an interesting recording from JavaPolis 2007. James Gosling is giving an example about how complicated unsigned arithmetic is (and why it isn't in Java). Josh Bloch points out that his example gives the wrong example under normal signed arithmetic too. For understandable arithmetic, we need arbitrary precision.
In Java Language Specification (5.6.2 Binary Numeric Promotion):
1 If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
2 Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.
3 Otherwise, if any expression is of type long, then the promoted type is long, and other expressions that are not of type long undergo widening primitive conversion to long.
4 Otherwise, none of the expressions are of type double, float, or long. In this case, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
Your code belongs to case 4. variables a and b are both converted to an int before being handed to the + operator. The result of + operation is also of type int not byte
If you declare variables of type byte or short and attempt to perform arithmetic operations on these, you receive the error "Type mismatch: cannot convert int to short" (or correspondingly "Type mismatch: cannot convert int to byte").
byte a = 23;
byte b = 34;
byte c = a + b;
In this example, the compile error is on the third line.
Although the arithmetic operators are defined to operate on any numeric type, according the Java language specification (5.6.2 Binary Numeric Promotion), operands of type byte and short are automatically promoted to int before being handed to the operators.
To perform arithmetic operations on variables of type byte or short, you must enclose the expression in parentheses (inside of which operations will be carried out as type int), and then cast the result back to the desired type.
byte a = 23;
byte b = 34;
byte c = (byte) (a + b);
Here's a follow-on question to the real Java gurus: why? The types byte and short are perfectly fine numeric types. Why does Java not allow direct arithmetic operations on these types? (The answer is not "loss of precision", as there is no apparent reason to convert to int in the first place.)
Update: jrudolph suggests that this behavior is based on the operations available in the JVM, specifically, that only full- and double-word operators are implemented. Hence, to operator on bytes and shorts, they must be converted to int.
The answer to your follow-up question is here:
operands of type byte and short are automatically promoted to int before being handed to the operators
So, in your example, a and b are both converted to an int before being handed to the + operator. The result of adding two ints together is also an int. Trying to then assign that int to a byte value causes the error because there is a potential loss of precision. By explicitly casting the result you are telling the compiler "I know what I am doing".
I think, the matter is, that the JVM supports only two types of stack values: word sized and double word sized.
Then they probably decided that they would need only one operation that works on word sized integers on the stack. So there's only iadd, imul and so on at bytecode level (and no operators for bytes and shorts).
So you get an int value as the result of these operations which Java can't safely convert back to the smaller byte and short data types. So they force you to cast to narrow the value back down to byte/short.
But in the end you are right: This behaviour is not consistent to the behaviour of ints, for example. You can without problem add two ints and get no error if the result overflows.
The Java language always promotes arguments of arithmetic operators to int, long, float or double. So take the expression:
a + b
where a and b are of type byte. This is shorthand for:
(int)a + (int)b
This expression is of type int. It clearly makes sense to give an error when assigning an int value to a byte variable.
Why would the language be defined in this way? Suppose a was 60 and b was 70, then a+b is -126 - integer overflow. As part of a more complicated expression that was expected to result in an int, this may become a difficult bug. Restrict use of byte and short to array storage, constants for file formats/network protocols and puzzlers.
There is an interesting recording from JavaPolis 2007. James Gosling is giving an example about how complicated unsigned arithmetic is (and why it isn't in Java). Josh Bloch points out that his example gives the wrong example under normal signed arithmetic too. For understandable arithmetic, we need arbitrary precision.
In Java Language Specification (5.6.2 Binary Numeric Promotion):
1 If any expression is of type double, then the promoted type is double, and other expressions that are not of type double undergo widening primitive conversion to double.
2 Otherwise, if any expression is of type float, then the promoted type is float, and other expressions that are not of type float undergo widening primitive conversion to float.
3 Otherwise, if any expression is of type long, then the promoted type is long, and other expressions that are not of type long undergo widening primitive conversion to long.
4 Otherwise, none of the expressions are of type double, float, or long. In this case, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
Your code belongs to case 4. variables a and b are both converted to an int before being handed to the + operator. The result of + operation is also of type int not byte