Java 符号零和装箱

2022-09-01 02:39:21

最近我用Java写了一个项目,注意到一个非常奇怪的功能,带有double/Double实现。Java中的双精度类型有两个0,即0.0和-0.0(有符号零)。奇怪的是:

0.0 == -0.0

计算结果为 ,但:true

new Double(0.0).equals(new Double(-0.0))

计算结果为 。有谁知道这背后的原因吗?false


答案 1

这一切都在javadoc中进行了解释:

请注意,在大多数情况下,对于双子类 d1 和 d2 的两个实例,当且仅当 d1.equals(d2) 的值为真

   d1.doubleValue() == d2.doubleValue() 

也具有值 true。但是,有两种例外情况:

  • 如果 d1 和 d2 都表示 Double.NaN,则 equals 方法返回 true,即使 Double.NaN==Double.NaN 的值为 false。
  • 如果 d1 表示 +0.0,而 d2 表示 -0.0,反之亦然,则相等检验的值为 false,即使 +0.0==-0.0 的值为 true。

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


现在你可能会问为什么这是真的。事实上,它们并不完全相同。例如:0.0 == -0.0

Double.doubleToRawLongBits(0.0) == Double.doubleToRawLongBits(-0.0); //false

是假的。但是,JLS要求(“根据IEEE 754标准的规则”)::

正零和负零被视为相等。

因此,这是真的。0.0 == -0.0


答案 2

在 Double 类中使用有符号零非常重要(大量有经验的 Java 程序员不会这样做)。

简短的回答是(根据定义)“-0.0小于0.0”在Double类提供的所有方法中(即equals(),compare(),compareTo()等)

Double 允许所有浮点数“在数字行上完全排序”。基元的行为方式是用户思考事物的方式(现实世界的定义)......0d = -0d

以下片段说明了行为...

final double d1 = 0d, d2 = -0d;

System.out.println(d1 == d2); //prints ... true
System.out.println(d1 < d2);  //prints ... false
System.out.println(d2 < d1);  //prints ... false
System.out.println(Double.compare(d1, d2)); //prints ... 1
System.out.println(Double.compare(d2, d1)); //prints ... -1

还有其他相关的帖子,并很好地解释了背景...

1: 为什么浮点数有符号零?

2: 为什么Java的Double.compare(double,double)是这样实现的?

还有一句警告...

如果你不知道,在 Double 类中,“-0.0 小于 0.0”,那么在逻辑测试中使用 Double 中的 equals()compare()compareTo() 等方法时,你可能会被抓到。例如,看看...

final double d3 = -0d; // try this code with d3 = 0d; for comparison

if (d3 < 0d) {     
    System.out.println("Pay 1 million pounds penalty");
} else {           
    System.out.println("Good things happen"); // this line prints
}


if (Double.compare(d3, 0d) < 0) { //use Double.compare(d3, -0d) to match the above behaviour
    System.out.println("Pay 1 million pounds penalty"); // this line prints
} else {                              
    System.out.println("Good things happen"); 
}

对于平等,您可以尝试...新的 Double(d3).equals(0d) ||新的双精度(d3).等于(-0d)


推荐