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?
BigDecimal precision is de facto unlimited since it is based on an int array of arbitrary length. Though operations with double are much faster than with BigDecimal this data type should never be used for precise values, such as currency.
A BigDecimal is an accurate way of expressing numbers. A Double has a reliable accuracy. Going with doubles of various magnitudes (say d1=1000.0 and d2=0.001) could occur in the 0.001 being dropped collectively when summing as the variation in magnitude is so large. With BigDecimal this would not occur.
BigDecimal reduces the chances of calculation errors. On double numbers, the BigDecimal class provides arithmetic, scale management, rounding, comparison, format conversion, and hashing functions. It compensates for the time complexity by handling large and small floating-point integers with exceptional precision.
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 usingBigDecimal
from the beginning and create them withnew BigDecimal("2789.45")
,new BigDecimal("557.89")
. As soon as you've used adouble
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
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));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With