I notice some issues with the Java float precision
Float.parseFloat("0.0065") - 0.001 // 0.0055000000134110451
new Float("0.027") - 0.001 // 0.02600000000700354575
Float.valueOf("0.074") - 0.001 // 0.07399999999999999999
I not only have a problem with Float
but also with Double
.
Can someone explain what is happening behind the scenes, and how can we get an accurate number? What would be the right way to handle this when dealing with these issues?
Floating point cannot accurately represent decimal numbers. If you need an accurate representation of a number in Java, you should use the java.math.BigDecimal class:
The problem is simply that
float
has finite precision; it cannot represent0.0065
exactly. (The same is true ofdouble
, of course: it has greater precision, but still finite.)A further problem, which makes the above problem more obvious, is that
0.001
is adouble
rather than afloat
, so yourfloat
is getting promoted to adouble
to perform the subtraction, and of course at that point the system has no way to recover the missing precision that adouble
could have represented to begin with. To address that, you would write:using
0.001f
instead of0.001
.I would convert your float to a string and then use BigDecimal.
This link explains it well
Dont use the BigDecimal double constructor though as you will still get errors
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.
Long story short if you require arbitrary precision use BigDecimal not float or double. You will see all sorts of rounding issues of this nature using float.
As an aside be very careful not to use the float/double constructor of BigDecimal because it will have the same issue. Use the String constructor instead.
From the Java Tutorials page on Primitive Data Types:
So I think your literals (
0.001
) are doubles and you're subtracting doubles from floats.Try this instead:
... and you'll get:
So add
F
suffixes to your literals and you should get better results: