+0 和 -0 显示 int 和 float 数据的不同行为

Jok*_*ker 14 java java-8

我读过这篇文章负和正零

根据我的理解,以下代码应该给出truetrue 作为输出。

然而,它是给予falsetrue作为输出。

我正在比较负零和正零。

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));
      }
  }
Run Code Online (Sandbox Code Playgroud)

为什么我们对 0Integer和0 有不同的行为Float

ysh*_*vit 17

Ints 和 floats 在 Java 中是完全不同的野兽。Ints 被编码为二进制补码,它有一个 0 值。浮点数使用IEEE 754(浮点数使用32 位变体,双精度数使用64位变体)。IEEE 754 有点复杂,但出于此答案的目的,您只需要知道它包含三个部分,其中第一个是符号位。这意味着对于任何浮动,都有一个积极和消极的变体¹。这包括 0,所以浮点数实际上有两个“零”值,+0 和 -0。

顺便说一句,int 使用的二进制补码并不是计算机科学中对整数进行编码的唯一方法。还有其他方法,比如ones'complement,但它们有一些怪癖——比如同时使用+0和-0作为不同的值。;-)

当您比较浮点基元(和双精度数)时,Java 将 +0 和 -0 视为相等。但是当您将它们装箱时,Java 将它们分开处理,如 中所述Float#equals。这让 equals 方法与它们的hashCode实现(以及compareTo)保持一致,它只使用浮点数的位(包括带符号的值)并将它们按原样推送到 int 中。

他们本可以为 equals/hashCode/compareTo 选择其他选项,但他们没有。我不确定那里的设计考虑是什么。但至少在一个方面,Float#equals总是会与 float 原语不同==:在原语中,NaN != NaN,但对于所有对象,o.equals(o)也必须为 true。这意味着,如果你有Float f = Float.NaN,那么f.equals(f)即使f.floatValue() != f.floatValue().


¹ NaN(非数字)值有一个符号位,但除了排序之外没有任何意义,Java 忽略它(即使是排序)。


use*_*900 9

这是Float 等于异常之一

有两个例外:

如果 f1 代表 +0.0f 而 f2 代表 -0.0f,反之亦然,则相等测试的值为false

还描述了原因:

此定义允许哈希表正常运行。

-0 和 0 将使用 Float 的第 31 位以不同方式表示:

第 31 位(由掩码 0x80000000 选择的位)表示浮点数的符号。

情况并非如此 Integer

  • 这个答案(和javadoc)没有提到的一个关键部分是,区别在于,在浮点数中,+0 和 -0 是不同的值——等效,但不同。基本上,浮点数由三个部分组成,第一部分是一个位,表示浮点数是正数还是负数。对于整数(如 Java 中所示)来说,情况并非如此,它只有一个 0 值。 (4认同)
  • @Joker *第31位(由掩码0x80000000选择的位)表示浮点数的符号。* (3认同)