Sum of decimal number in java

16,149

Solution 1

You can get rounding error, but I don't see it here.

final double first=198.4;//value extract by unmodifiable format method
final double second=44701.2;//value extract by unmodifiable format method
final double firstDifference= first+second; //I receive 44899.6
final double calculatedDifference=44900.1; // comparison value for the flow
final double error=firstDifference-calculatedDifference;// I receive -0.5 

if(Math.abs(error)<=0.5d){
    // this branch is entered.
    System.out.println(error);
}

prints

-0.5

There are two ways to handle this more generally. You can define a rounding error such as

 private static final double ERROR = 1e-9;

 if(Math.abs(error)<=0.5d + ERROR){

OR use rounding

final double firstDifference= round(first+second, 1); // call a function to round to one decimal place.

OR use integers with fixed precision

final int first=1984;// 198.4 * 10
final int second=447012; // 44701.2 * 10
final int firstDifference= first+second;  //I receive 448996
final int calculatedDifference=449001; // comparison value for the flow
final int error=firstDifference-calculatedDifference;// I receive -5 

if(Math.abs(error)<=5){
    // this branch is entered.
    System.out.println(error);
}

OR You can use BigDecimal. This is often the preferred solution for many developers, but a last option IMHO. ;)

Solution 2

This error will depend slightly on your version of Java (and I see you are using a slightly old one). However, regardless of Java version, for best results when you are particularly worried about decimal accuracy in java, you should use the BigDecimal class for your values.

This is what financial applications use for handling currency, and also what many industrial Java applications use when precision is essential.

EDIT: I see many valid comments that this solution comes with a slight performance hit (also depends on the number of operations you are doing in the first place). And really, if this is the only single place that you encounter an issue and you dont care about precision after it, then ya, go for a workaround. But if this happens frequently and in more than one place, or if you think you might be expanding your application in the future, I would use the safer BigDecimal.

Share:
16,149
alepuzio
Author by

alepuzio

Italian Java developer; I'm interest on: -&gt;measurement about software; -&gt;data structure and algorithms; -&gt;testing; -&gt;Design Pattern; -&gt;other :)

Updated on August 21, 2022

Comments

  • alepuzio
    alepuzio almost 2 years

    I have a problem for the managemente of decimal number in java (JDK 1.4).

    I have two double numbers first and second (as output of formatted String). I do a sum between fist and second and I receive a number with more decimal digits!

       final double first=198.4;//value extract by unmodifiable format method
    
       final double second=44701.2;//value extract by unmodifiable format method
    
       final double firstDifference= first+second; //I receive 44899.598 instead of 44899.6
    
       final double calculatedDifference=44900.1; // comparison value for the flow
    
        final double error=firstDifference-calculatedDifference;// I receive -0.50390605 instead 0.5
    
        if(Math.abs(error)<=0.5d)){
             //I must enter in this branch but the error not allows the correct flow!!!
        }
        /***
        * the flow of program is uncorrect and there's a very visible bug in business view
        */
    

    I prefer not growing the threshold value (0.5d) because I'm not safe with similar situation (when I started coding, the specs was talking about 0.1d as comparison value). If it's the only solution, the value of 0.9d is safest value for this problem?

    How I can resolve this situation? I thinked that this problem derive by the use of double variables, but with the float I have the same problem.

    Some idea (having some tested code line, if possible ;))?

    • adarshr
      adarshr over 13 years
      Actually, for me it enters the if condition!
    • Kushal
      Kushal over 13 years
      Your if clause has an extra parenthesis. Otherwise, code is perfect, and values its returning is also the same you are "expecting".
    • Vishy
      Vishy over 13 years
      I think the first values were for float ;)
    • gnomed
      gnomed over 13 years
      I think the mixed results for different users has something to do with the fact that the OP is using JDK 1.4 which is relatively old these days. (although I've been stuck supporting 1.3 recently at work. Ugh!)
  • Vishy
    Vishy over 13 years
    BigDecimal is suitable if you are not familar with working with double its better to be correct than performant and BigDecimal holds your hand more for rounding errors. However if you are familar with double you may find BigDecimal cumbersome both to code and to run. esp as there are often simple work arounds for rounding errors.
  • avgvstvs
    avgvstvs over 13 years
    Depends on the application. If you're working on actuarial applications primitives are garbage in terms of precision. If you're doing some kind of scientific/actuarial application BigDecimal is really the only solution.
  • Vishy
    Vishy over 13 years
    BigDecimal is particularly useful if you need the various rounding solutions it provided. However for prices/money using double with rounding or long/int with fixed precision values can do the job much faster and often cleaner. I wouldn't suggest float in 99% of cases.
  • alepuzio
    alepuzio about 13 years
    Great idea to use the int instead the double. The BigDecimal class gives me some problem with the rounding :(
  • Roland Illig
    Roland Illig over 12 years
    BigDecimal is only better than double if you are indeed working with decimal numbers. But as soon as you divide 6 by 7, both are equally imprecise.
  • Vishy
    Vishy over 12 years
    BigDecimal can be less imprecise, however the level of accuracy BigDecimal can give is rarely needed. Even usdebtclock.org the US national debt (just an estimate) can be represented unambigously with rounding.