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

Mav*_*ick 154 java floating-point scjp nan ocpjp

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

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

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

false
true
Run Code Online (Sandbox Code Playgroud)

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

Adr*_*tev 138

NaN表示"非数字".

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

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

  • 它不仅仅是Java; 它是浮点标准. (53认同)
  • @nibot:**大部分都是真的**.与符合IEEE的浮点数进行任何比较都会产生"假".因此该标准与Java的不同之处在于IEEE要求`(NAN!= NAN)== false`. (4认同)
  • 打开这个Pandora的盒子 - 你在哪里看到"IEEE要求(NAN!= NAN)== false"? (2认同)

Pet*_*rey 61

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

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

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

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

  • JVM必须调用正确实现它的任何东西.在PC上,CPU可以完成所有工作.在没有此支持的计算机上,JVM必须实现它.(我不知道任何这样的机器) (3认同)

fal*_*lla 48

为什么那么逻辑

NaN手段Not a Number.什么不是数字?任何东西.你可以在一边拥有任何东西,在另一边拥有任何东西,所以没有什么可以保证两者都是平等的.NaN计算方法,Double.longBitsToDouble(0x7ff8000000000000L)您可以在以下文档中看到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;
Run Code Online (Sandbox Code Playgroud)

顺便说一句,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);
}
Run Code Online (Sandbox Code Playgroud)

你可以做的是使用compare/ compareTo:

Double.NaN通过这种方法认为它等于自身并且大于所有其他double值(包括 Double.POSITIVE_INFINITY).

Double.compare(Double.NaN, Double.NaN);
Double.NaN.compareTo(Double.NaN);
Run Code Online (Sandbox Code Playgroud)

或者,equals:

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

Double.NaN.equals(Double.NaN);
Run Code Online (Sandbox Code Playgroud)


JRE*_*REN 14

它可能不是这个问题的直接答案.但是如果你想检查某些东西是否相等,Double.NaN你应该使用这个:

double d = Double.NaN
Double.isNaN(d);
Run Code Online (Sandbox Code Playgroud)

这将返回 true


Boh*_*ian 6

Double.NaNjavadoc说明了一切:

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

有趣的是,Double定义的来源NaN因此:

public static final double NaN = 0.0d / 0.0;
Run Code Online (Sandbox Code Playgroud)

您描述的特殊行为是硬连线到JVM中的.

  • 它是在JVM中硬接线,还是像Peter提到的那样由CPU实现? (5认同)