简体   繁体   中英

What's the right way to parseFloat in Java

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?

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.

You're getting the right results. There is no such float as 0.027 exactly, nor is there such a double . You will always get these errors if you use float or double .

float and double are stored as binary fractions : something like 1/2 + 1/4 + 1/16... You can't get all decimal values to be stored exactly as finite-precision binary fractions. It's just not mathematically possible.

The only alternative is to use BigDecimal , which you can use to get exact decimal values.

From the Java Tutorials page on Primitive Data Types :

A floating-point literal is of type float if it ends with the letter F or f ; otherwise its type is double and it can optionally end with the letter D or d .

So I think your literals ( 0.001 ) are doubles and you're subtracting doubles from floats.

Try this instead:

System.out.println((0.0065F - 0.001D)); // 0.005500000134110451
System.out.println((0.0065F - 0.001F)); // 0.0055

... and you'll get:

0.005500000134110451
0.0055

So add F suffixes to your literals and you should get better results:

Float.parseFloat("0.0065") - 0.001F
new Float("0.027") - 0.001F
Float.valueOf("0.074") - 0.001F

I would convert your float to a string and then use BigDecimal.

This link explains it well

new BigDecimal(String.valueOf(yourDoubleValue));

Dont use the BigDecimal double constructor though as you will still get errors

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.

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:

BigDecimal d = new BigDecimal("0.0065");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM