javadoublecurrencybigdecimaldouble-precision

What's the most precision you might lose if you use double to convert a currency value to another currency and back?


I know the problem of doubles due to base 2 calculations:

var total: Double = 0.1
total *= 0.1
total /= 0.1
println(total) // 0.10000000000000002

I understand that BigDecimal should be used for money related calculations, but in my case the little precision loss is acceptable, cuase all the currency calculation I need to do is convert currency C1 to currency C2 and back to currency C1. The only thing is that the two values of C1 after this conversion should match, when I show the result to customer with 5 decimal precision.

Now I'm trying to figure out, how much the value might drift over this conversion at worst case scenario? What are the numbers that might cause the worst case scenario?


Solution

  • You could read the description of double-precision floating-point:

    The 11 bit width of the exponent allows the representation of numbers with a decimal exponent between 10^−308 and 10^308, with full 15–17 decimal digits precision.

    Since you want 5 fraction digits, that means you're ok up to max. 10 integral digits.

    Or you could test it. Sometimes empirical evidence is more convincing:

    double value = 0.00009;
    while (true) {
        String nextDown = String.format("%.5f", Math.nextDown(value));
        String nextUp   = String.format("%.5f", Math.nextUp(value));
        if (! nextDown.equals(nextUp))
            break; // loss of precision to 5 decimals
        System.out.printf("Good: %.5f%n", value);
        value = value * 10 + 0.00009;
    }
    System.out.printf("Bad: %.5f%n", value);
    

    Output

    Good: 0.00009
    Good: 0.00099
    Good: 0.00999
    Good: 0.09999
    Good: 0.99999
    Good: 9.99999
    Good: 99.99999
    Good: 999.99999
    Good: 9999.99999
    Good: 99999.99999
    Good: 999999.99999
    Good: 9999999.99999
    Good: 99999999.99999
    Good: 999999999.99999
    Good: 9999999999.99999
    Bad: 99999999999.99997
    

    Yup, 10 is good, 11 bad.