Search code examples
javamathbigdecimal

BigDecimal operations precision overflow


import java.math.BigDecimal;

public class TestNumber {

    public static void main(String[] args) {
        BigDecimal bd = new BigDecimal(0);
        bd = bd.add(new BigDecimal(19.89));
        System.out.println(bd.doubleValue() + " - \t " + bd);
    }
}

I have multiple BidDecimals fields and arithmetic operations/comparations, the problem is with arithmetic results and decimals values.

For the above example the output is as follows:

19.89 -      19.8900000000000005684341886080801486968994140625

I expects:

19.89

The unexpected result creates other undesirable outputs to perform operations on the field type BigDecimal


Solution

  • The double value displayed by println is not the same as the actual value stored in that double variable.

    In any range there are an infinite number of real numbers but only a finite number of representable floating point values. When you define a floating point value, that value may not map to a representable floating point value, in which case you get the representable value that is closest to what you want. (Also keep in mind the representation is in binary, and a lot of numbers that are familiar to us become repeating decimals in binary that have to get truncated.) Here of course it's off by only 0.0000000000000005684341886080801486968994140625.

    The lines

    double d = 19.89d;
    System.out.println(d);
    

    will show you a cleaned-up approximation of what's in d. Java is hiding the messy trailing decimals from you.

    On the other hand, these lines

    double d = 19.89d
    BigDecimal b = new BigDecimal(d);
    System.out.println(b);
    

    result in the BigDecimal getting initialized with the entire contents of d, which the BigDecimal reproduces faithfully out to the last trailing digit.

    When println is passed the BigDecimal, the BigDecimal's toString method returns a string showing the digits it stored, and println writes that string to the console.

    Using

    BigDecimal b = new BigDecimal("19.89");
    

    will result in the actual decimal value 19.89 getting stored in the BigDecimal, because no floating point evaluation is involved.