Confusion on NaN in Java

后端 未结 4 1108
深忆病人
深忆病人 2020-12-29 08:22
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.doub         


        
相关标签:
4条回答
  • 2020-12-29 08:43

    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.

    0 讨论(0)
  • 2020-12-29 08:43

    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.

    0 讨论(0)
  • 2020-12-29 08:51

    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.

    0 讨论(0)
  • 2020-12-29 08:54

    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

    0 讨论(0)
提交回复
热议问题