The float value at that high value has a precision of only 0.5, so Java parsed it to the closest float value it could = 5555998.5, and that's what was printed.
To see the difference between the 2 closest values at that magnitude, use Math.ulp (unit in the last place):
String s = "5555998.558f";
float value = Float.parseFloat(s);
System.out.println(value);
System.out.println(Math.ulp(value));
This prints
5555998.5
0.5
You can use a double which has much better precision:
double d = Double.parseDouble(s);
System.out.println(d);
System.out.println(Math.ulp(d));
This prints
5555998.558
9.313225746154785E-10
Interestingly, Double.parseDouble doesn't seem to mind the f on the end. Double.parseDouble converts the String into a double "as performed by the valueOf method of class Double". And Double.valueOf states:
FloatValue:
Signopt NaN
Signopt Infinity
Signopt FloatingPointLiteral
Signopt HexFloatingPointLiteral
SignedInteger
This method will take a String as if it were a Java numeric literal, which Java supports with a f on the end to indicate a floating-point literal.
Videos
The float value at that high value has a precision of only 0.5, so Java parsed it to the closest float value it could = 5555998.5, and that's what was printed.
To see the difference between the 2 closest values at that magnitude, use Math.ulp (unit in the last place):
String s = "5555998.558f";
float value = Float.parseFloat(s);
System.out.println(value);
System.out.println(Math.ulp(value));
This prints
5555998.5
0.5
You can use a double which has much better precision:
double d = Double.parseDouble(s);
System.out.println(d);
System.out.println(Math.ulp(d));
This prints
5555998.558
9.313225746154785E-10
Interestingly, Double.parseDouble doesn't seem to mind the f on the end. Double.parseDouble converts the String into a double "as performed by the valueOf method of class Double". And Double.valueOf states:
FloatValue:
Signopt NaN
Signopt Infinity
Signopt FloatingPointLiteral
Signopt HexFloatingPointLiteral
SignedInteger
This method will take a String as if it were a Java numeric literal, which Java supports with a f on the end to indicate a floating-point literal.
BigDecimal is probably your best bet for exact decimal representations.
BigDecimal value = new BigDecimal("5555998.558");
It's immutable, so every operation you do to it will result in you creating a new BigDecimal instance, but its precision is also likely what you need.
The problem is simply that float has finite precision; it cannot represent 0.0065 exactly. (The same is true of double, of course: it has greater precision, but still finite.)
A further problem, which makes the above problem more obvious, is that 0.001 is a double rather than a float, so your float is getting promoted to a double to perform the subtraction, and of course at that point the system has no way to recover the missing precision that a double could have represented to begin with. To address that, you would write:
float f = Float.parseFloat("0.0065") - 0.001f;
using 0.001f instead of 0.001.
See What Every Computer Scientist Should Know About Floating-Point Arithmetic. Your results look correct to me.
If you don't like how floating-point numbers work, try something like BigDecimal instead.
This happens because Float numbers cannot be represented exactly on a system.
A Floating Point number is represented on 32bit Architecture using this format. http://en.wikipedia.org/wiki/Single-precision_floating-point_format
While on a 64bit architechture using this format. http://en.wikipedia.org/wiki/Double-precision_floating-point_format
Representation of the number in the above two format results in loss of precision. Thus a number such as 0.15 can come up weirdly as 0.149999999998.
When you convert 0.15 to it's binary representation it gives you a recurring number which is 0.0010011001100....
10 however has a binary representation which is not recurring hence can be exactly represented on the above two systems.
0.15 however has some it's bits removed so as to fit in the above architecture where the precision loss happens.
Check the exact mathematics on how to convert a floating point number to a binary which will better help you understand where the precision loss is happening. http://sandbox.mc.edu/~bennet/cs110/flt/dtof.html
If you really require parsing the value "0.15" as something that exactly represents the real value 0.15, then you need to use BigDecimal (http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html):
BigDecimal parsed = new BigDecimal(value)
Your "10" is also not exactly 10, BTW.