BigDecimal Error

2019-02-17 16:17发布

问题:

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.

回答1:

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));
}


回答2:

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.



回答3:

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?



回答4:

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.



回答5:

You need to have k as BigDecimal too, instead of double.