Search code examples
javadoubledecimalapproximation

Sum of decimal number in java


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


Solution

  • 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. ;)