Double subtraction precision issue

2019-01-14 03:54发布

问题:

My coworker did this experiment:

public class DoubleDemo {

      public static void main(String[] args) {
           double a = 1.435;
           double b = 1.43;
           double c = a - b;
           System.out.println(c);
      }
 }

For this first-grade operation I expected this output:

0.005

But unexpectedly the output was:

0.0050000000000001155

Why does double fails in such a simple operation? And if double is not the datatype for this work, what should I use?

回答1:

double is internally stored as a fraction in binary -- like 1/4 + 1/8 + 1/16 + ...

The value 0.005 -- or the value 1.435 -- cannot be stored as an exact fraction in binary, so double cannot store the exact value 0.005, and the subtracted value isn't quite exact.

If you care about precise decimal arithmetic, use BigDecimal.

You may also find this article useful reading.



回答2:

double and float are not exactly real numbers.

There are infinite number of real numbers in any range, but only finite number of bits to represent them! for this reason, rounding errors is expected for double and floats.

The number you get is the closest number possible that can be represented by double in floating point representation.

For more details, you might want to read this article [warning: might be high-level].

You might want to use BigDecimal to get exactly a decimal number [but you will again encounter rounding errors when you try to get 1/3].



回答3:

double and float arithmetic are never going to be exactly correct because of the rounding that occurs "under the hood".

Essentially doubles and floats can have an infinite amount of decimals but in memory they must be represented by some real number of bits. So when you do this decimal arithmetic a rounding procedure occurs and is often off by a very small amount if you take all of the decimals into account.

As suggested earlier, if you need completely exact values then use BigDecimal which stores its values differently. Here's the API



回答4:

 //just try to make a quick example to make b to have the same precision as a has, by using BigDecimal

 private double getDesiredPrecision(Double a, Double b){
     String[] splitter = a.toString().split("\\.");
     splitter[0].length();   // Before Decimal Count
     int numDecimals = splitter[1].length(); //After Decimal Count

     BigDecimal bBigDecimal = new BigDecimal(b);
     bBigDecimal = bBigDecimal.setScale(numDecimals,BigDecimal.ROUND_HALF_EVEN);

     return bBigDecimal.doubleValue();  
 }


标签: java double