72

A simple comparison of two double values in Java creates some problems. Let's consider the following simple code snippet in Java.

package doublecomparision;

final public class DoubleComparision 
{
    public static void main(String[] args) 
    {
        double a = 1.000001;
        double b = 0.000001;

        System.out.println("\n"+((a-b)==1.0));
    }
}

The above code appears to return true, the evaluation of the expression ((a-b)==1.0) but it doesn't. It returns false instead because the evaluation of this expression is 0.9999999999999999 which was actually expected to be 1.0 which is not equal to 1.0 hence, the condition evaluates to boolean false. What is the best and suggested way to overcome such a situation?

Jeff Mercado
  • 121,762
  • 30
  • 236
  • 257
Lion
  • 18,105
  • 22
  • 78
  • 106
  • 6
    This is because doubles and floats cannot express every numerical value. They are really using approximations to represent the value. – onit Nov 10 '11 at 15:21
  • The title of question is very misleading. The Author of question is actually asking, how to do precise math operations on double typ. Answer is you cant. If you have to, use BigDecimalr or similar. Those have .... at least theoretically, unlimited precision. – judovana Aug 06 '20 at 14:41
  • 2
    Here is good article: https://www.baeldung.com/java-comparing-doubles – nikolai.serdiuk Feb 17 '21 at 16:52

7 Answers7

105

Basically you shouldn't do exact comparisons, you should do something like this:

double a = 1.000001;
double b = 0.000001;
double c = a-b;
if (Math.abs(c-1.0) <= 0.000001) {...}
Janusz
  • 182,484
  • 112
  • 300
  • 368
Kevin
  • 24,129
  • 18
  • 99
  • 155
  • 14
    You might want to take a look at the Double's compare method. Check this link : http://www.tutorialspoint.com/java/lang/double_compare.htm – Tina Maria Jun 30 '14 at 04:54
  • 16
    But if you use Double.compare, note that (1) If d1 and d2 both represent Double.NaN, then the method returns true, even though Double.NaN==Double.NaN has the value false; and (2) If d1 represents +0.0 while d2 represents -0.0, or vice versa, the method returns the value false, even though +0.0==-0.0 has the value true. This definition allows hash tables to operate properly. – shiggity Sep 17 '14 at 22:22
  • 1
    this could also use `Math.ulp()` instead of a fixed error like `0.000001` (despite ot that obvious) – user85421 Sep 30 '19 at 12:07
14

Instead of using doubles for decimal arithemetic, please use java.math.BigDecimal. It would produce the expected results.

For reference take a look at this stackoverflow question

Community
  • 1
  • 1
Zaki Saadeh
  • 642
  • 4
  • 11
10

You can use Double.compare; It compares the two specified double values.

Anand
  • 459
  • 5
  • 6
  • 16
    I don't believe Double.compare in itself solves the problem that the poster was asking. You'd still need the abs and threshold – typoerrpr May 04 '18 at 03:47
  • 2
    the *advantage* of `compare` is that it accounts for `NaN` and `-0.0` - questions problem is sure not solved by that – user85421 Sep 30 '19 at 11:51
  • 2
    I belive it does, jsut walk through: http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Double.java#l1016 and http://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/lang/Double.java#l815 – judovana Aug 06 '20 at 13:44
2
        int mid = 10;
        for (double j = 2 * mid; j >= 0; j = j - 0.1) {
            if (j == mid) {
                System.out.println("Never happens"); // is NOT printed
            }

            if (Double.compare(j, mid) == 0) {
                System.out.println("No way!"); // is NOT printed
            }

            if (Math.abs(j - mid) < 1e-6) {
                System.out.println("Ha!"); // printed
            }
        }
        System.out.println("Gotcha!");
Splash
  • 96
  • 6
0

Consider this line of code:

Math.abs(firstDouble - secondDouble) < Double.MIN_NORMAL

It returns whether firstDouble is equal to secondDouble. I'm unsure as to whether or not this would work in your exact case (as Kevin pointed out, performing any math on floating points can lead to imprecise results) however I was having difficulties with comparing two double which were, indeed, equal, and yet using the 'compareTo' method didn't return 0.

I'm just leaving this there in case anyone needs to compare to check if they are indeed equal, and not just similar.

ThePC007
  • 21
  • 3
  • 1
    There are already multiple posts about this. Search better in SO. – mentallurg Jun 03 '19 at 22:24
  • 1
    and this is also returning `false` for questions data. Error with given data is about `1e-16`, `MIN_NORMAL` is about `2e-308` - way off {{ maybe you meant to use `Math.ulp()` }} – user85421 Sep 30 '19 at 11:56
-3

Just use Double.compare() method to compare double values.
Double.compare((d1,d2) == 0)

double d1 = 0.0;
double d2 = 0.0;

System.out.println(Double.compare((d1,d2) == 0))  // true
Chanaka Fernando
  • 1,958
  • 14
  • 19
  • 3
    you'd still need the abs and threshold. Double.compare doesn't do anything magic; if you look at the javadoc it returns "the value 0 if d1 is numerically equal to d2; a value less than 0 if d1 is numerically less than d2; and a value greater than 0 if d1 is numerically greater than d2.", effectively doing d1 == d2 in this case – typoerrpr Dec 12 '18 at 01:09
-4
double a = 1.000001;
double b = 0.000001;

System.out.println( a.compareTo(b) );

Returns:

  • -1 : 'a' is numerically less than 'b'.

  • 0 : 'a' is equal to 'b'.

  • 1 : 'a' is greater than 'b'.

Amit Kumar Lal
  • 5,013
  • 3
  • 18
  • 36
Ibrahim
  • 29
  • 3