6

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.

Fahim Parkar
  • 30,974
  • 45
  • 160
  • 276
  • Why don't you define a separate function for rounding, something like in this answer?: http://stackoverflow.com/a/8911683/744859 With this and defining k as BigDecimal as people suggest in the comments you would have a clean and efficient code. – Jav_Rock Jan 18 '12 at 15:40
  • @Jav_Rock : I am using function, but here to explain I only presented code... Let me know incase of any further details are needed... – Fahim Parkar Jan 18 '12 at 15:47

5 Answers5

7

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));
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
6

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.

Joey
  • 344,408
  • 85
  • 689
  • 683
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?

Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674
  • I want to display total salary while displaying all employee of company... to execute sum, I will have to fire query again, hence in while loop itself I was trying to add and get the desired result without second query.... – Fahim Parkar Jan 17 '12 at 08:51
2

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.

Joni
  • 108,737
  • 14
  • 143
  • 193
0

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

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110