Confusion on NaN in Java

心不动则不痛 提交于 2019-11-29 06:44:35

问题


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

output:

true
true
false

Please help me how the output came true for first two and false for last one. Please tell me what is actual work of Double.doubleToRawLongBits() method.


回答1:


Please try to run following code to see the values:

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

On my Mac, it produces following output:

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

This pitfall is documented in the Javadoc for the doubleToRawLongBits method:

If the argument is NaN, the result is the long integer representing the actual NaN value. Unlike the doubleToLongBits method, doubleToRawLongBits does not collapse all the bit patterns encoding a NaN to a single "canonical" NaN value.




回答2:


The reason is because when you divide a double variable 0 by 0 it returns NaN, so the method doesnt have a single canonical representation in binary, so it may return the binary of NaN as 7F F8 00 00 00 00 00 00 or FF F8 00 00 00 00 00 00.

Even though technically they represent the same thing, which is NaN, its different in binary representation.




回答3:


The IEEE 754 standard allows different bit patterns for NaN. For computation and comparison purposes they should all work the same (i.e. NaN compares not equal to itself, is not ordered and every computation involving NaN is NaN itself). With doubleToRawLongBits you get the exact bit pattern used. This is also detailed in the JLS:

For the most part, the Java platform treats NaN values of a given type as though collapsed into a single canonical value (and hence this specification nor- mally refers to an arbitrary NaN as though to a canonical value). However, version 1.3 the Java platform introduced methods enabling the programmer to distinguish between NaN values: the Float.floatToRawIntBits and Double.double- ToRawLongBits methods. The interested reader is referred to the specifications for the Float and Double classes for more information.

In your case the sign bit is different, in this case I can direct you to Wikipedia, which summarises this concisely:

In IEEE 754 standard-conforming floating point storage formats, NaNs are identified by specific, pre-defined bit patterns unique to NaNs. The sign bit does not matter.

Both your values are NaN, they just use different bits to represent that. Something that is allows by IEEE 754 and in this case probably stems from the compiler substituting Double.NaN for a constant computation that results in NaN while the actual hardware gives a different result, as suspected by Mysticial in a comment to the question already.




回答4:


I think Java follows IEEE 754. In this case NaN has more than one possible bit representation. The two representations in your case differ in the "sign" bit. The value of the sign bit seems to be not defined by the standard and is usually ignored. So both values are correct. See http://en.wikipedia.org/wiki/NaN



来源:https://stackoverflow.com/questions/11008755/confusion-on-nan-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!