Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can Java round-trip String -> float -> String even for (some) values not representable as a float? [duplicate]

As explained in many places (such as Why can't decimal numbers be represented exactly in binary?), not all decimal fractions can be represented as floating point values (such as stored in a float in Java).

The typical example given is "0.2". According to this nifty IEEE 754 Converter, the float closest to 0.2 is approximately 0.20000000298023224 , so parsing "0.2" as a float should yield this result.

However, I noted that Java seems to be able to do the impossible:

String number="0.2";
float f = Float.parseFloat(number);
System.out.println("Result of roundtrip String -> float -> String: "+f);

prints:

Result of roundtrip String -> float -> String: 0.2

Test on IDeone.com

How does Java know that I wanted the (rounded) output "0.2", instead of the precise output "0.20000000298023224" as explained above?

The Javadocs of Float.toString() try to explain this:

How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type float.

Unfortunately, this confuses me even more. Why does "printing as many digits as needed to uniquely distinguish the argument value" allow Java to print "0.2"?

Ideally, the answer would also explain why this printing algorithm was chosen. It is to make (some) round-trips work, as in this example? Is there another motivation?

like image 724
sleske Avatar asked Oct 19 '22 06:10

sleske


1 Answers

The rounding of the output is not because of some printing algorithm. It is because of the size of float. If you do:

String fs = "0.2";
double f = Float.parseFloat(fs);
System.out.println(f);

You get:

0.20000000298023224

Test on Ideone.com

This clearly shows that the String "0.2" is parsed as 0.20000000298023224, but the float data-type is not able to hold it, and rounds it up to 0.2. double data type is capable of holding this data, and hence, when you parse it as float, but store it in a double, you get the expected output.

like image 79
dryairship Avatar answered Oct 29 '22 03:10

dryairship