Can someone explain how typecasting works in the line int y = (int) x;
Thank You
public class typecast
{
public static void main(String [] args)
{
double x=10.5;
int y=(int) x;
System.out.println("x="+x);
System.out.println("y="+y);
}
}
The type cast performs a narrowing type conversion. The exact conversion depends on the double value, as follows:
If it is within the range of int values, it is rounded towards zero.
If it outside of the range or is an "Inf" value, then the conversion gives Integer.MIN_VALUE or Integer.MAX_VALUE, depending on the sign.
If it is a "NaN" value, the conversion gives zero.
Reference: JLS 5.1.3
Note: "round towards zero" is defined as follows:
"The Java programming language uses round toward zero when converting a floating value to an integer (ยง5.1.3), which acts, in this case, as though the number were truncated, discarding the mantissa bits. Rounding toward zero chooses at its result the format's value closest to and no greater in magnitude than the infinitely precise result."
In this particular case, the code won't compile if you try and take a double (variable x) and assign it's value to an int (variable y). So you have to explicitly tell the compiler to cast (convert) the type from a double to an int. When it does that, in this particular case, I believe it drops the fractional part instead of rounding up/down. I could be wrong about that last point.
Related
Using this snippet:
public static void main(String[] args){
int i = XXX;
System.out.println( (int) ( (float) i ) );
}
If int i = 1234; then the output is 1234
If int i = Integer.MAX_VALUE; then the output is equal to Integer.MAX_VALUE
However, if int i = 1234567990;, then the output is 1234567936, which is not equal to i.
And if int i = 1235567990;, then the output is 1235568000, which is also not equal to i.
How does this casting conversion math work?
This is entirely normal for floating point maths. Both int and float are 32-bit values. float only has about 7 significant digits of precision, because it uses some of the bits for scale. As you get to large values, "adjacent" float values (i.e. going from one precisely-representable value to the next one up) are more than 1 apart - so any integer between those two adjacent values can't be represented precisely as a float.
Another way of looking at this is a version of the pigeonhole principle:
Both float and int have 2^32 possible bit patterns
There's a valid mapping from every int to a float value
Every bit pattern is a valid int, so there are 2^32 possible integer values
float also contains the value 1.5 (and many other non-integers, but we only need one of them to prove the point)
Therefore at least two int values must map to the same float, which means the mapping cannot be reversible in every case
Note that if you use double, you're fine - every int can be cast to double and then cast back to int, and you'll get the original value. However, using double and long (instead of int) you get the same problem, for the same reason, but using 64 bits instead of 32.
How does this casting conversion math work?
Casting an int to a float works the same way any float operation works: Do the math (which in this case is nothing - just take the int as is), then convert it to the 'nearest representable float' - that float which is closer to the result of the calculation than any other.
Why is it 'lossy'? See the other answer.
What's the math behind which floats are representable? Wikipedia's page on IEEE754 floating point representation explains that.
Why does this output 0 instead of 1?
System.out.println((int) (Math.ceil(1/2)));
While this one correct outputs 1
System.out.println((int) (Math.ceil((double) 1/ (double) 2)));
Shouldn't Math.ceil(double) automatically type cast the 1/2 to double?
Math.ceil does, indeed, cast the integer to a double. But it only does so after the integer operation has been performed. This is the order of operations:
int a = 1;
int b = 2;
int c = a / b; // now equals 0, because it's an integer operation.
double d = (double)c; // now it's a double - but equals 0.0.
double e = Math.ceil(d); // still 0.0.
You're thinking of 1/2 as a fraction, but it's not - it's an expression of two ints and an operator that has to be resolved before its value can be used in further expressions.
Explicit casting always require (datatype) to be mentioned. Here 1 and 2 represents itself as int and to cast from int to double explicit casting will be introduced. Whenever casting is preformed from lower to higher datatypes explicit casting should be imposed. See example below;
public class MainClass{
public static void main(String[] argv){
int a = 100;
long b = a; // Implicit cast, an int value always fits in a long
}
}
An explicit casts looks like this:
public class MainClass{
public static void main(String[] argv){
float a = 100.001f;
int b = (int)a; // Explicit cast, the float could lose info
}
}
Code Snippet: Source
The first thing which happens when that line is executed, is that the division 1/2 is resolved. This happens without any consideration for the method-call to Math.ceil it is embedded in.
The literals 1 and 2 are integers. When you perform a division with only integers as arguments, an integer division is performed, which always rounds down. So the term gets resolved to the int value 0. Math.ceil() only accepts type double, but that's not a problem because Java can perform the conversion automatically and turn the int 0 to a double 0.0.
To perform an explicit floating point division, have one or both of the parameters to the division be floating point literals:
System.out.println((int) (Math.ceil(1.0/2.0)));
Why values of c are 2.0 and 2.5 although they have same data type
How is conversion taking place in a/b
public static void main(String[] args)
{
int a = 5,b=2;
float c;
c=a/b;
System.out.println(c);
c=(float)a/b;
System.out.println(c);
}
The answer lies in understanding that despite declaring c as float, integer division still takes place with a/b. Integer division in Java truncates any fractional part (so it can remain an int). Only then is it implicitly converted to a float upon assignment to c, and 2.0 is printed.
The cast to a float in (float)a/b changes a to 5.0f and forces floating point division before the result is assigned to c, so the correct result 2.5 is printed.
In the first statement, a/b is calculated. As both variables are integers, the result is an integer too: 2. In your second statement, a is first converted to a float and then divided by b. As one of the values is a float, the result is a float too: 2.5.
The first division is int / int --> int result.
the second is Float / int, --> Float results.
In Java, we can convert an int to float implicitly, which may result in loss of precision as shown in the example code below.
public class Test {
public static void main(String [] args) {
int intVal = 2147483647;
System.out.println("integer value is " + intVal);
double doubleVal = intVal;
System.out.println("double value is " + doubleVal);
float floatVal = intVal;
System.out.println("float value is " + floatVal);
}
}
The output is
integer value is 2147483647
double value is 2.147483647E9
float value is 2.14748365E9
What is the reason behind allowing implicit conversion of int to float, when there is a loss of precision?
You are probably wondering:
Why is this an implicit conversion when there is a loss of information? Shouldn't this be an explicit conversion?
And you of course have a good point. But the language designers decided that if the target type has a range large enough then an implicit conversion is allowed, even though there may be a loss of precision. Note that it is the range that is important, not the precision. A float has a greater range than an int, so it is an implicit conversion.
The Java specification says the following:
A widening conversion of an int or a long value to float, or of a long value to double, may result in loss of precision - that is, the result may lose some of the least significant bits of the value. In this case, the resulting floating-point value will be a correctly rounded version of the integer value, using IEEE 754 round-to-nearest mode.
Converting an integer type to a floating point type that uses the same number of bits may result in a loss of precision, but will be done automatically.
"Loss of precision" means that some of the less significant digits may become zeros, but the most important digits and the size of the number will remain. Recall that float has only about seven decimal digits of precision. For example, converting the int 123456789 to a float 123456700.0 shows a loss of precision.
In Java, I want to convert a double to an integer, I know if you do this:
double x = 1.5;
int y = (int)x;
you get y=1. If you do this:
int y = (int)Math.round(x);
You'll likely get 2. However, I am wondering: since double representations of integers sometimes look like 1.9999999998 or something, is there a possibility that casting a double created via Math.round() will still result in a truncated down number, rather than the rounded number we are looking for (i.e.: 1 instead of 2 in the code as represented) ?
(and yes, I do mean it as such: Is there any value for x, where y will show a result that is a truncated rather than a rounded representation of x?)
If so: Is there a better way to make a double into a rounded int without running the risk of truncation?
Figured something: Math.round(x) returns a long, not a double. Hence: it is impossible for Math.round() to return a number looking like 3.9999998. Therefore, int(Math.round()) will never need to truncate anything and will always work.
is there a possibility that casting a double created via Math.round() will still result in a truncated down number
No, round() will always round your double to the correct value, and then, it will be cast to an long which will truncate any decimal places. But after rounding, there will not be any fractional parts remaining.
Here are the docs from Math.round(double):
Returns the closest long to the argument. The result is rounded to an integer by adding 1/2, taking the floor of the result, and casting the result to type long. In other words, the result is equal to the value of the expression:
(long)Math.floor(a + 0.5d)
For the datatype Double to int, you can use the following:
Double double = 5.00;
int integer = double.intValue();
Double perValue = 96.57;
int roundVal= (int) Math.round(perValue);
Solved my purpose.