I am pretty new to Java. Came across a problem and would like to gain more insight on it.
The following code doesn't compile :
byte a = 10;
byte b = 20;
byte c = a + b;
Compilation error -> Type mismatch: cannot convert from int to byte
Its a compilation error since :
All integer literals are treated as Integers in Java.
So, a+b results in an integer literal which needs to be typecasted to byte before storing in a byte type variable since there might be a loss of precision. I completely understands the above concept.
What confuses me is a similar concept with float variables. The below code snippet compiles successfully:
float d = 1.2;
float e = 2.3;
float f = d + e;
According to Java :
All decimal literals are treated as Decimal in Java.
So, on similar note (d + e) must result in a decimal literal which will treated as decimal type and is getting stored in a float type variable. Here also we have a loss of precision. Why compiler doesn't force us here for explicit typecasting as in earlier case ? Why is it not a compilation error here ?
Type casting ambiguity in Java
There are no typecasts in the code you posted.
The following code doesn't compile :
byte a = 10;
byte b = 20;
byte c = a + b;
Compilation error -> Type mismatch: cannot convert from int to byte
Its a compilation error since :
All integer literals are treated as Integers in Java.
No it isn't. It's a compilation error because all operations between types narrower than int produce int values. JLS #4.2.2 Integer Operations:
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.
If what you claim as a Java rule really was a Java rule, all three lines would have failed to compile. But there is no such rule in Java as the one you claim. You just made it up.
So, a+b results in an integer literal
No it doesn't. It results in an integer value.
which needs to be typecasted to byte before storing in a byte type variable since there might be a loss of precision. I completely understands the above concept.
No, you don't understand it at all.
What confuses me is a similar concept with float variables. The below code snippet compiles successfully:
float d = 1.2;
float e = 2.3;
No it doesn't. Both lines produce compilation errors: error: incompatible types: possible lossy conversion from double to float.
float f = d + e;
This compiles.
According to Java :
All decimal literals are treated as Decimal in Java.
There is no such rule. Again you have just made this up. There is no such thing as a 'decimal literal' in Java, or Decimal either.
So, on similar note (d + e) must result in a decimal literal
No. It results in a float value.
which will treated as decimal type
There is no 'decimal type' in Java. There is BigDecimal, which is a class, not a type, but it doesn't relate to this question in any way.
and is getting stored in a float type variable. Here also we have a loss of precision.
No we don't. JLS #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.)
You wrote:
Why compiler doesn't force us here for explicit typecasting as in earlier case? Why is it not a compilation error here?
Because it isn't an error. It isn't an instance of the previous error because it doesn't involve types narrower than int.
Don't just make rules up and then ask why Java doesn't comply with them. Check the actual rules.
In java you can't declare float values as :
float d = 1.2;
float e = 2.3;
Because compiler infers 1.2 and 2.3 as double. You have to cast them to float:
float d = (float) 1.2;
float e = (float) 2.3;
or
float d = 1.2f;
float e = 2.3f;
Related
Today, I defined two float variable f1 and f2. Then I perform an addition, "+", arithmetic operation and assign to float variable f.
float f1 = 0.5048076923076923F;
float f2 = 0.5048076923076923F;
float f = f1 + f2;
This is the output:
According to this picture, All floating point values (float and double) in an arithmetic operation (+, −, *, /) are converted to double type:
picture source: http://www.mathcs.emory.edu/~cheung/Courses/170/Syllabus/04/mixed.html
I found an identical question but it hasn't explain why. Why doesn't eclipse have any issue tips? Is it the reason why the value of "f1 + f2" is a float type? And, why will Java auto convert the double to float type if like the above picture saying?
You seem to be saying that there is a conversion to float in the following.
float f1 = 0.5048076923076923F;
float f2 = 0.5048076923076923F;
float f = f1 + f2;
In fact, there is no conversion. The values are all float.
In particular, the literal 0.5048076923076923F is a float. The trailing F makes it a float. If you want a double literal, leave off the F or replace it with D.
When your teacher says "all floating point values are converted to double" he is wrong. The JLS says (in effect) that a numeric primitive operand will be converted to double when the other operand is a double. If both operands are float, then the operation will performed using single-precision floating point arithmetic.
The JLS reference is JLS 5.6.2: Binary Numeric Promotion.
It has been pointed out that there may be additional conversions happening at the hardware level. For example, the JLS says this:
Within an expression that is not FP-strict, some leeway is granted for an implementation to use an extended exponent range to represent intermediate results; the net effect, roughly speaking, is that a calculation might produce "the correct answer" in situations where exclusive use of the float value set or double value set might result in overflow or underflow.
However:
This is only allowed if the expression is not strictfp.
These are not the "conversions" that the JLS talks about in JLS 5.6.2.
This still contradicts what the OP's teacher is saying. He (or she) states that the all floating point calculations are done using double. The JLS states that under certain circumstances, a hardware platform may use extended precision arithmetic (possibly with more precision than 64 bit floating point), and in other circumstances it must not do this.
Your teacher is incorrect, kindly refer him to section 5.6.2 of the Java Language Specification, which states:
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.
As you can see, floats are only converted to double if the other operand is a double, not in all cases as your syllabus incorrectly states.
That is, the sum of two floats is a float, but the sum of a float and a double is a double.
PS: And no, Java will never convert a double to a float unless you explicitly ask it to, as in:
float f = (float) Math.PI;
Hi for floating points values JVM uses instructions like this:
'+' : fadd : pops two floats, adds them, and pushes the float result
'-' : fsub : pops two floats, subtracts them and pushes the flot result
similarly for there are other instructions set for other operators like * and / etc.
So as per JVM implementation point of view float + float will result to float.
But float + double will result to double.
For more information, you can read chapter 14. Floating-Point Arithmetic
of the book "Inside Java Virtual Machine"
What the other answers are missing is the hardware level. Floating point processors, in general, convert all operations to double (or quad), and then return the result in the requested precision. The Java specification may not recognize the conversion, but if it uses the floating point hardware then the conversion happens.
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
int m = 10;
int f = 3;
float r = (float)m/f; // gives 3.333333 as output
float r = (float)(m/f); // gives 3.0 as output
Can anyone tell me how the parentheses are changing the answer because I am basically typecasting the integer value of m/f into float. What I don't understand is how the addition of brackets around m/f is changing the answer.
In the second case:
(float)(m/f)
you are doing integer division first and then casting to float and therefore you lose the fraction. In the first case you cast m to float and therefore end up performing floating point division.
The cast operator has higher precedence in both C++ and Java but using parenthesis around the division forces it to be evaluated first.
In C++ his behavior is due to the usual arithmetic conversions which is covered in the draft C++ standard section 5 Expressions paragraph 10 which says:
Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield
result types in a similar way. The purpose is to yield a common type, which is also the type of the result.
This pattern is called the usual arithmetic conversions, which are defined as follows:
and includes the following bullet:
— Otherwise, if either operand is float, the other shall be converted to float.
In Java this behavior is covered in the JLS section 5.6.2. Binary Numeric Promotion which says:
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:
and includes:
Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:
and includes:
Otherwise, if either operand is of type float, the other is converted to float.
and includes the following example:
int i = 0;
float f = 1.0f;
// First int*float is promoted to float*float, then
The difference is what gets converted to float. In the first case m gets converted to float, so the entire expression becomes floating point. In the second, you perform the expression (integer division) and then convert to float, at which point it's too late to save those precious significant digits.
(float)m/f divides (float)m by f. Since one of the operands is a float, the operator is floating-point division, and the answer is 3.333 etc.
(float)(m/f) calculates (m/f) and casts it to float. Since both operands are integer, the operation is integer division, and m/f is 3. Then 3 is casted to float to become 3.0.
On the first example, m gets casted to float first then divided which gives you a floating-point number. The second example, the division is an int division so it will give you an int number that then gets transformed to a floating-point number.
Adding parentheses, change precedence of operators. Type casting is applied before division normally but using parentheses you tell compiler to divide before casting to float.
Order of operations: Casting applies before division, and division between two integers always rounds (down) to the nearest integer in Java.
float r = (float)m/f; // Is the same as ((float)m)/f, and because there's a
// float in the division, we keep everything a float.
float r = (float)(m/f); // Is division between two integers, so we round down
// to the nearest integer before casting to a float.
I'm doing multiplication and division of floats and ints and I forget the implicit conversion rules (and the words in the question seem too vague to google more quickly than asking here).
If I have two ints, but I want to do floating-point division, do I need only to cast one or both of the operands? How about for multiplication — if I multiply a float and an int, is the answer a float?
You can’t assign to an int result from division of a float by an int or vice-versa.
So the answers are:
If I have two ints, but I want to do floating point division…?
One cast is enough.
If I multiply a float and an int, is the answer a float?
Yes it is.
float f = 1000f;
int i = 3;
f = i; // Ok
i = f; // Error
f = i/f; //Ok 0.003
f = f/i; //Ok 333.3333(3)
i = i/f; //Error
i = f/i; //Error
To demonstrate:
int i1 = 5;
float f = 0.5f;
int i2 = 2;
System.out.println(i1 * f);
System.out.println(i1 / i2);
System.out.println(((float) i1) / i2);
Result:
2.5
2
2.5
In order to perform any sort of floating-point arithmetic with integers, you need to convert (read: cast) at least one of the operands to a float type.
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.
(Source: Java language specifications - 4.2.4)
if I multiply a float and an int, is the answer a float?
System.out.println(((Object)(1f*1)).getClass());//class java.lang.Float
(If you use DrJava, you can simply type ((Object)(1f*1)).getClass() into the interactions panel. There's a plugin for DrJava for Eclipse too.)
The simple answer is that Java will perform widening conversions automatically but not narrowing conversions. So for example int->float is automatic but float->int requires a cast.
Java ranks primitive types in the order int < long < float < double. If an operator is used with different primitive types, the type which appears before the other in the above list will be implicitly converted to the other, without any compiler diagnostic, even in cases where this would cause a loss of precision. For example, 16777217-1.0f will yield 16777215.0f (one less than the correct value). In many cases, operations between a float and an int outside the range +/-16777216 should be performed by casting the int to double, performing the operation, and then--if necessary--casting the result to float. I find the requirement for the double casting annoying, but the typecasting rules in Java require that one either use the annoying double cast or suffer the loss of precision.
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