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

时间:2012-01-11 13:02:31

标签: java floating-point nan scjp ocpjp

我正在研究OCPJP问题,我发现了这个奇怪的代码:

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

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

false
true

当我们比较两个看起来彼此相同的东西时,输出false怎么样? NaN是什么意思?

10 个答案:

答案 0 :(得分:136)

NaN表示“不是数字”。

Java Language Specification (JLS) Third Edition says

  

溢出的操作产生有符号的无穷大,下溢的操作产生非规范化值或有符号零,并且没有数学定义结果的操作产生NaN。以NaN作为操作数的所有数值运算都会产生NaN。正如已经描述的那样,NaN是无序的,因此涉及一个或两个NaN的数字比较操作返回false,并且涉及NaN的任何!=比较返回true,包括x!=xx是NaN。

答案 1 :(得分:60)

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

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

  

与NaN进行比较时,即使与自身进行比较,也会返回无序结果。 ...相等和不等式谓词是非信令的,因此x = x返回false可用于测试x是否是安静的NaN。

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

答案 2 :(得分:48)

为何选择逻辑

NaN表示Not a Number。什么不是数字?任何东西。你可以在一边拥有任何东西,在另一边拥有任何东西,所以没有什么可以保证两者都是平等的。 NaN使用Double.longBitsToDouble(0x7ff8000000000000L)进行计算,您可以在longBitsToDouble的文档中看到:

  

如果参数是范围0x7ff0000000000001L到的任何值   0x7fffffffffffffffL0xfff0000000000001L0xffffffffffffffffL范围内   NaN,结果为NaN

此外,/** * 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; 在API内部进行了逻辑处理。


<强>文档

NaN

顺便说一下,/** * 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

<强>解决方案

您可以使用compareTo / Double.NaN

  此方法认为

double等于自身   并且大于所有其他Double.POSITIVE_INFINITY值(包括   Double.compare(Double.NaN, Double.NaN); Double.NaN.compareTo(Double.NaN); )。

equals

或者,this

  

如果argumentDouble.NaN都代表equals,那么   尽管true方法返回Double.NaN==Double.NaN   false的值为Double.NaN.equals(Double.NaN);

{{1}}

答案 3 :(得分:14)

这可能不是问题的直接答案。 但是如果你想检查一下是否等于Double.NaN,你应该使用它:

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

这将返回true

答案 4 :(得分:6)

javadoc for Double.NaN说明了一切:

  

保持类型double的非数字(NaN)值的常量。它等同于Double.longBitsToDouble(0x7ff8000000000000L)返回的值。

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

public static final double NaN = 0.0d / 0.0;

您描述的特殊行为已硬连接到JVM中。

答案 5 :(得分:3)

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

答案 6 :(得分:3)

,双精度数字的The IEEE standard for floating point arithmetic

  

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

enter image description here 其中,

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

特别是,你无法测试

if (x == Double.NaN) 

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

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

答案 7 :(得分:2)

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

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

答案 8 :(得分:0)

根据这个link,它有各种各样的情况,很难记住。这就是我记忆和区分它们的方式。 NaN表示&#34;数学上未定义&#34;例如:&#34; 0除以0的结果未定义&#34;因为它是未定义的,所以&#34;与undefined相关的比较当然是未定义的&#34;。此外,它更像是数学前提。另一方面,正和负无限都是预定义的和确定的,例如&#34;正或负无限大是数学上明确定义的#34;。

答案 9 :(得分:0)

如果你有变量

Double a = Double.NaN

使用

String.valueOf(Double.NaN) == a.toString()