为什么HashSet区分0.0和-0.0

时间:2016-03-21 00:38:56

标签: java floating-point hashset

当我尝试这个时:

HashSet<Double> set = new HashSet<>();
Double d1 = new Double(0);
Double d2 = new Double(0);
Double d3 = new Double(-0);
set.add(d1);
System.out.println(set.contains(d2));
System.out.println(set.contains(d3));

输出符合我的预期:

true
true

但是当我尝试时:

HashSet<Double> set = new HashSet<>();
Double d1 = new Double(0.0);
Double d2 = new Double(0.0);
Double d3 = new Double(-0.0);
set.add(d1);
System.out.println(set.contains(d2));
System.out.println(set.contains(d3));

set.add(Double.valueOf(d1));
System.out.println(set.contains(Double.valueOf(d2)));
System.out.println(set.contains(Double.valueOf(d3)));

令我惊讶的是,输出结果为:

true
false

为什么会这样?如何使HashSet处理(0.0)和(-0.0)相同? 有没有比if(num == -0.0) num = 0.0;更好的方式?

3 个答案:

答案 0 :(得分:4)

Double Double解释了这一点。

  

如果d1表示+0.0而d2表示-0.0,反之亦然,则等于测试的值为false,即使+0.0 == - 0.0的值为true。

因此,从0.0创建的Double 与从-0.0创建的0相同。当您使用-0-0时,情况也是如此,因为整数使用二进制补码,它没有负零概念。 0double相同。另一方面,HashSetthe docs,它确实识别负零值。

此行为已得到修复,因此无法0.0对待-0.0self.userNameTextField.becomeFirstResponder() self.passwordTextField.becomeFirstResponder() 。如果您想这样做,在添加或搜索之前,您需要手动将所有负零值转换为正零。

答案 1 :(得分:2)

-0.0double值的文字,与0.0不同。

-0是应用于int0的否定运算符,它仅提供int0

因此,new Double(-0)相当于new Double(0),而new Double(-0.0)new Double(0.0)实际上产生了两个不相等的Double个对象。

有关为什么必须有两个不同的浮点零值,请参阅this question

答案 2 :(得分:1)

正如维基百科(感谢)中所解释的,浮点的IEEE格式实际上由于各种原因支持负和正零。 https://en.wikipedia.org/wiki/Signed_zero

您在散列映射中发现0.0和-0.0不同的原因直接来自IEEE表示。 Double#hashCode方法使用浮点数的原始位来计算哈希码。由于0.0和-0.0甚至可能+0.0在位方面不同,因为一些数值计算显然需要这样,它们的位是不同的,因此是哈希码。