我只是在研究 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:
如果参数是范围
0x7ff0000000000001Lthrough0x7fffffffffffffffL或范围 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(allEare1) 并且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()