Difference Between Double and Double in Comparison

Difference between double and Double in comparison

c and d are technically two different objects and == operator compares only references.

c.equals(d)

is better as it compares values, not references. But still not ideal. Comparing floating-point values directly should always take some error (epsilon) into account (Math.abs(c - d) < epsilon).

Note that:

Integer c = 1;
Integer d = 1;

here comparison would yield true, but that's more complicated (Integer internal caching, described in JavaDoc of Integer.valueOf()):

This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

Why valueOf()? Because this method is implicitly used to implement autoboxing:

Integer c = Integer.valueOf(1);
Integer d = Integer.valueOf(1);

See also

  • Weird Integer boxing in Java
  • How to properly compare two Integers in Java?

What is the difference between Double and double in Java?

Double is an object and double is a primitive data type. See this answer for more details.

The Double class wraps a value of the primitive type double in an
object. An object of type Double contains a single field whose type is
double.

Source: http://docs.oracle.com/javase/7/docs/api/java/lang/Double.html

What is the difference between double? and int? for .Equals comparisons?

You are completely right to find this confusing. It is a mess.

Let's start by clearly saying what happens by looking at more examples, and then we will deduce the correct rules that are being applied here. Let's extend your program to consider all these cases:

    double d = 2;
double? nd = d;
int i = 2;
int? ni = i;
Console.WriteLine(d == d);
Console.WriteLine(d == nd);
Console.WriteLine(d == i);
Console.WriteLine(d == ni);
Console.WriteLine(nd == d);
Console.WriteLine(nd == nd);
Console.WriteLine(nd == i);
Console.WriteLine(nd == ni);
Console.WriteLine(i == d);
Console.WriteLine(i == nd);
Console.WriteLine(i == i);
Console.WriteLine(i == ni);
Console.WriteLine(ni == d);
Console.WriteLine(ni == nd);
Console.WriteLine(ni == i);
Console.WriteLine(ni == ni);
Console.WriteLine(d.Equals(d));
Console.WriteLine(d.Equals(nd));
Console.WriteLine(d.Equals(i));
Console.WriteLine(d.Equals(ni)); // False
Console.WriteLine(nd.Equals(d));
Console.WriteLine(nd.Equals(nd));
Console.WriteLine(nd.Equals(i)); // False
Console.WriteLine(nd.Equals(ni)); // False
Console.WriteLine(i.Equals(d)); // False
Console.WriteLine(i.Equals(nd)); // False
Console.WriteLine(i.Equals(i));
Console.WriteLine(i.Equals(ni));
Console.WriteLine(ni.Equals(d)); // False
Console.WriteLine(ni.Equals(nd)); // False
Console.WriteLine(ni.Equals(i));
Console.WriteLine(ni.Equals(ni));

All of those print True except the ones I have notated as printing false.

I'll now give an analysis of those cases.

The first thing to notice is that the == operator always says True. Why is that?

The semantics of non-nullable == are as follows:

int == int -- compare the integers
int == double -- convert the int to double, compare the doubles
double == int -- same
double == double -- compare the doubles

So in every non-nullable case, integer 2 is equal to double 2.0 because the int 2 is converted to double 2.0, and the comparison is true.

The semantics of nullable == are:

  • If both operands are null, they're equal
  • If one is null and the other is not, they're unequal
  • If both are not null, then fall back to the non-nullable case above.

So again, we see that for the nullable comparisons, int? == double?, int? == double, and so on, we always fall back to the non-nullable cases, convert the int? to double, and do the comparison in doubles. Thus these are also all true.

Now we come to Equals, which is where things get messed up.

There is a fundamental design problem here, which I wrote about in 2009: https://blogs.msdn.microsoft.com/ericlippert/2009/04/09/double-your-dispatch-double-your-fun/ -- the problem is that the meaning of == is resolved based on the compile time types of both operands. But Equals is resolved on the basis of the run time type of the left operand (the receiver), but the compile time type of the right operand (the argument), and that's why things go off the rails.

Let's begin by looking at what double.Equals(object) does. If the receiver of a call to Equals(object) is double then if the argument is not a boxed double, they are considered not equal. That is, Equals requires that the types match, whereas == requires that the types be convertible to a common type.

I'll say that again. double.Equals does not try to convert its argument to double, unlike ==. It just checks to see if it already is double, and if it is not, then it says they are not equal.

That then explains why d.Equals(i) is false... but... wait a minute, it is not false above! What explains this?

double.Equals is overloaded! Above we are actually calling double.Equals(double), which -- you guessed it -- converts the int to a double before doing the call! If we had said d.Equals((object)i)) then that would be false.

All right, so we know why double.Equals(int) is true -- because the int is converted to double.

We also know why double.Equals(int?) is false. int? is not convertible to double, but it is to object. So we call double.Equals(object) and box the int, and now its not equal.

What about nd.Equals(object) ? The semantics of that is:

  • If the receiver is null and the argument is null, they are equal
  • If the receiver is not null then defer to the non-nullable semantics of d.Equals(object)

So now we know why nd.Equals(x) works if x is a double or double? but not if it is int or int?. (Though interestingly, of course (default(double?)).Equals(default(int?)) would be true since they are both null!)

Finally, by similar logic we see why int.Equals(object) gives the behaviour it has. It checks to see if its argument is a boxed int, and if it is not, then it returns false. Thus i.Equals(d) is false. The i cannot be converted to double, and the d cannot be converted to int.

This is a huge mess. We would like equality to be an equivalence relation, and it is not! An equality relationship should have these properties:

  • Reflexivity: a thing is equal to itself. That is usually true in C# though there are a few exceptions.
  • Symmetry: If A is equal to B then B is equal to A. That is true of == in C# but not of A.Equals(B), as we've seen.
  • Transitivity: If A equals B and B equals C then A also equals C. That is absolutely not the case in C#.

So, its a mess on all levels. == and Equals have different dispatch mechanisms and give different results, neither of them are equivalence relations, and it's all confusing all the time. Apologies for getting you into this mess, but it was a mess when I arrived.

For a slightly different take on why equality is terrible in C#, see item number nine on my list of regrettable language decisions, here: http://www.informit.com/articles/article.aspx?p=2425867

BONUS EXERCISE: Repeat the above analysis, but for x?.Equals(y) for the cases where x is nullable. When do you get the same results as for non-nullable receivers, and when do you get different results?

Why is Java's Double.compare(double, double) implemented the way it is?

@Shoover's answer is correct (read it!), but there is a bit more to it than this.

As the javadoc for Double::equals states:

"This definition allows hash tables to operate properly."

Suppose that the Java designers had decided to implement equals(...) and compare(...) with the same semantics as == on the wrapped double instances. This would mean that equals() would always return false for a wrapped NaN. Now consider what would happen if you tried to use a wrapped NaN in a Map or Collection.

List<Double> l = new ArrayList<Double>();
l.add(Double.NaN);
if (l.contains(Double.NaN)) {
// this wont be executed.
}

Map<Object,String> m = new HashMap<Object,String>();
m.put(Double.NaN, "Hi mum");
if (m.get(Double.NaN) != null) {
// this wont be executed.
}

Doesn't make a lot of sense does it!

Other anomalies would exist because -0.0 and +0.0 have different bit patterns but are equal according to ==.

So the Java designers decided (rightly IMO) on the more complicated (but more intuitive) definition for these Double methods that we have today.

What's the best way to compare Double and Int?

You really can't compare floating point and integral values in a naive way; particularly, since there's the classic floating point representation challenges. What you can do is subtract one from the other and see if the difference between them is less than some precision you care about, like so:

int iValue = 0;
double dValue = 0.0;

var diff = Math.Abs(dvalue - iValue);
if( diff < 0.0000001 ) // need some min threshold to compare floating points
return true; // items equal

You really have to define for yourself what equality means to you. For example, you may want a floating point value to round towards the nearest integer, so that 3.999999981 will be "equal" to 4. Or you may want to truncate the value, so it would effectively be 3. It all depends on what you're trying to achieve.

EDIT: Note that i chose 0.0000001 as an example threshold value ... you need to decide for yourself what precision is sufficient for comparison. Just realize you need to be within the normal representational bounds of double which I believe is defined as Double.Epsilon.

Is it valid to compare a double with an int in java?

Yes, it's valid - it will promote the int to a double before performing the comparison.

See JLS section 15.20.1 (Numerical Comparison Operators) which links to JLS section 5.6.2 (Binary Numeric Promotion).

From the latter:

Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

  • If either operand is of type double, the other is converted to double.

  • ...

Comparing class double with primitive double

Yes, this is good practice. Java makes auto-unboxing Double -> double.

P.S. By the way, correct comparison of double is Double.compare(one, two) == 0

Long and Double comparison (==) behaves differently

Long v1 = 1L;
Long v2 = 1L;
Double d1 = 1.0;
Double d2 = 1.0;

You are creating two references to objects here, and instantiating two objects with autoboxing behaviour of Java.

Java re-uses the same Long object instance from a pool for v1 and v2, The Doubles do not use a pool for remembering values, as can be read in this informative blog entry https://gerardnico.com/code/type/autoboxing

Here are some rules as with Java 5 :

autoboxing to Boolean and Byte always returns an object from the pool

autoboxing to Char, Short, Integer and Long returns an object from the
pool when the autoboxed value is between -128 and 127 (inclusive)

autoboxing of Float and Double does not use the pool and always
returns a new object

Your code becomes then with autoboxing(some pool is a visualisation of the pool java uses to cache certain values):

class SomePoolJavaUses {
static Long _l1 = new Long(1L);
static Long _l2 = new Long(2L);
static Long _l3 = new Long(3L);
...
}

Long v1 = SomePoolJavaUses._l1;
Long v2 = SomePoolJavaUses._l1;
Double d1 = new Double(1.0);
Double d2 = new Double(1.0);

This means that d1 and d2 are not equal instances, so they are not equal in ==

This means that v1 and v2 are equal instance, so they are equal in ==

the v1.equals returns true, because there is being looked at the actual value there instead of a quick check if the memory addresses are the same.

How to compare two double values in Java?

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) {...}

Double vs double in java

First off you need to understand the difference between the two types.
double is a primitive type whereas Double is an Object.

The code below shows an overloaded method, which I assume is similar to your lab code.

void doStuff(Double d){ System.out.println("Object call"); }
void doStuff(double d){ System.out.println("Primitive call"); }

There are several ways you can call these methods:

doStuff(100);
doStuff(200d);
doStuff(new Double(100));

These calls will result in:

"Primitive call"
"Primitive call"
"Object call"


Related Topics



Leave a reply



Submit