Correct way to compare floats or doubles in Java

Correctly compare float or compare double is not only Java specific problem. It can be observed in almost all the programming languages today. In computer memory, floats and doubles are stored using IEEE 754 standard format. How the actual storage and conversion works, it is out of scope of this article.

For now, just understand that during computations and conversions, minor rounding errors can be introduced in these numbers. That’s why it is not advisable to simply rely on the equality operators (==) to compare floating-point numbers.

Let’s learn how to compare float values in Java.

Table of Contents

1. Simple comparison [Not recommended]
2. Threshold based comparison [Recommended]
3. Compare with BigDecimal [Recommended]

1. Compare double – Simple comparison [Not recommended]

First look at the simple comparison to understand what exactly is wrong with comparing double with == operator. In given program, I am creating same floating point number (i.e. 1.1) using two methods:

  1. Add .1, 11 times.
  2. Multiply .1 to 11.

In theory, both operations should produce the number 1.1. And when we compare the results of both methods, it should match.

private static void simpleFloatsComparison() 
{
	//Method 1
	double f1 = .0;
	for (int i = 1; i <= 11; i++) {
		f1 += .1;
	}

	//Method 2
	double f2 = .1 * 11;

	System.out.println("f1 = " + f1);
	System.out.println("f2 = " + f2);

	if (f1 == f2)
		System.out.println("f1 and f2 are equal\n");
	else
		System.out.println("f1 and f2 are not equal\n");
}

Program Output.

f1 = 1.0999999999999999
f2 = 1.1
f1 and f2 are not equal

Look at the both values printed in console. f1 is computed to 1.0999999999999999. Its exactly the problem which rounding off causes internally. That’s why, floating point comparison with '==' operator is not recommended.

2. Compare double – Threshold based comparison [Recommended]

Now when we know the problem with equality operator, lets solve it. Using programming, we cannot change the way these floating point numbers are stored or computed. So we have to adapt a solution where we agree that a determine the differences in both values which we can tolerate and still consider the numbers equal. This agreed upon difference in values is called the threshold or epsilon.

So now to use ‘threshold based floating point comparison‘, we can use the Math.abs() method to compute a difference between the two numbers and compare the difference to a threshold value.

private static void thresholdBasedFloatsComparison() 
{
	final double THRESHOLD = .0001;

	//Method 1
	double f1 = .0;
	for (int i = 1; i <= 11; i++) {
		f1 += .1;
	}

	//Method 2
	double f2 = .1 * 11;

	System.out.println("f1 = " + f1);
	System.out.println("f2 = " + f2);

	if (Math.abs(f1 - f2) < THRESHOLD)
		System.out.println("f1 and f2 are equal using threshold\n");
	else
		System.out.println("f1 and f2 are not equal using threshold\n");
}

Program Output.

f1 = 1.0999999999999999
f2 = 1.1
f1 and f2 are equal using threshold

3. Compare double – Compare with BigDecimal [Recommended]

In BigDecimal class, you can specify the rounding mode and exact precision which you want to use. Using the exact precision limit, rounding errors are mostly solved.

Best part is that BigDecimal numbers are immutable i.e. if you create a BigDecimal BD with value "1.23", that object will remain "1.23" and can never be changed. This class provide many methods which can be used to do numerical operations on it’s value.

You can use it’s compareTo() method to compare to BigDecimal numbers. It ignore the scale while comparing.

a.compareTo(b);

Method returns:

-1 – if a < b)

0 – if a == b

1 – if a > b

Never use the equals() method to compare BigDecimal instances. That is because this equals function will compare the scale. If the scale is different, equals() will return false, even if they are the same number mathematically.

Java program to compare double with BigDecimal class.

private static void testBdEquality() 
{
	 BigDecimal a = new BigDecimal("2.00");
	 BigDecimal b = new BigDecimal("2.0");

	 System.out.println(a.equals(b)); 			// false

	 System.out.println(a.compareTo(b) == 0); 	// true
}

Now just to verify, let’s solve out original problem using BigDecimal class.

private static void bigDecimalComparison() 
{
	//Method 1
	BigDecimal f1 = new BigDecimal("0.0");
	BigDecimal pointOne = new BigDecimal("0.1");
	for (int i = 1; i <= 11; i++) {
		f1 = f1.add(pointOne);
	}

	//Method 2
	BigDecimal f2 = new BigDecimal("0.1");
	BigDecimal eleven = new BigDecimal("11");
	f2 = f2.multiply(eleven);

	System.out.println("f1 = " + f1);
	System.out.println("f2 = " + f2);

	if (f1.compareTo(f2) == 0)
		System.out.println("f1 and f2 are equal using BigDecimal\n");
	else
		System.out.println("f1 and f2 are not equal using BigDecimal\n");
}

Program Output.

f1 = 1.1
f2 = 1.1
f1 and f2 are equal using BigDecimal

That’s all about comparing floating point numbers in java. Share your thoughts in comments section.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

5 thoughts on “Correct way to compare floats or doubles in Java”

  1. This won’t work for infinity values. Here’s a test case to demonstrate this:

    import java.util.*;
    import java.lang.*;
    import java.io.*;
    
    /* Name of the class has to be "Main" only if the class is public. */
    class Ideone
    {
    	public static void main (String[] args) throws java.lang.Exception
    	{
    		double a = Double.POSITIVE_INFINITY;
    		double b = Double.POSITIVE_INFINITY;
    		if(a == b) {
    			System.out.println("'==' says a is equal to b");
    		} else {
    			System.out.println("'==' says a is not equal to b");
    		}
    		if(Math.abs(a - b)  &lt; 0.0001) {
    			System.out.println(&quot;&#039;THRESHOLD&#039; based equality check says a is equal to b&quot;);
    		} else {
    			System.out.println(&quot;&#039;THRESHOLD&#039; based equality check says a is not equal to b&quot;);
    		}
    	}
    }
    
    Reply
    • public static boolean fuzzyEquals(double a, double b, double tolerance) {
      MathPreconditions.checkNonNegative(“tolerance”, tolerance);
      return Math.copySign(a – b, 1.0) <= tolerance
      // copySign(x, 1.0) is a branch-free version of abs(x), but with different NaN semantics
      || (a == b) // needed to ensure that infinities equal themselves
      || (Double.isNaN(a) && Double.isNaN(b));
      }

      copy from guava DoubleMath

      Reply
  2. I tried this threshold value of floating number one but I am not getting both are same.
    Please have a look and correct me.

    package po;
    
    public class FloatExample {
    	static double d1=0.0;
    	static double d2=.1;
    	static double thresholdValue = 0.0001;
    	
    	private static double doubleOne(){
    		
    		for(int i=1; i<=11; i++){
    			d1=d1+.1;
    		}
    		return d1;
    	}
    	
    	private static double doubleTwo(){
    		d2=d2*11;
    		return d2;
    	}
    	
    	public static void main(String[] args) {
    		doubleOne();
    		doubleTwo();
    		if(Math.abs(doubleOne()-doubleTwo())<thresholdValue){
    			System.out.println("Both are equal");
    		}else{
    			System.out.println("Both are not equal");
    		}
    	}
    }
    

    Output:
    Both are not equal

    Reply
    • Its because you are using global variables. Try something like below

      private static double doubleOne(){
              double d1=0.0;
              for(int i=1; i<=11; i++){
                  d1=d1+.1;
              }
              return d1;
          }
           
          private static double doubleTwo(){
              double d2=.1;
              d2=d2*11;
              return d2;
          }
      
      Reply
    • Both methods are changing global var and are invoked twice. doubleOne results in 0.1*11+0.1*11, doubleTwo results in 0.1*11*11
      You should:
      Either don’t change global vars in the methods, that’s the best.
      Invoke them once only, there is no need in invocation prior to if – remove those two method calls before the if block in main.

      Reply

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.