4

I am building a web app in Java that does math and shows steps to the user. When doing basic arithmetic with decimals I often get the messy in accurate outputs.

Here is my problem:

double a = 0.15;
double b = 0.01;
System.out.println(a - b);
// outputs 0.13999999999999999

float a = 0.15;
float b = 0.01;
System.out.println(a - b);
// outputs 0.14

float a = 0.16f;
float b = 0.01f;
System.out.println(a - b);
// outputs 0.14999999

double a = 0.16;
double b = 0.01;
System.out.println(a - b);
// outputs 0.15

Neither is reliable for complete accuracy. Is there a numeric class that is more precise or should I just round the values off?

7

4 Answers 4

6

You can use BigDecimal for this. It's ugly, but it works:

BigDecimal a = new BigDecimal("0.15");
BigDecimal b = new BigDecimal("0.01");
System.out.println(a.subtract(b));

Be sure to construct them either with a String parameter, or with the valueOf method, like this:

BigDecimal x = new BigDecimal("0.15");   // This is ok
BigDecimal x = BigDecimal.valueOf(0.15); // This is also ok

And not with a double parameter, like this:

BigDecimal x = new BigDecimal(0.15); // DON'T DO THIS

Because if you pass in a double, you will also pass in double's inaccuracy into the new BigDecimal instance. If you pass in a String, BigDecimal will know™ and do the right thing™.

4
  • 1
    Instead of new BigDecimal(0.15) you should use BigDecimal.valueOf(0.15) Commented Aug 29, 2012 at 7:23
  • @PeterLawrey You're right, I missed that one. I've updated my answer.
    – jqno
    Commented Aug 29, 2012 at 7:26
  • Won't work too well for "1/3", though. For that you need rational numbers.
    – Thilo
    Commented Aug 29, 2012 at 23:54
  • @Thilo True, but OP asked for "basic arithmetic with decimals", not for "basic arithmetic with rationals" :).
    – jqno
    Commented Aug 30, 2012 at 7:53
2

You need to apply a sensible round when using double. If you do you can get 15 digits of accuracy which is more than enough in most cases.

double a = 0.15;
double b = 0.01;
System.out.printf("%.2f%n", a - b);

double a2 = 0.16;
double b2 = 0.01;
System.out.printf("%.2f%n", a2 - b2);

prints

0.14
0.15
1

How about BigDecimal?

Will not be completely accurate for all divisions, though (such as 1/3). For that you'd need fractions, which is not part of the JDK, but easy to implement, for example as two integers (or BigIntegers).

0
  BigDecimal  a = new BigDecimal(".15");
  BigDecimal  b = new BigDecimal(".01"),
  BigDecimal  c = new BigDecimal(0);

  c = a.subtract(b);      
  System.out.println(c);

Not the answer you're looking for? Browse other questions tagged or ask your own question.