Adam Jarvis
Adam Jarvis

Reputation: 181

Using Java BigDecimal still not correctly solving

I have a method with two double values being inputted. When trying to add them together I get incorrect values over a certain threshold so I started using BigDecimal.

However even with BigDecimal I still have incorrect values?

double value1 = 2789.45;
double value2 = 557.89;
System.out.println(BigDecimal.valueOf(value1 + value2));

prints

3347.3399999999997

when It should read as

3347.34

How can I do this correctly even if value1 and value2 could be higher than current scope? (they are calculated in a separate method).

Should I just use rounding?

Upvotes: 5

Views: 1726

Answers (3)

Jordi Castilla
Jordi Castilla

Reputation: 27003

Should I just use rounding?

NOPE, what you are experiencing is lose of precision of double sum.


You are suming the doubles first (value1 + value2) and after converting the double sum (which has lost precision) to a BigDecimal.

To avoid this use this instead:

double value1 = 2789.45;
double value2 = 557.89;
System.out.println(BigDecimal.valueOf(value1).add(BigDecimal.valueOf(value2)));

OUTPUT:

3347.34

Working IDEONE DEMO here


UPDATE

-1. Instead of using BigDecimal.valueOf, which is still fragile, you should be using BigDecimal from the beginning and create them with new BigDecimal("2789.45"), new BigDecimal("557.89"). As soon as you've used a double literal, you've introduced imprecision. BigDecimal.valueOf tries to get it back, but it doesn't always work. – Louis Wasserman

Actually I'm not totally agree with this. You cannot hardcode the values creating new decimals, what I can be agree is to read the values (if possible for the OP) in a String directly to avoid double precision lost:

String value1 = "2789.45"; 
BigDecimal one = new BigDecimal(value1);
String value2 = "557.89";
BigDecimal two = new BigDecimal(value2);
System.out.println(one.add(two));

OUTPUT:

3347.34

This will avoid the problems Louis Wasserman is noticing.

NEW WORKING DEMO

Upvotes: 8

Patricia Shanahan
Patricia Shanahan

Reputation: 26185

You have already lost precision when you assign the variables to doubles.

Consider this program:

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    System.out.println(new BigDecimal(2789.45));
    System.out.println(new BigDecimal("2789.45"));
  }
}

Output:

2789.4499999999998181010596454143524169921875
2789.45

Doing the addition in BigDecimal will get you the exact sum of the inputs, but if you first convert to double the inputs will be the closest doubles to the values you wrote.

Upvotes: 1

Sleiman Jneidi
Sleiman Jneidi

Reputation: 23349

Because the compiler will evaluate the sum first, it adds the two doubles first and hence you losing the precision, you essentially doing this

double value1 = 2789.45;
double value2 = 557.89;
double sum = value1 + value2; // precision lost here
System.out.println(BigDecimal.valueOf(sum));

Upvotes: 1

Related Questions