Inconsistent Arithmetic Operations On Decimal Values

Overview

This post provides details on general pitfalls while doing arithmetic operations on decimal values and how to handle them..

Subtraction operation:

  • Executed statements:
    		System.out.println("Actual value of (4.375-4.250) Using Double:  "+((4.375-4.250))+" Expected Result 0.125");
    		System.out.println("Actual value of (4.650-4.250) Using Double:  "+((4.650-4.250))+" Expected Result 0.4");
    		System.out.println("Actual value of (4.650-4.250) Using BigDecimal:  "+(BigDecimal.valueOf(4.650).subtract(BigDecimal.valueOf(4.250)))+" Expected Result 0.4");
    		
  • Results:
    In the below results, the double subtraction is correct for (4.375-4.250) but incorrect for (4.650-4.250).

    		Actual value of (4.375-4.250) Using Double:  0.125 Expected Result 0.125
    		Actual value of (4.650-4.250) Using Double:  0.40000000000000036 Expected Result 0.4
    		Actual value of (4.650-4.250) Using BigDecimal:  0.40 Expected Result 0.4
    		

Addition operation:

  • Executed statements:
    		System.out.println(" Actual value of (4.65+4.25) Using Double:  "+(4.65+4.25)+" Expected Result 8.90");
    		System.out.println(" Actual value of (0.111+3.70) Using Double:  "+(0.111+3.70)+" Expected Result 3.811");
    		System.out.println(" Actual value of (0.111+3.70) Using BigDecimal:  "+(BigDecimal.valueOf(0.111).add(BigDecimal.valueOf(3.70)))+" Expected Result 3.811");
    		
  • Results:
    In the below results, the double addition is correct for (4.65+4.25) but incorrect for (0.111+3.70).

    		Actual value of (4.65+4.25) Using Double:  8.9 Expected Result 8.90
    		Actual value of (0.111+3.70) Using Double:  3.8110000000000004 Expected Result 3.811
    		Actual value of (0.111+3.70) Using BigDecimal:  3.811 Expected Result 3.811
    		

Multiplication operation:

  • Executed statements:
    		System.out.println(" Actual value of (100*0.21) Using Double:  "+(100*0.21)+" Expected Result 21.0");
    		System.out.println(" Actual value of (100*0.211) Using Double:  "+(100*0.211)+" Expected Result 21.1");
    		System.out.println(" Actual value of (100*0.211) Using BigDecimal:  "+(BigDecimal.valueOf(100).multiply(BigDecimal.valueOf(0.211)))+" Expected Result 21.100");
    		System.out.println(" Using scale for Bigdecimal results:  "+(BigDecimal.valueOf(100).multiply(BigDecimal.valueOf(0.211))).setScale(1)+" Expected Result 21.1");
    		
  • Results:
    In the below results, the double multiplication is correct for (100*0.21) and incorrect for (100*0.211).

    			Actual value of (100*0.21) Using Double:  21.0 Expected Result 21.0
    			Actual value of (100*0.211) Using Double:  21.099999999999998 Expected Result 21.1
    			Actual value of (100*0.211) Using BigDecimal:  21.100 Expected Result 21.100
    			Using scale for Bigdecimal results:  21.1 Expected Result 21.1
    		

Analysis:

Decimal values are based on power of 2, for arithmetic operations java internally approximates to nearest power of 2 which results in above absurd results. When a exact calculation is feasible with representation of nearest power of 2 we get expected results in all other scenario we get some approximate results. The BigDecimal offers various methods for performing arithmetic operations and to the required precision.
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s