为什么Double.NaN == Double.NaN返回false?

我刚刚学习OCPJP的问题,我发现这个奇怪的代码:

public static void main(String a[]) { System.out.println(Double.NaN==Double.NaN); System.out.println(Double.NaN!=Double.NaN); } 

当我运行代码时,我得到:

 false true 

当我们比较两个看起来相同的东西时,输出是falseNaN是什么意思?

NaN的意思是“不是一个数字”。

Java语言规范(JLS)第三版说 :

溢出的操作产生有符号的无穷大,下溢的操作产生非规格化的值或有符号的零,而没有math上确定的结果的操作产生NaN。 以NaN作为操作数的所有数字操作都会产生NaN。 如前所述,NaN是无序的,所以涉及一个或两个NaN的数字比较操作返回false ,任何!=涉及NaN的比较都返回true ,当x是NaN时,包括x!=x

NaN根据定义不等于包括NaN在内的任何数字。 这是IEEE 754标准的一部分,由CPU / FPU执行。 这不是JVM必须添加任何逻辑来支持的东西。

http://en.wikipedia.org/wiki/NaN

与NaN的比较总是返回一个无序的结果,即使与自己比较。 …等式和不等式谓词是非信号的,所以x = x返回false可以用来testingx是否是安静的NaN。

Java将所有NaN视为安静的NaN。

为什么这个逻辑

NaN意思Not a Number 。 什么不是数字? 任何东西。 你可以在一边有任何东西,而在另一边有任何东西,所以没有什么能保证两者是平等的。 NaN是用Double.longBitsToDouble(0x7ff8000000000000L)计算的,正如你在longBitsToDouble的文档中看到的longBitsToDouble

如果参数是0x7ff0000000000001L0x7fffffffffffffffL范围内的任何值,或者范围是0xfff0000000000001L0xffffffffffffffffL ,则结果是NaN

另外, NaN在API内部被逻辑处理。


文档

 /** * A constant holding a Not-a-Number (NaN) value of type * {@code double}. It is equivalent to the value returned by * {@code Double.longBitsToDouble(0x7ff8000000000000L)}. */ public static final double NaN = 0.0d / 0.0; 

顺便说一下, NaN 作为您的代码示例进行testing的:

 /** * Returns {@code true} if the specified number is a * Not-a-Number (NaN) value, {@code false} otherwise. * * @param v the value to be tested. * @return {@code true} if the value of the argument is NaN; * {@code false} otherwise. */ static public boolean isNaN(double v) { return (v != v); } 

你可以做的是使用compare / compare

这个方法认为Double.NaN等于它自己,并且大于所有其他的double值(包括Double.POSITIVE_INFINITY )。

 Double.compare(Double.NaN, Double.NaN); Double.NaN.compareTo(Double.NaN); 

或者equals

如果thisargument都表示Double.NaN ,那么即使Double.NaN==Double.NaN的值为falseequals方法也会返回true

 Double.NaN.equals(Double.NaN); 

Double.NaN的javadoc说:

一个常量,其中包含一个types为double非数字(NaN)值。 它相当于Double.longBitsToDouble(0x7ff8000000000000L)返回的Double.longBitsToDouble(0x7ff8000000000000L)

有趣的是, Double的源码定义了NaN

 public static final double NaN = 0.0d / 0.0; 

您描述的特殊行为是硬连线到JVM。

这可能不是问题的直接答案。 但是,如果你想检查是否有什么东西等于Double.NaN你应该使用这个:

 double d = Double.NaN Double.isNaN(d); 

这将返回true

NaN是一个特殊的值,表示“不是一个数字”。 它是某些无效算术运算的结果,例如sqrt(-1) ,并且具有NaN != NaN (有时是烦人的)属性。

根据双精度数字浮点运算的IEEE标准 ,

IEEE双精度浮点标准表示需要一个64位的字,可以从0到63的数字表示,从左到右

在这里输入图像描述 哪里,

 S: Sign – 1 bit E: Exponent – 11 bits F: Fraction – 52 bits 

如果E=2047 (全部E1 )并且F是非零,那么V=NaN (“不是数字”)

意思是,

如果所有的E位都是1,并且如果F有任何非零位,则数字是NaN

因此,其中以下所有数字都是NaN

 0 11111111 0000000000000000010000000000000000000000000000000000 = NaN 1 11111111 0000010000000000010001000000000000001000000000000000 = NaN 1 11111111 0000010000011000010001000000000000001000000000000000 = NaN 

尤其是,你不能testing

 if (x == Double.NaN) 

来检查一个特定的结果是否等于Double.NaN ,因为所有“不是一个数字”的值被认为是不同的。 但是,您可以使用Double.isNaN方法:

 if (Double.isNaN(x)) // check whether x is "not a number" 

不是数字表示结果不能用数字表示的操作的结果。 最着名的操作是0/0,其结果是未知的。

出于这个原因,NaN不等于任何东西(包括其他非数值)。 有关更多信息,请查看维基百科页面: http : //en.wikipedia.org/wiki/NaN