I'm studying java by Herbert Schildt's "Java for beginners" book. It is said that, being a destiny variable compatible and sufficiently big to store an origin one, an automatic conversion is done.
That being said, an Int should be able to store an Float and vice-versa, since they both have a 4 bytes size.
public class MyClass {
public static void main(String args[]) {
int i = 10;
float f = i;
float ff = 10;
int ii = ff;
}
}
However, when compiled, this piece of code generetes the following error:
/MyClass.java:15: error: incompatible types: possible lossy conversion from float to int
int ii = ff;
^
1 error
Why is there that, being a compatible type and sufficiently big to store each other, a float can store an int but an int cannot store a float?
Because float contains numbers also after the decimal point and int does not. Without this you shouldn't be able to simply trim the decimal part from the number by explicitly casting the float to int too.
an Int should be able to store an Float and vice-versa, since they both have a 4 bytes size.
The size of the data is not the important part. Rather it is about the values which can be stored in the give number of bytes. int can only store whole number values between -2^31 and 2^31-1. On the other hand, float can store decimal values.
As you can see, you can store a int into a float, but you can't put a float inside a int.
This heappens because the internal structure of float is a decimal number and int, as its name says, is integer.
For more information you can take a look into this discussion about How are floating point numbers are stored in memory.
Int to float is never a lossy conversion if the integer value will be within the range of maximum integer value that float can store as value will always be stored/converted to <intvalue>.0 like 4 will be stored as 4.0. But in case of conversion from float to int, your fraction value will be lost so JVM gives you such error. If you can take such risk then you have to explicitly convert the float value into int.
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.
I am new to Java programming and I am working with arrays .In arrays
index needs to be an integer and it doesn't allow float or double so I used long data type for index and it gave error. Whereas when I used byte and short and Int it worked . I want to know since the error was "possible lossy conversion from long to int "
Is it such that only int is allowed in index and since byte and short are small in size that's why it worked (auto promotion) and long was larger than int so it gave error(no auto depromotion)plz help
import Java.util.*;
class Demo{
public static void main(String args[]){
long n=5;
int a[]=new int[n]; //error possible lossy conversion from long to int
System.out.println(Arrays.toString(a));
}
}
In short, it's because that's the way the language is designed. If you take a look at section 10.7 of the Java language specifications, you'll notice that the length of the array is defined as an int (which is smaller than a long). Semtantically, ints and longs represent integers, but "larger" integer types will not be automatically cast to "smaller" integer types.
Needs to be int. Long, short, byte, float are other data types. Implicit or explicit conversion of your supplied data type can occur, but the index of your array will only be constructed with an int by the javac.
An array object contains a number of variables. The number of variables may be zero, in which case the array is said to be empty. The variables contained in an array have no names; instead they are referenced by array access expressions that use non-negative integer index values. These variables are called the components of the array. If an array has n components, we say n is the length of the array; the components of the array are referenced using integer indices from 0 to n - 1, inclusive.
Oracle Docs
You cannot cast long to int or rather cannot convert from long to int.
The only conversion you can do is
•
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
Since you have array of int you can store int ,short and byte datatype values
This question already has answers here:
Why does Java implicitly (without cast) convert a `long` to a `float`?
(4 answers)
Closed 8 years ago.
if you call the following method of Java
void processIt(long a) {
float b = a; /*do I have loss here*/
}
do I have information loss when I assign the long variable to the float variable?
The Java language Specification says that the float type is a supertype of long.
Do I have information loss when I assign the long variable to the float variable?
Potentially, yes. That should be fairly clear from the fact that long has 64 bits of information, whereas float has only 32.
More specifically, as float values get bigger, the gap between successive values becomes more than 1 - whereas with long, the gap between successive values is always 1.
As an example:
long x = 100000000L;
float f1 = (float) x;
float f2 = (float) (x + 1);
System.out.println(f1 == f2); // true
In other words, two different long values have the same nearest representation in float.
This isn't just true of float though - it can happen with double too. In that case the numbers have to be bigger (as double has more precision) but it's still potentially lossy.
Again, it's reasonably easy to see that it has to be lossy - even though both long and double are represented in 64 bits, there are obviously double values which can't be represented as long values (trivially, 0.5 is one such) which means there must be some long values which aren't exactly representable as double values.
Yes, this is possible: if only for the reason that float has too few (typically 6-7) significant digits to deal with all possible numbers that long can represent (19 significant digits). This is in part due to the fact that float has only 32 bits of storage, and long has 64 (the other part is float's storage format † ). As per the JLS:
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 (§4.2.4).
By example:
long i = 1000000001; // 10 significant digits
float f = i;
System.out.printf(" %d %n %.1f", i, f);
This prints (with the difference highlighted):
1000000001
1000000000.0
~ ← lost the number 1
It is worth noting this is also the case with int to float and long to double (as per that quote). In fact the only integer → floating point conversion that won't lose precision is int to double.
~~~~~~
† I say in part as this is also true for int widening to float which can also lose precision, despite both int and float having 32-bits. The same sample above but with int i has the same result as printed. This is unsurprising once you consider the way that float is structured; it uses some of the 32-bits to store the mantissa, or significand, so cannot represent all integer numbers in the same range as that of int.
Yes you will, for example...
public static void main(String[] args) {
long g = 2;
g <<= 48;
g++;
System.out.println(g);
float f = (float) g;
System.out.println(f);
long a = (long) f;
System.out.println(a);
}
... prints...
562949953421313
5.6294995E14
562949953421312
Okay, I'm fairly new to java but I'm learning quickly(hopefully). So anyway here is my problem:
I have a string(For example we will use 2.9), I need to change this to either int or long or something similar that I can use to compare to another number.
As far as I know int doesn't support decimals, I'm not sure if long does either? If not I need to know what does support decimals.
This is the error: java.lang.NumberFormatException: For input string: "2.9" with both Interger.parseInt and Long.parseLong
So any help would be appreciated!
You can't directly get int (or) long from decimal point value.
One approach is:
First get a double value and then get int (or) long.
Example:
int temp = Double.valueOf("20.2").intValue();
System.out.println(temp);
output:
20
int and long are both integer datatypes, 32-bit and 64-bit respectively. You can use float or double to represent floating point numbers.
That string (2.9) is neither integer nor long. You should use some decimal point types, for example float or double.
Both int and long are integer values (being long the representation of a long integer that is an integer with a higher capacity). The parsing fails because those types do not support a decimal part.
If you were to use them and enforce a casting you're relinquishing the decimal part of the number.
double iAmADouble = 100 / 3;
int iWasADouble = (int)iAmADouble; //This number turns out to be 33
Use double or float instead.
i was developing the below code
static String m(float i) {
return "float";
}
static String m(double i) {
return "double";
}
public static void main(String[] args) {
int a1 = 1;
long b1 = 2;
System.out.print(m(a1) + "," + m(b1));
}
Both results in output float, float , what the reason behind that please advise and how can I call double please advise thanks a lot.
Short answer: Java can automatically widen ints and longs to both floats and doubles, but Java will choose to widen to a float because it is smaller (in terms of memory footprint) than a double. You can call the double version of the method by explicitly casting the argument to a double:
System.out.print(m((double)a1) + "," + m((double)b1));
Long answer: Each primitive data type in Java has a size (measured in bytes), which determines how much information (or rather, what range of values) a given primitive can hold. The table below shows the sizes of some of Java's primitive data types:
byte 1 byte
short 2 bytes
char 2 bytes
int 4 bytes
float 4 bytes
long 8 bytes
double 8 bytes
Java will automatically "widen" values for you in certain situations, following some well-defined rules from the Java Language Specification. The following widening primitive conversions are performed by Java automatically:
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
The other rules that are applicable to this situation are:
Widening does not lose information about the overall magnitude of the numeric value.
Widening from an integral type to another integral type does not lose any information at all; the numeric value is preserved exactly.
Widening an int or long value to a float, or of a long value to a double may result in a loss of precision.
For example, Java can safely widen an int to a long without changing the numeric value at all, because both are integral types and a long is larger than an int (see rule 2). Java can also widen an int to a float, but there might be a loss of precision. The sample code below demonstrates this loss of precision.
public static void foo(float f) {
System.out.println(f);
}
public static void main(String[] args) {
int a = 123;
int b = 1234567890;
foo(a);
foo(b);
}
The first call to foo(float) prints "123.0" as expected. The int value "123" is widened to the float value "123.0". The second call prints "1.23456794E9", which makes sense when you take rule 3 into account. The value "1234567940" is the same magnitude as but less precise than "1234567890".
The other piece of information that is key here: when multiple overloaded methods are present, Java determines which method to call by choosing the method with the smallest parameter type (in terms of memory footprint) such that the given argument is capable of being widen to the parameter type. In other words, the number you pass to the method must be capable of being widened to the parameter type of the method, and if multiple overloaded methods satisfy that requirement, Java will choose the method whose parameter type is of the smallest size.
In your case, you are passing an int and a long to one of two overloaded methods. Java will look at methods m(float) and m(double) to determine which method to call. An int can be widened to a float and a double, but a float (4 bytes) is smaller than a double (8 bytes), so Java will choose to call m(float). The same is true when you call the method with a long argument: float is chosen because it's the smallest data type that a long can be widened to.
If you want to call the double version, make it explicitly a double: m((double)a1)
Take a look at the JLS §8.4.9 - Method Overloading
Try
System.out.print(m(1f)+","+ m(2d));
why are you creating an int and long to test it? Well, what is actually happening is that both parameters are converted to float by default.
how can I call double?
Use a double variable
double d = 3.3;
m(d);