在Java中的混乱南朝(Confusion on NaN in Java)

2019-06-25 11:01发布

int i = 0, j = 0;
double nan1 = (double)0/0;
double nan2 = (double)0/0;
double nan3 = (double)i/j;
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2));
System.out.println(Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0));
System.out.println(Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2));

输出:

true
true
false

请帮我输出怎么来true的前两个和false的最后一个。 请告诉我什么是Double.doubleToRawLongBits的实际工作()方法。

Answer 1:

请尝试运行下面的代码来查看值:

public class Test
{
    public static void main(String[] args){
        int i = 0, j = 0;
        double nan1 = (double)0/0;
        double nan2 = (double)0/0;
        double nan3 = (double)i/j;
        System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits(nan2) + " is " +
            (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits(nan2)));
        System.out.println(Double.doubleToRawLongBits(nan1) + " == "+ Double.doubleToRawLongBits((double)0/0) + " is " +
            (Double.doubleToRawLongBits(nan1) == Double.doubleToRawLongBits((double)0/0)));
        System.out.println(Double.doubleToRawLongBits(nan3) + " == "+ Double.doubleToRawLongBits(nan2) + " is " +
            (Double.doubleToRawLongBits(nan3) == Double.doubleToRawLongBits(nan2)));
    }
}

在我的Mac,它会产生以下的输出:

9221120237041090560 == 9221120237041090560 is true
9221120237041090560 == 9221120237041090560 is true
-2251799813685248 == 9221120237041090560 is false

这个陷阱记录在Javadoc的doubleToRawLongBits方法 :

如果参数是NaN,则结果是表示实际NaN值的长整数。 与doubleToLongBits方法不同不同,doubleToRawLongBits不塌陷所有将NaN编码为一个单一的“规范” NaN值的位模式。



Answer 2:

IEEE 754标准允许不同的位模式NaN 。 对于计算和比较的目的,他们应该所有的工作相同(即NaN比较不等于本身,不排序,涉及每一个计算NaNNaN本身)。 随着doubleToRawLongBits你使用的确切位模式。 这也详细介绍了JLS:

在大多数情况下,Java平台把一个给定类型的NaN值如同折叠到单个规范值(因此本说明书中去甲马利是指任意的NaN仿佛到规范值)。 然而,1.3版本在Java平台中引入的方法使程序员NaN值来区分:在Float.floatToRawIntBitsDouble.double- ToRawLongBits方法。 有兴趣的读者可以参考的规格为FloatDouble班以获取更多信息。

在你的情况下,签位是不同的,在这种情况下,我可以引导您到维基百科 ,它总结了简洁:

在IEEE 754符合标准的浮点存储格式,NaN是由特定的预定义的位独有的NaN图案识别。 符号位并不重要。

无论你的价值观是NaN ,他们只是使用不同的比特来表示。 东西是可以通过IEEE 754在这种情况下可能是由编译器代替茎Double.NaN对于恒定计算导致NaN ,而实际的硬件给出了不同的结果,因为涉嫌Mysticial在评论的问题了。



Answer 3:

我认为Java遵循IEEE 754在这种情况下楠多个可能的位表示。 你的情况这两种表述在“符号”有点不同。 符号位的值似乎不是由标准限定,通常被忽略。 所以,这两个值是正确的。 见http://en.wikipedia.org/wiki/NaN



Answer 4:

其理由是因为当你除以0双变量0它返回NaN,所以不必须在二进制单个规范表示,因此它可以返回的NaN的二进制作为7F F8 00 00 00 00 00 00或FF F8 00的方法00 00 00 00 00。

尽管在技术上它们代表相同的事情,这是NaN,它的二进制表示不同。



文章来源: Confusion on NaN in Java