In Java, I have defined k as
double k=0.0;
I am taking data from database and adding the same using while
loop,
while(rst.next()) {
k = k + Double.parseDouble(rst.getString(5));
}
NOTE: In database, I have values as 125.23, 458.45, 665.99 (all two decimals)
When I display k, I get value as
k = 6034.299999999992
Hence I introduced BigDecimal
and changed code to below
BigDecimal bd = new BigDecimal(k);
bd = bd.setScale(2,BigDecimal.ROUND_UP);
Now I get new total as bd=6034.30
which is correct.
Problem 1
Well the problem is when I am using same at other place, below is what I am getting
k = 157.3
bd = 157.31
It should have shown bd=157.30
as after adding manually I get 157.30
.
Any reason why it is showing as 157.31
.
Problem 2
Also any reason why k is showing so many decimal values?
Below are different values I am getting for double variable k
157.3
67.09
1014.6000000000003
229.06999999999996
I don't understand sometime it displays one decimal, sometime it display 2 decimal and most of the time it show 14 decimal value.
Any suggestion would be appreciated.
You're still going via double
. Stick to BigDecimal
everywhere:
BigDecimal k = BigDecimal.ZERO;
while (rst.next()) {
k = k.add(new BigDecimal(rst.getString(5));
}
Alternatively - and preferrably, if the field in the database is actually a decimal value:
BigDecimal k = BigDecimal.ZERO;
while (rst.next()) {
k = k.add(rst.getBigDecimal(5));
}
As to your second question, double
is a binary floating point number. This means that it is expressed as a sum of powers of two. Don't ever use those for calculating monetary values. (if that's what you're summing up there). BigDecimal uses decimal arithmetic, so this is more in line to what we use.
Numbers such as 0.1
are infinite fractions in binary, in this case: 0.000110011...
thus you cannot get a reliable and exact result from using double
.
I assume rst
is a ResultSet
. Make sure you are using getBigDecimal
rather than Double.parseDouble(rst.getString(5))
:
BigDecimal k = BigDecimal.ZERO;
while(rst.next()) {
k = k.add(rst.getBigDecimal(5));
}
And first of all: why aren't you adding these numbers in the database directly using appropriate SQL SUM
query?
Use BigDecimal.ROUND_HALF_UP (or .._DOWN or .._EVEN).
Floating point calculations are inherently inaccurate and the small errors accumulate. That's why your end result is off by a small amount. If you always round up, a small positive error like 1.0000000001 becomes 1.01.
Alternatively you can use BigDecimal also for the calculations. That way you won't have an error in the end result in the first place. Just remember to use the BigDecimal(String) constructor, or obtain the BigDecimal directly from the result set.
You need to have k
as BigDecimal
too, instead of double
.