为什么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
当我们比较两个看起来相同的东西时,输出是false
? NaN
是什么意思?
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
:
如果参数是
0x7ff0000000000001L
到0x7fffffffffffffffL
范围内的任何值,或者范围是0xfff0000000000001L
到0xffffffffffffffffL
,则结果是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
:
如果
this
和argument
都表示Double.NaN
,那么即使Double.NaN==Double.NaN
的值为false
,equals
方法也会返回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
(全部E
是1
)并且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