159

我只是在研究 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意思?

4

10 回答 10

139

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

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

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

于 2012-01-11T13:06:06.800 回答
62

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

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

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

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

于 2012-01-11T14:04:35.377 回答
51

为什么这个逻辑

NaN意味着Not a Number。什么不是数字?任何事物。您可以在一侧拥有任何东西,而在另一侧拥有任何东西,因此无法保证两者是平等的。NaNDouble.longBitsToDouble(0x7ff8000000000000L)和 计算,您可以在以下文档中看到longBitsToDouble

如果参数是范围0x7ff0000000000001Lthrough 0x7fffffffffffffffL或范围 through 中的0xfff0000000000001L任何 值0xffffffffffffffffL,则结果是 a 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

/**
 * 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

如果thisargument都表示Double.NaN,则该equals方法返回true,即使 Double.NaN==Double.NaN具有值false

Double.NaN.equals(Double.NaN);
于 2012-01-11T13:35:15.610 回答
17

这可能不是问题的直接答案。但是,如果您想检查某些内容是否等于,Double.NaN则应使用以下命令:

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

这将返回true

于 2015-10-01T14:08:30.170 回答
6

Double.NaN的javadoc说明了一切:

一个保持类型为非数字 (NaN) 值的常量double。它相当于返回的值Double.longBitsToDouble(0x7ff8000000000000L)

有趣的是,源代码是这样Double定义的NaN

public static final double NaN = 0.0d / 0.0;

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

于 2012-01-11T13:06:17.333 回答
4

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

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

在此处输入图像描述 在哪里,

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

如果E=2047(all Eare 1) 并且F非零,则V=NaN("Not a number")

意思是,

如果所有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"
于 2015-01-30T15:56:31.317 回答
3

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

于 2012-01-11T13:04:10.017 回答
2

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

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

于 2012-01-11T13:07:15.687 回答
0

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

于 2018-02-26T02:32:23.863 回答
0

如果你有变量

Double a = Double.NaN

采用

String.valueOf(Double.NaN) == a.toString()
于 2021-01-30T21:10:08.290 回答