casting between short,int,long,double,float in Java - java

As i understand, when you cast between 2 of these types with an arithmetic operation in Java, for example double + int, the result will be as the bigger type (meaning in this example, the result will be double). What happens when you make an arithmetic operation on 2 types with the same size? what will int + float and long + double give? since int and float are 4 bytes each, and long and double are 8 bytes.

This is all specified by the binary numeric promotion rules in the JLS. From http://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2:
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.
After the type conversion, if any, value set conversion (§5.1.13) is
applied to each operand.
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)
("value set conversion" is about mapping between floating-point representations.)

int + float will give you float (note that you'll have to cast result to float because double is used by default). long + double will give you double.

Still going to return the "bigger" type that can hold the entirely value. In your specific question
if you make a + between a int and a float the return will be a float
and long + double returns a double,

The behavior of the additive operators + and - is defined in by 15.18.2. Additive Operators (+ and -) for Numeric Types of the JLS. It states that it first performs a binary numeric promotion:
Binary numeric promotion is performed on the operand.
This in turns is defined by 5.6.2. Binary Numeric Promotion. In substance, for primitives:
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.

There are two an interesting FAQ on type conversion that can be found in: http://www.programmersheaven.com/2/FAQ-JAVA-Type-Conversion-Casting
http://myhowto.org/java/60-understanding-the-primitive-numeric-type-conversions-in-java/
Answering your questions on two types of the same size, the return value is of the type with the biggest precision.
Try the following code:
public static void main(String[] args) {
int i=1;
float f=2.5f;
long l=10;
double d=3.74;
System.out.println(i+f);
System.out.println(f+i);
System.out.println(l+d);
System.out.println(d+l);
}
You will see that the results are 3.5 and 13.74, which are a float and a double, respectively (tested in Netbeans 6.9 and java 1.6).

A gotcha of this "promotion" is that a long + float will "widen" to using a float.
e.g.
System.out.println(1111111111111111111L + 0.0f);
System.out.println(1111111111111111111L + 0.0);
prints
1.11111113E18
1.11111111111111117E18
When dealing with long and float, you may not get a wider type and can lose more precision than you might expect.

Related

What if a cast operator is used in shift operators

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?
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:
...
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.
...
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.

How does Java handle precision across multiple types?

In Java when I print something like this
System.out.println(1.0f*1l));
I get an output of
1.0
or with
System.out.println(((byte)1)*'A');
I get an output of
65
In both cases, one of the types is bigger than the other. Longs are 64-bits while floats are 32-bits, and bytes are 8-bits while chars are 16-bits. Despite this, Java outputs the result in the smaller type. Wouldn't this be considered a loss of precision?
Java Language Specification provides a list of rules governing the type of result based on the types of operands.
In particular, section 4.2.4 says that
If at least one of the operands to a binary operator is of floating-point type, then the operation is a floating-point operation, even if the other is integral.
which explains why float "wins" against a long.
Integer arithmetic is explained in section 5.6.2. Specifically, it says that
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.
That is why in your second example the result, 65, is of type int.
Java widens type based on the range of possible values. This means float is considered wider thanlong.
Also integer operations which are not long are performed as int.
A byte * char is an int
You are asking about Binary Numeric Promotion (JLS 5.6.2) (emphasis mine):
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.
The expression 1.0f*1l is a float and long, so the long is converted to a float.
The expression ((byte)1)*'A' is a byte and a char, so they are both converted to int.
In addition to the other answers that spell out the rules in detail, I think it's also worth considering why it should be this way. Suppose you do
2.7F * 2L
The true mathematical answer to this multiplication is 5.4. Therefore if the answer were a long, it would have to be 5L (5 is the closest integer to 5.4). Because of this kind of thing it makes much more sense for the result of multiplying a floating-point value by an integer to be a floating point value. I think there would be many more questions about this on Stack Overflow if the following line of code printed 5.
System.out.println(2.7F * 2L);
In fact it prints 5.4.
It also makes sense that all operations between integer types (except long) are done with int. After all, a byte is usually thought of as a small packet of data, and a char is usually thought of as a character. From these perspectives multiplying byte or char values isn't really meaningful. It makes much more sense to keep the rules simple and just do the operations with int.

Data types and variables java [duplicate]

This question already has an answer here:
Why byte and short values are promoted to int when an expression is evaluated [duplicate]
(1 answer)
Closed 7 years ago.
When we do addition,subtractions,divide(etc..)in byte short data types the result is coming from int value...why is that...?
e.g:- in above code does not compile because the result in c is coming from int why is that happen...??? when we try to print c using system out it came error because result is in int
public class A {
public static void main(String[] args) {
byte a = 12;
byte b = 10;
byte c = a + b;
System.out.println(c);
}
}
According to java doc the when we perform operations on two bytes there is probability that the output would be a number which can't be handled by byte, so it was decided by creators of java to auto cast it to Integer. So it's like this.
This is well answered here, starting from an identical scenario :) http://www.coderanch.com/t/499127/java/java/Adding-bytes
To quote http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.6.2
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.
The spec says:
https://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.18.2
The binary + operator performs addition when applied to two operands of numeric type, producing the sum of the operands.
The binary - operator performs subtraction, producing the difference of two numeric operands.
Binary numeric promotion is performed on the operands (§5.6.2).
Note that binary numeric promotion performs value set conversion (§5.1.13) and may perform unboxing conversion (§5.1.8).
The type of an additive expression on numeric operands is the promoted type of its operands.
https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2
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.
If you combine the two you see that any operand in an addition will be promoted to either int or long and any primitive smaller than int will be promoted to int. The result of the operation is the type of both operands - which it int.
The reasoning behind that is most probably that int is the most common datatype which reduces probability of overflow while not requiring as much space as a long. The space argument probably isn't as generally valid as it used to be anymore but that part of the spec was defined like in 1995 and an inherent part of the language (which you can't change without breaking compatibility).
Any Binary arithmetic operations we performed on char & byte datatype(and short) promote it to int.
For more details please refer JLS 5.6.2.
This works:
final byte a = 12;
final byte b = 10;
byte c = a + b;
Or this:
byte a = 12;
byte b = 10;
byte c = (byte)( a + b);

Converting an int to a double by multiplying by 1.0 or adding 1d?

As far as I know, to convert an integer to a double one can multiply the former by "1.0". It's apparently also possible to add "1d" (the double literal) to it. What, then, is the difference?
Thanks!
So, if you mean "add the d to the end of the numeral"...then there's no difference. In Java, by default, all floating-point literals are double.
So these two literals are the same thing:
41.32
41.32d
If you were to add f instead of d, then one would be a float instead of a double.
You can change an int to a double in this way, too:
113
113d
If you're multiplying an int with a double to get a double, then the int is being promoted to a double so that the floating-point arithmetic can take place.
From the JLS:
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.
Adding 'd' is like an explicit cast to a double, multiplying will also convert to double cause
If either operand is of type double, the other is converted to double
before the operation is carried out.
and 1.0 is a double, so multiplying an int by 1.0, would give a result of type double, but would also convert the other operand to double

type calculation in math expressions

I am prepare for ocpjp.
I know that:
byte * byte = int
long * int = long
But I was wondered that float * float = float
float on float may be very huge number and for logically convert it to double.
Anyway for success exam passing I should to know all rules about it.
Please explain me these rules or just point to relevant jls part.
I suppose the relevant part of the JLS is 4.2.4 Floating-Point Operations :
If at least one of the operands to a numerical operator is of type double, then the operation is carried out using 64-bit floating-point arithmetic, and the result of the numerical operator is a value of type double. If the other operand is not a double, it is first widened (§5.1.5) to type double by numeric promotion (§5.6).
Otherwise, the operation is carried out using 32-bit floating-point arithmetic, and the result of the numerical operator is a value of type float. (If the other operand is not a float, it is first widened to type float by numeric promotion.)
So if you multiply two float values, a 32-bit operation is performed. An overflow to infinity will occur if the values are too large.
If you multiply a float by a double, the result will be a double and the float will be expanded to a 64-bit value during the operation.
As a result of my investigation I created following rule:
if (statement contains double)
result-double
else if (statement contains float)
result-float
else if (statement contains long)
result - long
else
result - int

Categories