Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

+0 and -0 shows different behavior for int and float data

Tags:

java

java-8

I have read this post negative and positive zero.

To my understanding following code should give true and true as a output.

However, it is giving false and true as a output.

I'm comparing negative zero with a positive zero.

public class Test {
     public static void main(String[] args) {
            float f = 0;
            float f2 = -f;
            Float F = new Float(f);
            Float F1 = new Float(f2);
            System.out.println(F1.equals(F));

            int i = 0;
            int i2 = -i;
            Integer I = new Integer(i);
            Integer I1 = new Integer(i2);
            System.out.println(I1.equals(I));
      }
  }

Why do we have different behavior for 0's for Integer and Float ?

like image 852
Sachin Sachdeva Avatar asked Dec 11 '19 06:12

Sachin Sachdeva


2 Answers

Ints and floats are pretty different beasts in Java. Ints are encoded as two's complement, which has a single 0 value. Floats use IEEE 754 (the 32-bit variant for floats, and 64-bit for doubles). IEEE 754 is somewhat complex, but for purpose of this answer, you just need to know that it has three sections, the first of which is a sign bit. That means for any float, there's a positive and negative variant¹. That includes 0, so floats actually have two "zero" values, +0 and -0.

As an aside, the two's complement that ints use is not the only way to encode integers in computer science. There are other methods, like ones' complement, but they have quirks — like having both a +0 and -0 as distinct values. ;-)

When you compare float primitives (and doubles), Java treats +0 and -0 as equal. But when you box them, Java treats them separately, as described in Float#equals. This lets the equals method be consistent with their hashCode implementation (as well as compareTo), which just uses the bits of the float (including that signed value) and shoves them as-is into an int.

They could have picked some other option for equals/hashCode/compareTo, but they didn't. I'm not sure what the design considerations there were. But in at least one regard, Float#equals was always going to diverge from the float primitive's ==: In primitives, NaN != NaN, but for all objects, o.equals(o) must also be true. That means that if you had Float f = Float.NaN, then f.equals(f) even though f.floatValue() != f.floatValue().


¹ NaN (not-a-number) values have a sign bit, but it doesn't have any meaning other than for ordering, and Java ignores it (even for ordering).

like image 199
yshavit Avatar answered Oct 23 '22 15:10

yshavit


This is one of Float equals exception

there are two exceptions:

If f1 represents +0.0f while f2 represents -0.0f, or vice versa, the equal test has the value false

The why is described also:

This definition allows hash tables to operate properly.

-0 and 0 will represented differently using Float's bit 31:

Bit 31 (the bit that is selected by the mask 0x80000000) represents the sign of the floating-point number.

This isn't the case in Integer

like image 37
user7294900 Avatar answered Oct 23 '22 15:10

user7294900