1

I have an issue with some calculations inside my app. It is basically some kind of shopping list app. The user inputs the quantity and the price. There can be as much as 150 products in that list but usually it's something like 20,on average.

I'm using JTextFields,getting the Strings out of them and putting them into Arrays.I'm then parsing the Double and doing my calculations. The issue is that I sometimes get a total from the user in my database and when i verify it its wrong,for example(the shortest list i could find that has the error):

10 * 27.10
10 * 27.81
Total: 549.08

Clearly,the total is not 549.08 but 549.1.

Now,I know my method for the calculation is not the best,I did it a couple of months ago when I knew very little about Java and I left it like that since it did the job and I don't have calculations that are very complicated. So I didn't move to BigDecimal since I do this calculation a lot and from what I've read,it's a lot slower then double and float.

Anyway,here's my method:

Double totaltest=0;
for (int j = 0; j < allcant.size(); j++) {

   cant[j] = allcant.get(j).getText().toString();
   pret[j] = allpret.get(j).getText().toString();
   Double temp = Double.parseDouble(cant[j]) * Double.parseDouble(pret[j]);
   totaltest = totaltest + temp;
}

Could the issue come out of here? Or should I look somewhere else in my code? I'll most probably change the way I do the calculations anyway but I'd like to know what's the best way to do it and if I made a mistake here. I now know about floating point and stuff but the weird part is that it gives the right total when I try to replicate it.

dertkw
  • 7,798
  • 5
  • 37
  • 45
Sorin Grecu
  • 1,036
  • 11
  • 30
  • 2
    Use BigDecimal instead of Double. In your small app you will not fell a difference between performance of BigDecimal and Double ;) – dharr Apr 17 '14 at 15:52
  • To expand on the [above comment](http://stackoverflow.com/questions/23137719/calculation-is-sometimes-wrong#comment35376899_23137719): money is often best stored in integer values (i.e. total cents/pence/whatever). That avoids any of this nasty floating point error stuff. – Duncan Jones Apr 17 '14 at 15:53
  • I already researched a bit and knew about all the things you guys told me(using BigDecimal or long with cents,floating point and some other stuff) but could the method I use result in such an error ? and why can't I replicate it? This leads me to believe that the problem is somewhere else. I don't want to make a new method to calculate only to discover that the problem is somewhere else.Thanks for your time ! – Sorin Grecu Apr 17 '14 at 15:59
  • after rounding back to cents you will most likely end up with the right answer, but it's not good practice. Also, different implementations do different things. For example, try javascript:alert(2.0-1.1) in your browser. Even a simple computation like that will give you slightly off results in javascript. – Zeki Apr 17 '14 at 16:54
  • Yes there is something wrong with your code. 10 * 27.10 + 10 * 27.81 = 549.10 in java. In general float and double will be off, but by very, very small numbers, like .0000000000001. – Zeki Apr 17 '14 at 16:56
  • try outputting all of your intermediate values to see if one of them is coming out incorrect. – Zeki Apr 17 '14 at 16:57
  • That's exact reason why you should use `BigDecimal`, because not every decimal number can be represented as binary fraction. Sometimes using `double` produce weird results such as yours. –  Apr 17 '14 at 18:07
  • Do you do any rounding of intermediate results to two decimal places? Especially using Math.floor or similar? – Patricia Shanahan Apr 17 '14 at 22:28

4 Answers4

3

Float and Double are imprecise by design. You should never use these to represent currency. Instead use int or long and represent your amounts in cents. For example 1.00 would be 100 internally.

Zeki
  • 5,107
  • 1
  • 20
  • 27
  • Thanks for your answer! I knew about this but still,could this result in such a big difference from such a short calculation ? I'm thinking that the big issue is not here but somewhere else in my code,that's why i'm asking. Again, thanks! – Sorin Grecu Apr 17 '14 at 16:04
1

I tried to reproduce your arithmetic, and got 549.09999999999990905052982270717620849609375 as result. If rounded to two decimal places for display, it would be 549.10, so I don't think your issue is floating point precision, although I do agree BigDecimal would be a better choice for this application.

(I'm only using BigDecimal in my program to get exact printout of the result.)

Here's my program. I suggest working out what is different about the arithmetic in yours, and investigating that.

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    String[] cant = {"10", "10"};
    String[] pret = {"27.10", "27.81"};
    double totaltest=0;
    for (int j = 0; j < cant.length; j++) {
       Double temp = Double.parseDouble(cant[j]) * Double.parseDouble(pret[j]);
       totaltest = totaltest + temp;
    }
    System.out.println(new BigDecimal(totaltest));
  }
}
Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
0

For correct precision, use BigDecimal.

rossa
  • 119
  • 5
  • Again,I knew about this! Not to be mean, thanks for your time but I already wrote a couple of times about knowing this! What I want to know is if using double can result in such a big difference. I mean,for 2 products it had an error of 0.02. Isn't that kind of a lot,even for `double`? – Sorin Grecu Apr 17 '14 at 16:11
0

I found the solution to this issue some time ago,forgot to come back. It was kind of a mistake on my part.Kind of. The user application was making the calculus somewhere,sending it to the database then i was extracting it and redoing the calculus in another application(with the same calculus method).

The issue was that when I made the database,the "client" told me that the prices will never have more then 2 decimals so i declared the price field as Decimal(10,2),since I asked and made sure it was ok. They then set a price as 0.305 for example. The user app would do the calculus, for example 24*0.305=7.32 and in the database it would record as 0.30 since it could only accept 2 decimals and then, when I took the data from the database and redid it in my other application , of course, 24*0.30=7.2

Sorry for leading you down the wrong path. All good now.I learned that you should never trust the user/client and always double check I guess, heh. Have a good one!

Sorin Grecu
  • 1,036
  • 11
  • 30