81

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
  • 129,526
  • 32
  • 251
  • 272
Lion
  • 18,729
  • 22
  • 80
  • 110
  • 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
  • 1
    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

8 Answers8

108

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
  • 187,060
  • 113
  • 301
  • 369
Kevin
  • 24,871
  • 19
  • 102
  • 158
  • 15
    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 T Jun 30 '14 at 04:54
  • 17
    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
  • Wait guys, okay, we can compare to doubles on the condition of equality considering desired accuracy, but how to compare which double variable is __bigger__? I don't totally get it. – Ivan Dec 05 '22 at 12:39
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
  • 23
    BigDecimal is sometimes not a viable solution. – mcfinnigan Nov 10 '11 at 15:57
  • 5
    But the poster was specifically asking about comparing doubles – typoerrpr May 04 '18 at 03:47
  • 1
    @mcfinnigan Could you please give an example when BigDecimal is not a viable solution? Because I am wondering what's the point of using double in production systems if it cannot perform such an easy operation as mentioned by original poster... – bridgemnc Jan 31 '23 at 07:51
  • @bridgemns Well, performance, memory footprint, multiplatform comes into mind. However fast BigDecimal is, it is still much slower than double which has it's own hardware implementation in the CPU. It uses more memory. And if you program multiplatform (in Kotlin for example), BigDecimal is not represented on all platforms (Javascript, Native). I agree that for money related calculations you should use BigDecimal. Other cases, it's not so simple. – tiz Jul 02 '23 at 02:14
11

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

Anand
  • 479
  • 5
  • 7
  • 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
3
        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
  • 106
  • 6
1

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
  • 41
  • 5
  • 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
0

This should be built into Java. There are a couple libraries that do a good job of safely comparing doubles, with a third 'epsilon' value:

  • Guava's DoubleMath:
// this returns true if roughlyOne is very close to 1
DoubleMath.fuzzyEquals(1.0, roughlyOne, 0.0001d)
  • Apache Common's has a very similar method, Precision.equals

And for what its worth, JUnit recently deprecated the equality assert methods that involve doubles that don't also include an epsilon threshold.

Adam Wise
  • 2,043
  • 20
  • 17
-4

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
  • 2,176
  • 19
  • 19
  • 4
    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,537
  • 3
  • 19
  • 37
Ibrahim
  • 37
  • 3