[英]Why does Double.NaN equal itself when wrapped in a Double instance?
从这个问题我学到了Double.NaN不等于它自己。
我正在为自己验证这一点,并注意到如果你在Double实例中包装Double.NaN则不是这种情况。 例如:
public class DoubleNaNTest {
public static void main(String[] args) {
double primitive = Double.NaN;
Double object = new Double(primitive);
// test 1 - is the primitive is equal to itself?
boolean test1 = primitive == primitive;
// test 2 - is the object equal to itself?
boolean test2 = object.equals(object);
// test 3 - is the double value of the object equal to itself?
boolean test3 = object.doubleValue() == object.doubleValue();
System.out.println("Test 1 = " + test1);
System.out.println("Test 2 = " + test2);
System.out.println("Test 3 = " + test3);
}
}
输出:
Test 1 = false
Test 2 = true
Test 3 = false
在我看来,所有三个测试都应该评估为false,因为所有三个操作都是等效的(因为如果你使用Double.NaN之外的其他东西)。
有人能解释一下这里发生了什么吗?
发生的事情是equals
方法故意偏离IEE浮点。 从Javadoc引用java.lang.Double的equals(Object)
方法。
但是,有两个例外:
- 如果d1和d2都表示Double.NaN,则equals方法返回true,即使Double.NaN == Double.NaN的值为false。
- 如果d1代表+0.0而d2代表-0.0,反之亦然
等值测试的值甚至是假的
虽然+0.0 == - 0.0的值为true。此定义允许哈希表正常运行。
结果是,如果您想要100%IEE浮点兼容性,则需要显式地取消对java.lang.Double
实例的打开并比较生成的double
值。
他们故意偏离IEEE方式,因此哈希表可以工作。
您可以在api文档中获取部分故事。 故事的其余部分是:每个继承自Object的类(都是它们)都有一个维护Object不变量的契约。 合同存在,以便库的其余部分可以实现所有那些好的集合和事物。 没有什么可以阻止你破坏它,但是你不能确定那些使用Object的东西会起作用。
如果有两个不可变对象定义Equals
,当一个对象中的每个字段报告自己Equal
另一个对应的字段时返回true,并且如果使用这些对象的代码都不关心引用相等,则应该可以用对另一个对象的引用替换对一个对象的所有引用。 如果通过例如解析从磁盘读取的数据来生成对象,并且如果许多对象将比较相等,则通过对一个实例的引用替换许多不同的实例可以极大地提高性能。 请注意,这种替换的正确性并不取决于对象是浅层还是深层不可变的,前提是嵌套在其中的任何可变对象都会将自身报告为与其他任何东西不相等。
为了使这种逻辑正常工作,重要的是所讨论的对象完全等效。 每个对象都必须等于自身,因此Double.NaN
必须等于Double.NaN
。 完全等价的要求意味着正零必须不报告自己等于负零(因为如果它确实如此,保持正零的对象可能与保持负零的对象不同)。
注意,顺便说一下,这是.net与Java不同的区域(一些非等效的浮点和Decimal
值是报告Equals
); 在很多方面,我认为.net是优越的,但这个细节是.net出错了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.