Java中对NaN的困惑

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()方法的实际工作是什么。

请尝试运行以下代码以查看值:

 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 

在DoubleToRawLongBits方法的Javadoc中记录了这个缺陷:

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

IEEE 754标准允许NaN不同位模式。 出于计算和比较的目的,它们应该都是相同的(即NaN比较不等于它自己,不是有序的,并且涉及NaN每个计算都是NaN本身)。 使用doubleToRawLongBits您可以获得使用的确切位模式。 这在JLS中也有详细说明:

在大多数情况下,Java平台将给定类型的NaN值视为折叠为单个规范值(因此,此规范通常指的是任意NaN,就像规范值一样)。 但是,Java平台版本1.3引入了使程序员能够区分NaN值的方法: Float.floatToRawIntBitsDouble.double- ToRawLongBits方法。 感兴趣的读者可以参考FloatDouble类的规范以获取更多信息。

在你的情况下,符号位是不同的,在这种情况下,我可以引导你到维基百科 ,它简明扼要地总结:

在符合IEEE 754标准的浮点存储格式中,NaN由NaN独有的特定预定义位模式识别。 符号位无关紧要。

你的两个值都是NaN ,它们只是使用不同的位来表示它。 IEEE 754允许的东西,在这种情况下,可能源于编译器将Double.NaN替换为导致NaN的常量计算,而实际硬件给出不同的结果,如Mysticial在对该问题的评论中所怀疑的那样 。

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

原因是因为当你将一个双变量0除以0时它返回NaN,所以该方法没有二进制的单个规范表示,因此它可能返回NaN的二进制为7F F8 00 00 00 00 00 00或FF F8 00 00 00 00 00 00。

尽管从技术上来说它们代表的是同一个东西,即NaN,它在二进制表示方面也有所不同。