我只是在研究 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
意思?
我只是在研究 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
意思?
NaN 的意思是“不是数字”。
上溢运算产生有符号无穷大,下溢运算产生非规格化值或有符号零,而没有数学确定结果的运算产生 NaN。所有以 NaN 作为操作数的数值运算都会产生 NaN 作为结果。如前所述,NaN 是无序的,因此涉及一个或两个 NaN 的数值比较操作会返回
false
,任何!=
涉及 NaN 的比较都会返回true
,包括x!=x
何时x
是 NaN。
根据定义,NaN 不等于包括 NaN 在内的任何数字。这是 IEEE 754 标准的一部分,由 CPU/FPU 实现。这不是 JVM 必须添加任何逻辑来支持的东西。
http://en.wikipedia.org/wiki/NaN
与 NaN 的比较始终返回无序结果,即使与自身进行比较也是如此。... 等式和不等式谓词是无信号的,因此 x = x 返回 false 可用于测试 x 是否为安静的 NaN。
Java 将所有 NaN 视为安静的 NaN。
为什么这个逻辑
NaN
意味着Not a Number
。什么不是数字?任何事物。您可以在一侧拥有任何东西,而在另一侧拥有任何东西,因此无法保证两者是平等的。NaN
用Double.longBitsToDouble(0x7ff8000000000000L)
和 计算,您可以在以下文档中看到longBitsToDouble
:
如果参数是范围
0x7ff0000000000001L
through0x7fffffffffffffffL
或范围 through 中的0xfff0000000000001L
任何 值0xffffffffffffffffL
,则结果是 aNaN
。
此外,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
:
如果
this
和argument
都表示Double.NaN
,则该equals
方法返回true
,即使Double.NaN==Double.NaN
具有值false
。
Double.NaN.equals(Double.NaN);
这可能不是问题的直接答案。但是,如果您想检查某些内容是否等于,Double.NaN
则应使用以下命令:
double d = Double.NaN
Double.isNaN(d);
这将返回true
Double.NaN的javadoc说明了一切:
一个保持类型为非数字 (NaN) 值的常量
double
。它相当于返回的值Double.longBitsToDouble(0x7ff8000000000000L)
。
有趣的是,源代码是这样Double
定义的NaN
:
public static final double NaN = 0.0d / 0.0;
您描述的特殊行为是硬连接到 JVM 中的。
根据双精度数浮点运算的 IEEE 标准,
IEEE 双精度浮点标准表示需要一个 64 位的字,可以表示为从 0 到 63 的编号,从左到右
在哪里,
S: Sign – 1 bit
E: Exponent – 11 bits
F: Fraction – 52 bits
如果
E=2047
(allE
are1
) 并且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"
NaN 是一个特殊值,表示“不是数字”;它是某些无效算术运算的结果,例如sqrt(-1)
, 并且具有(有时令人讨厌的)属性NaN != NaN
.
非数字表示其结果不能用数字表示的操作的结果。最著名的操作是 0/0,其结果未知。
因此,NaN 不等于任何值(包括其他非数字值)。有关更多信息,请查看维基百科页面:http ://en.wikipedia.org/wiki/NaN
根据这个链接,它有各种各样的情况,很难记住。这就是我记忆和区分它们的方式。NaN
表示“数学上未定义”,例如:“0除以0的结果是未定义的”,因为它是未定义的,所以“与未定义相关的比较当然是未定义的”。此外,它更像数学前提。另一方面,正无穷和负无穷都是预定义的和确定的,例如“正无穷大或负无穷大在数学上是很好定义的”。
如果你有变量
Double a = Double.NaN
采用
String.valueOf(Double.NaN) == a.toString()