简体   繁体   English

为什么Double.NaN在包装在Double实例中时自相同?

[英]Why does Double.NaN equal itself when wrapped in a Double instance?

From this question I learned Double.NaN is not equal to itself. 这个问题我学到了Double.NaN不等于它自己。

I was verifying this for myself and noticed this is not the case if you wrap Double.NaN in a Double instance. 我正在为自己验证这一点,并注意到如果你在Double实例中包装Double.NaN则不是这种情况。 For example: 例如:

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);
    }
}

Outputs: 输出:

Test 1 = false
Test 2 = true
Test 3 = false

It seems to me that all three tests should evaluate to false as all three operations are equivalent (as they are if you use something other then Double.NaN). 在我看来,所有三个测试都应该评估为false,因为所有三个操作都是等效的(因为如果你使用Double.NaN之外的其他东西)。

Could someone explain what's going on here? 有人能解释一下这里发生了什么吗?

What is going on is that the equals method deliberately deviates from IEE floating point. 发生的事情是equals方法故意偏离IEE浮点。 Quoting from the Javadoc for the equals(Object) method of java.lang.Double . 从Javadoc引用java.lang.Doubleequals(Object)方法。

However, there are two exceptions: 但是,有两个例外:

  • If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN==Double.NaN has the value false. 如果d1和d2都表示Double.NaN,则equals方法返回true,即使Double.NaN == Double.NaN的值为false。
  • If d1 represents +0.0 while d2 represents -0.0, or vice versa, the 如果d1代表+0.0而d2代表-0.0,反之亦然
    equal test has the value false, even 等值测试的值甚至是假的
    though +0.0==-0.0 has the value true. 虽然+0.0 == - 0.0的值为true。

This definition allows hash tables to operate properly. 此定义允许哈希表正常运行。

The upshot is that if you want 100% IEE floating point compatibility you need to explicitly unbox the java.lang.Double instances and compare the resulting double values. 结果是,如果您想要100%IEE浮点兼容性,则需要显式地取消对java.lang.Double实例的打开并比较生成的double值。

It's so hash tables work right 这样哈希表就可以了

They deliberately deviated from the IEEE way so hash tables would work. 他们故意偏离IEEE方式,因此哈希表可以工作。

You can get part of the story in the api docs . 您可以在api文档中获取部分故事。 The rest of the story is: every class that inherits from Object, which is all of them, has a contract to maintain the Object invariants. 故事的其余部分是:每个继承自Object的类(都是它们)都有一个维护Object不变量的契约。 The contract exists so that the rest of the library can implement all those nice collections and things. 合同存在,以便库的其余部分可以实现所有那些好的集合和事物。 Nothing really stops you from damaging this, but then you can't be certain that things that take Object's will work. 没有什么可以阻止你破坏它,但是你不能确定那些使用Object的东西会起作用。

If one has two immutable objects which define Equals to return true when every field in one object reports itself Equal to the corresponding field in the other, and if none of the code which uses the objects cares about reference equality, then it should be possible to replace all references to one object with references to the other. 如果有两个不可变对象定义Equals ,当一个对象中的每个字段报告自己Equal另一个对应的字段时返回true,并且如果使用这些对象的代码都不关心引用相等,则应该可以用对另一个对象的引用替换对一个对象的所有引用。 If the objects are generated by eg parsing data read from disk, and if many objects will compare equal, replacing many different instances with references to one instance may improve performance greatly. 如果通过例如解析从磁盘读取的数据来生成对象,并且如果许多对象将比较相等,则通过对一个实例的引用替换许多不同的实例可以极大地提高性能。 Note that the correctness of such substitution does not depend upon whether the objects are shallowly or deeply immutable, provided only that any mutable objects nested within them will report themselves as unequal to anything other than themselves. 请注意,这种替换的正确性并不取决于对象是浅层还是深层不可变的,前提是嵌套在其中的任何可变对象都会将自身报告为与其他任何东西不相等。

For such logic to work correctly, it's important that the objects in question be fully equivalent. 为了使这种逻辑正常工作,重要的是所讨论的对象完全等效。 Every object is required to be equal to itself, so Double.NaN must equal Double.NaN . 每个对象都必须等于自身,因此Double.NaN必须等于Double.NaN The requirement for full equivalence implies that positive zero must not report itself equal to negative zero (since if it did, an object which holds a positive zero might behave differently from one holding negative zero). 完全等价的要求意味着正零必须不报告自己等于负零(因为如果它确实如此,保持正零的对象可能与保持负零的对象不同)。

Note, btw, that this is an area where .net differs from Java (some non-equivalent floating-point and Decimal values are report Equals ); 注意,顺便说一下,这是.net与Java不同的区域(一些非等效的浮点和Decimal值是报告Equals ); in many ways, I think .net is superior, but this detail is one that .net got wrong. 在很多方面,我认为.net是优越的,但这个细节是.net出错了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM