loss of precision during widening conversions - java

Output of the below code is
package com.ajay.compoitepattern;
class Test {
public static void main(String[] args) {
int big = 1234567890;
float approx = big;
System.out.println(big - (approx));
System.out.println(big - (int)(approx));
}
}
The outptut to this program is
0.0
-46
My question is , if the precision was lost in the widening conversion it should have been -46 in the first
sysout also, why is the first output 0.0 ?

First output is 0.0 because float substract from an int and it makes whole statement in to float.
That means int big also converted into a float value. Basically you are doing is (approx - approx) as (float)big = approx.
This should be the reason why you are getting zero.
If you want just try this one too
System.out.println(big/(approx));
Operations between int and float converts the whole statement into float

This is covered by JLS §4.2.4:
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.
In your first example, big - approx, since approx is a float, this counts as a floating-point operation. big is widened into a float, and since approx is also big widening into a float, the loss of precision cancels itself out, netting you an answer of zero.
In your second example, big - (int) approx, neither operand is a floating-point type since you casted approx to int. The loss of precision is now present, and your answer is no longer zero.

float in Java uses 23 bit for mantissa, plus 1 implisit bit, hence 24 significant bits are available, and int is represented by 32 bits. So there is inevitable loss of precision for int values higher than 2^23. You should use double here, as it has a 53 significant bits, so the result will be 0 in second case.
public static void main(String[] args) {
int big = 1234567890;
double approx = big;
System.out.println(big - (approx)); // --> 0.0
System.out.println(big - (int) (approx)); // --> 0
}

Read this may help you to understand. Read this SO post too..
Let's consider your code
int big = 1234567890; // here your int big=1234567890;
float approx = big;
BigDecimal bd=BigDecimal.valueOf(approx);
System.out.println(bd); // Now you can see int to float creates approx= 1234567936;
System.out.println(big - (approx)); // In here big again casting to float since you are doing a operation with float, result is zero.
System.out.println(big - (int)(approx)); // here big=1234567890 and approx= 1234567936. so difference is -46

Related

Adding Float to long makes value decrease [duplicate]

This question already has answers here:
Why does Java implicitly (without cast) convert a `long` to a `float`?
(4 answers)
Closed 7 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

Long is of size 8 bytes then how can it be 'promoted' to float(4 bytes) in JAVA?

I read that in Java the long type can be promoted float and double ( http://www.javatpoint.com/method-overloading-in-java ). I wanted to ask that long integer takes 8 bytes of memory in JAVA and float takes 4 bytes then how this promotion works? Isn't it possible that we could be facing some data loss if we promote this way? Also it is noticeable that all other type promotions are from smaller size primitive datatype to similar or larger size datatypes.
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 _______________ Exceptional In case Of Float
float to double
long uses more bytes, but it has a smaller range: while long cannot go above 263, float can go to about 2127. Obviously, the expansion of range comes at the price of lower precision, but since the range of float is larger, the conversion from long to float is a promotion.
float is represented in a different way than integral types. For further infos on the floating-type, read this: https://en.wikipedia.org/wiki/Single-precision_floating-point_format . The content cooked down would look like this: the floating-point format consists of a sign-bit, 8 bits for the exponent and 23 bits for the fractional part of the value. The value is calculated like this: (-1)^signbit * 1.fractionalpart * 2 ^ (exponent - 127). Thus this algorithm allows representation of larger values than a 64bit integral type.
This quick test should show why:
public class Main {
public static void main(String[] args) {
System.out.println("Float: " + Float.MAX_VALUE);
System.out.println("Long: " + Long.MAX_VALUE);
}
}
Ouput:
Float: 3.4028235E38
Long: 9223372036854775807
Note the scientific notation in the Float line. The Float takes up less space, but due to its representation, it can hold up to a larger number than a Long.

Difference between number/10 and number*0.1 in java

I've been working on an interview question for 1.5 hours and could not find the bug in my Java program.
And then I found what the problem was, which I don't understand (don't pay attention to the values, there were others, it's about the types):
int size=100;
Integer a=12;
if(a >= size/10)...
//didn't work
is different than
if(a >= size*0.1)...
//worked
I understand that there is a conversion, but still, how is it possible that with a=12, if(a>=size/10) returns false?
Why is that?
/10 is integer division. While *0.1 first converts the first operand to a double and performs a floating point multiplication.
If you use the /10, and the operand is 14, it will result in 1 indeed, 14/10=1.4 but integer division rounds this down. Thus 29/10=2.
If you use *0.1, the Java compiler will first convert the value of size to a double, thus 14.0 and then muliplies it with 0.1 resulting in 1.4.
On the other hand it's not all beaty that comes out of floating points. float and double can't represent every integer, and round off after computation.
For the given values for size however, it will result in the effect because 100 is a multiple of 10 and a float or double is capable of representing any integer value in the range from zero to hundred.
Finally /10 is not always an integer division: if the first operand is a floating point (e.g. 14.0d/10), the compiler will convert this to a floating point division.
Short version:
int/int is an integer division that rounds down to the nearest (lower) integer.
int*double is a double multiplication that - with rounding off errors - results in the floating point value, nearest to the correct result (with decimal digits).
I just tested here:
public class a {
public static void main(String[] args) {
int size = 100;
int a = 12;
System.out.println((a >= size / 10) ? "OK" : "Failed?");
}
}
And it worked. I don't think this is your real problem. Probably it's in another part of your code.

Java float not acting correctly [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Why does (360 / 24) / 60 = 0 … in Java
I am having this problem:
float rate= (115/100);
When I do:
System.out.println(rate);
It gives me 1.0
What... is the problem?
115 and 100 are both integers, so will return an integer.
Try doing this:
float rate = (115f / 100f);
You're performing integer division (which provides an integer result) and then storing it in a float.
You need to use at least one float in the operation for the result to be the proper type:
float rate = 115f / 100;
float rate= (115/100);
Does the following things:
1) Performs integer division of 115 over 100 this yields the value 1.
2) Cast the result from step 1) to a float. This yields the value 1.0
What you want is this:
float rate = 115.0/100;
Or more generally, you want to convert one of the pieces of your division into a float whether that is via casting (float)115/100 or by appending a decimal point to one of the two pieces or by doing this float rate = 115f / 100 is completely up to you and yields the same result.
In order to perform floating-point arithmetic with integers you need to cast at least one of the operands to a float.
Example:
int a = 115;
int b = 100;
float rate = ((float)a)/b;
use float rate= (float)(115.0/100); instead
It is enough to put float rate = 115f / 100;
The problem you have is that your dividend and divisor are declared as integer type.
In mathematic when you divide two integer results only with remainder. And that is what you assign to your rate variable.
So to have the result as you expected, a remainder with fraction (rational numbers). Your dividend or divisor must be declared in a type with precision.
Base two known types with precision are float (Floating point) and double (Double precision).
By default all numbers (integer literals for purists) written in Java code are in type int (Integer). To change that you need to tell the compiler that a number you want to declare should be represent in different type. To do that you need to append a suffix to integer literal.
Literals for decimal types:
float - f or F; 110f;
double - d or D 110D;
Note that when you would like to use the double, type you can also declare it by adding a decimal separator to literal:
double d = 2.;
or
double d = 2.0;
I encourage you to use double type instead of float. Double type is more suitable for most of modern application. Usage of float may cause unexpected results, because of accuracy problem that in single point calculation have bigger impact on result. Good reading about this “What Every Computer Scientist Should Know About Floating-Point Arithmetic”.
In addition on current CPU architecture both float and double have same performance characteristic. So there is not need to sacrifice the accuracy.
A final note about floating point types in is that non of them should be use when we write a financial application. To have valid results in this matter, you should always used [BigDecimal]

Loss of precision - int -> float or double

I have an exam question I am revising for and the question is for 4 marks.
"In java we can assign a int to a double or a float". Will this ever lose information and why?
I have put that because ints are normally of fixed length or size - the precision for storing data is finite, where storing information in floating point can be infinite, essentially we lose information because of this
Now I am a little sketchy as to whether or not I am hitting the right areas here. I very sure it will lose precision but I can't exactly put my finger on why. Can I get some help, please?
In Java Integer uses 32 bits to represent its value.
In Java a FLOAT uses a 23 bit mantissa, so integers greater than 2^23 will have their least significant bits truncated. For example 33554435 (or 0x200003) will be truncated to around 33554432 +/- 4
In Java a DOUBLE uses a 52 bit mantissa, so will be able to represent a 32bit integer without lost of data.
See also "Floating Point" on wikipedia
It's not necessary to know the internal layout of floating-point numbers. All you need is the pigeonhole principle and the knowledge that int and float are the same size.
int is a 32-bit type, for which every bit pattern represents a distinct integer, so there are 2^32 int values.
float is a 32-bit type, so it has at most 2^32 distinct values.
Some floats represent non-integers, so there are fewer than 2^32 float values that represent integers.
Therefore, different int values will be converted to the same float (=loss of precision).
Similar reasoning can be used with long and double.
Here's what JLS has to say about the matter (in a non-technical discussion).
JLS 5.1.2 Widening primitive conversion
The following 19 specific conversions on primitive types are called the widening primitive conversions:
int to long, float, or double
(rest omitted)
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.
Despite the fact that loss of precision may occur, widening conversions among primitive types never result in a run-time exception.
Here is an example of a widening conversion that loses precision:
class Test {
public static void main(String[] args) {
int big = 1234567890;
float approx = big;
System.out.println(big - (int)approx);
}
}
which prints:
-46
thus indicating that information was lost during the conversion from type int to type float because values of type float are not precise to nine significant digits.
No, float and double are fixed-length too - they just use their bits differently. Read more about how exactly they work in the Floating-Poing Guide .
Basically, you cannot lose precision when assigning an int to a double, because double has 52 bits of precision, which is enough to hold all int values. But float only has 23 bits of precision, so it cannot exactly represent all int values that are larger than about 2^23.
Your intuition is correct, you MAY loose precision when converting int to float. However it not as simple as presented in most other answers.
In Java a FLOAT uses a 23 bit mantissa, so integers greater than 2^23 will have their least significant bits truncated. (from a post on this page)
Not true.
Example: here is an integer that is greater than 2^23 that converts to a float with no loss:
int i = 33_554_430 * 64; // is greater than 2^23 (and also greater than 2^24); i = 2_147_483_520
float f = i;
System.out.println("result: " + (i - (int) f)); // Prints: result: 0
System.out.println("with i:" + i + ", f:" + f);//Prints: with i:2_147_483_520, f:2.14748352E9
Therefore, it is not true that integers greater than 2^23 will have their least significant bits truncated.
The best explanation I found is here:
A float in Java is 32-bit and is represented by:
sign * mantissa * 2^exponent
sign * (0 to 33_554_431) * 2^(-125 to +127)
Source: http://www.ibm.com/developerworks/java/library/j-math2/index.html
Why is this an issue?
It leaves the impression that you can determine whether there is a loss of precision from int to float just by looking at how large the int is.
I have especially seen Java exam questions where one is asked whether a large int would convert to a float with no loss.
Also, sometimes people tend to think that there will be loss of precision from int to float:
when an int is larger than: 1_234_567_890 not true (see counter-example above)
when an int is larger than: 2 exponent 23 (equals: 8_388_608) not true
when an int is larger than: 2 exponent 24 (equals: 16_777_216) not true
Conclusion
Conversions from sufficiently large ints to floats MAY lose precision.
It is not possible to determine whether there will be loss just by looking at how large the int is (i.e. without trying to go deeper into the actual float representation).
Possibly the clearest explanation I've seen:
http://www.ibm.com/developerworks/java/library/j-math2/index.html
the ULP or unit of least precision defines the precision available between any two float values. As these values increase the available precision decreases.
For example: between 1.0 and 2.0 inclusive there are 8,388,609 floats, between 1,000,000 and 1,000,001 there are 17. At 10,000,000 the ULP is 1.0, so above this value you soon have multiple integeral values mapping to each available float, hence the loss of precision.
There are two reasons that assigning an int to a double or a float might lose precision:
There are certain numbers that just can't be represented as a double/float, so they end up approximated
Large integer numbers may contain too much precision in the lease-significant digits
For these examples, I'm using Java.
Use a function like this to check for loss of precision when casting from int to float
static boolean checkPrecisionLossToFloat(int val)
{
if(val < 0)
{
val = -val;
}
// 8 is the bit-width of the exponent for single-precision
return Integer.numberOfLeadingZeros(val) + Integer.numberOfTrailingZeros(val) < 8;
}
Use a function like this to check for loss of precision when casting from long to double
static boolean checkPrecisionLossToDouble(long val)
{
if(val < 0)
{
val = -val;
}
// 11 is the bit-width for the exponent in double-precision
return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 11;
}
Use a function like this to check for loss of precision when casting from long to float
static boolean checkPrecisionLossToFloat(long val)
{
if(val < 0)
{
val = -val;
}
// 8 + 32
return Long.numberOfLeadingZeros(val) + Long.numberOfTrailingZeros(val) < 40;
}
For each of these functions, returning true means that casting that integral value to the floating point value will result in a loss of precision.
Casting to float will lose precision if the integral value has more than 24 significant bits.
Casting to double will lose precision if the integral value has more than 53 significant bits.
You can assign double as int without losing precision.

Categories