Java中NaN的困惑

2022-09-03 15:43:27
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

请帮助我前两个和最后一个的输出是如何产生的。请告诉我Double.doubleToRawLongBits()方法的实际工作是什么。truefalse


答案 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 值。


答案 2

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

尽管从技术上讲,它们表示相同的事物,即NaN,它在二进制表示中是不同的。