Behaviour of shortcut assignment and normal assignment for float - java

I have a simple doubt
float k = 0;
k+=0.2;
k=k+0.2; // here compliation error
compliation error Type mismatch: cannot convert from double to float
My question is why not a complilation error at k+=0.2;

From the Java specification:
15.26.2. Compound Assignment Operators
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.
So the += operator has a built-in cast to the destination type.
In contrast, the clause for simple assignment says:
15.26.1. Simple Assignment Operator =
A compile-time error occurs if the type of the right-hand operand cannot be converted to the type of the variable by assignment conversion (§5.2).
Clause 5.2 allows widening conversions but does not allow narrowing conversions. So, in k+.2, the constant .2 has type double, and this causes the expression to have type double, and a double expression may not be directly assigned to a float object; it requires an explicit cast.

In Java by default decimal number consider as double.
Float numbers you need to append 'f' or 'F' at end of the number like this k=k+0.2f; or k=k+0.2F;

Java assumes literal decimal values are doubles. You need to explicitly put an "f" or "F" after the value to force it to be a float.

If Java allowed widening conversions from double to float, as well as float to double, then assignments like yours would compile fine, but expressions such as someFloat == someDouble would be ambiguous. To avoid such ambiguity, Java regards all primitive types in sequence such that each type may be converted to the next higher type, but not vice versa. Even though the percentage of implicit float-to-double conversions which represent programming mistakes far exceeds the percentage of implicit double-to-float conversions that would do so(*), the desire to arrange types into a strict sequence while avoiding having someFloat == someDouble translate as someFloat == (float)someDouble motivated type-casting rules which allow constructs which are more likely than not wrong to be done without typecasts, while requiring typecasts in cases where the behavior would be obvious without them.
In your cast, the compiler could be made not to squawk if you either specify that a constant is a float rather than a double, by adding an f suffix, or else avoid using float and simply use double. I would generally advise the latter approach. If you use float and later change your variables to type double, your maths will be compile fine but yield erroneous results unless you remove the suffixes from your constants (and also remove any explicit typecasts to float of things like function return values). A statement like double d=0.1f; will set d equal to precisely 13421773/134217728 (i.e. 0.100000001490116), a value substantially larger than was probably intended, without any compiler squawk whatsoever.

Related

Why don't we add an "s" suffix to short types?

Why don't we write s with short data type like short s = 2s; as we write with float e.g float f = 1.23f?
I know when we write float by default the compiler treats it as double and assigns 8 temporary bytes to it, and when it tries to copy that 8 byte to float's 4 that results in a type error, so that is why we write f after initializing a float, but why we don't do something similar with short as by default int is a literal type?
The Java Language Specification allows a type suffix of L or l for long literals. However, it does not provide a type suffix for short values. It's not necessary because:
Any value that could be represented by a short can also by represented by the default integral type int.
Assignments of an int value to a short variable are allowed if the value is a constant expression, whose value can be represented by a short. See the Java Language Specification, "Assignment Contexts":
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.
Why don't we add an “s” suffix to short types?
Because the Java language is inconsistent on this point.
The JLS is more flexible for no floating numeric primitive types as for floating numeric primitive types :
In addition, if the expression is a constant expression (§15.28) of
type byte, short, char, or int:
A narrowing primitive conversion may be used if the type of the
variable is byte, short, or char, and the value of the constant
expression is representable in the type of the variable.
I think that doing a distinction between byte, short, char, or int and float and double in the way to declare and manipulate them was not really required. It creates inconsistency and so potential mistakes in the use of them.
if short s = 10; is valid because the narrowing primitive conversion is validated by the compiler that it has no lost information, so float f = 10.0; would also have been valid for exactly the same reason.
That is because coming from double to a float is truncating value and losing data so the compiler doesn't do that automatically, you have to explicitly tell it. But when going from a smaller size, short, to a larger size, int, it is done automatically as the compiler just has to pad the data and there is no potential loss of data, as opposed to the former case.

Java: Type mismatch: cannot convert from int to char [duplicate]

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

Faulty behavior in Java in conditional expression

A simple expression:
Object val = true ? 1l : 0.5;
What type is val? Well, logically, val should be a Long object with value 1. But Java thinks that val is a Double with value 1.0.
It doesn't have to to anything with autoboxing as
Object val = true ? new Long(1) : new Double(0.5);
results with same behavior.
Just to clarify:
Object val = true ? "1" : 0.5;
results in the correct String.
Can anybody explain me why they have defined this like that? For me it seems to be rather really bad designed or actually a bug.
This is described in the Java Language Specification Section 15.25 (relevant parts in bold face):
The type of a conditional expression is determined as follows:
If the second and third operands have the same type [...]
If one of the second and third operands is of type boolean [...]
If one of the second and third operands is of the null type [...]
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 [...]
If one of the operands is of type T where T is byte, short, or char, [...]
If one of the operands is of type Byte [...]
If one of the operands is of type Short [...]
If one of the operands is of type; Character [...]
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).
Otherwise, the second and third operands are of types S1 and S2 respectively. Let T1 be the type that results from applying boxing conversion to S1, and let T2 be the type that results from applying boxing conversion to S2. The type of the conditional expression is the result of applying capture conversion (§5.1.10) to lub(T1, T2) (§15.12.2.7).
The "lub" mentioned in the last paragraph stands for least upper bound and refers to the most specific super type common for T1 and T2.
As for the case with Object val = true ? 1l : 0.5; I agree that it would be more precise if it applied rule 5 (on the boxed values). I guess the rules would become ambiguous (or even more complicated) when taking autoboxing into account. What type would for instance the expression b ? new Byte(0) : 0.5 have?
You can however force it to use rule 5 by doing
Object val = false ? (Number) 1L : .5;
Because the expression needs to be of a type.
If you do 1l + 0.5d, you end with 1.5d because the compiler changes automatically the types to the one which can allow all possible results.
In your case, the compiler sees ? and assigns the result of the expression the double using the same rule (you can write a long as a double, but not all doubles as longs).
That's not a design flaw:
The compiler has to determine the type of the entire expression true ? 1l : 0.5. It tries using a type where as few conversions as possible are required.
As 0.5 does not fit into a long (without loss of precision), the result of the expression can't be long - therefore, it has to be double and the long is simply converted (no loss of precision).
Note that you can't have an expression conditionally having different types - a tertiary expression has to evaulate to the same type regardless of the condition.
In the second snippet, Object is the only compatible type - the Double gets boxed and the String can be simply assigned.
When you write
Object val = true ? new Long(1) : new Double(0.5);
you need to consider that
(new Long(1) : new Double(0.5))
needs to have a value... The compiler needs to come up with a type that covers both possible values. For your example, it was double.
I cannot provide you with a good reason, but the type of the expression is given by the Java Language Specification: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25
In the JLS all the numeric types are treated as special cases.

Narrowing Type Conversion: Why is assignment of int to a byte in a declaration allowed?

This may sound too trivial for an intermediate Java programmer. But during my process of reviewing Java fundamentals, found a question:
Why is narrowing conversion like:
byte b = 13;
will be allowed while
int i = 13;
byte b = i;
will be complained by the compiler?
Because byte b = 13 ; is assignment of a constant. Its value is known at compile time, so the compiler can/should/will whine if assignment of the constant's value would result in overflow (try byte b = 123456789 ; and see what happens.)
Once you assign it to a variable, you're assigning the value of an expression, which, while it may well be invariant, the compiler doesn't know that. That expression might result in overflow and so the compiler whines.
From here:
Assignment conversion occurs when the
value of an expression is 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 an identity
conversion (§5.1.1), a widening
primitive conversion (§5.1.2), or a
widening reference conversion
(§5.1.4). In addition, a narrowing
primitive conversion may be used if
all of the following conditions are
satisfied:
The expression is a constant expression of type byte, short, char or int.
The type of the variable is byte, short, or char.
The value of the expression (which is known at compile time, because it is a constant expression) is representable in the type of the variable.
In your example all three conditions are satisfied, so the narrowing conversion is allowed.
P.S. I know the source I'm quoting is old, but this aspect of the language hasn't changed since.
Because a literal number has no type.
Once you give it a type it must be casted to the other one:
int i = 13;
byte b = (byte) i;
A byte has 8 bits. An int, 32 bits, and it is a signed number.
Conversion from a number with a smaller range of magnitude ( like int to long or long to float ) is called widening. The goal of widening conversions is to produce no change in the magnitude of the number while preserving as much of the precision as possible. For example, converting the int 2147483647 to float produces 2.14748365e9 or 2,147,483,650. The difference is usually small, but it may be significant.
Conversely, conversion where there is the possibility of losing information about the magnitude of the number ( like long to int or double to long ) is called narrowing. With narrowing conversions, some information may be lost, but the nearest representation is found whenever possible. For example, converting the float 3.0e19 to long yields -9223372036854775807, a very different number.

Java: why do I receive the error message "Type mismatch: cannot convert int to 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

Categories

Resources