在Java中,NaN是什么意思?

Dav*_*vid 98 java nan

我有一个程序试图缩小double到所需的数字.我得到的输出是NaN.

NaNJava 中的含义是什么?

Ken*_*ker 144

摘自本页:

"NaN"代表"不是数字".如果浮点运算有一些输入参数导致操作产生一些未定义的结果,则会产生"Nan".例如,0.0除以0.0是算术上未定义的.取负数的平方根也是不确定的.

  • 此外,"NaN"具有作为唯一"数字"的有趣属性,在比较时它与自身不同.因此,如果数字"x"是"NaN",则常见的(在许多语言中唯一的)测试如下:`boolean isNaN(x){return x!= x;}` (37认同)
  • 另外,NaN由IEEE标准的浮点运算(IEEE 754)非常明确地定义,Java盲目地遵循.阅读标准会让你看到很多东西,零的多重值就是其中之一. (16认同)
  • @RafaelT我会说它在非复杂算术中是未定义的.无法在Java中为float或double分配复数.Python是动态类型的,因此在这种情况下可能只返回一个复数. (4认同)
  • 答案中的链接已经死了? (3认同)
  • ......"取负数的平方根是未定义的(在算术中)"......不是!它实际上是`i`和像python这样的语言处理得很好......在`java`中可能不是这样 (2认同)

pok*_*oke 18

NaN表示"非数字",基本上是IEE 754浮点标准中特殊浮点值的表示.NaN通常表示该值是无法用有效浮点数表示的值.

当转换的值是其他值时,转换将导致此值,例如,在转换不表示数字的字符串时.


sep*_*p2k 12

NaN表示"非数字",是浮点数的未定义运算的结果,例如将零除以零.(请注意,虽然在数学中通常不会将非零数除以零,但它不会导致NaN,但会产生正或负无穷大).


Cir*_*四事件 7

最小的可运行示例

您必须知道的第一件事是 NaN 的概念是直接在 CPU 硬件上实现的。

所有主要的现代 CPU 似乎都遵循IEEE 754,它指定了浮点格式,而 NaN 只是特殊的浮点值,是该标准的一部分。

因此,这个概念在任何语言中都非常相似,包括直接向 CPU 发出浮点代码的 Java。

在继续之前,您可能需要先阅读我写的以下答案:

现在进行一些 Java 操作。大多数不在核心语言中的感兴趣的函数都存在于其中java.lang.Float

南爪哇

import java.lang.Float;
import java.lang.Math;

public class Nan {
    public static void main(String[] args) {
        // Generate some NaNs.
        float nan            = Float.NaN;
        float zero_div_zero  = 0.0f / 0.0f;
        float sqrt_negative  = (float)Math.sqrt(-1.0);
        float log_negative   = (float)Math.log(-1.0);
        float inf_minus_inf  = Float.POSITIVE_INFINITY - Float.POSITIVE_INFINITY;
        float inf_times_zero = Float.POSITIVE_INFINITY * 0.0f;
        float quiet_nan1     = Float.intBitsToFloat(0x7fc00001);
        float quiet_nan2     = Float.intBitsToFloat(0x7fc00002);
        float signaling_nan1 = Float.intBitsToFloat(0x7fa00001);
        float signaling_nan2 = Float.intBitsToFloat(0x7fa00002);
        float nan_minus      = -nan;

        // Generate some infinities.
        float positive_inf   = Float.POSITIVE_INFINITY;
        float negative_inf   = Float.NEGATIVE_INFINITY;
        float one_div_zero   = 1.0f / 0.0f;
        float log_zero       = (float)Math.log(0.0);

        // Double check that they are actually NaNs.
        assert  Float.isNaN(nan);
        assert  Float.isNaN(zero_div_zero);
        assert  Float.isNaN(sqrt_negative);
        assert  Float.isNaN(inf_minus_inf);
        assert  Float.isNaN(inf_times_zero);
        assert  Float.isNaN(quiet_nan1);
        assert  Float.isNaN(quiet_nan2);
        assert  Float.isNaN(signaling_nan1);
        assert  Float.isNaN(signaling_nan2);
        assert  Float.isNaN(nan_minus);
        assert  Float.isNaN(log_negative);

        // Double check that they are infinities.
        assert  Float.isInfinite(positive_inf);
        assert  Float.isInfinite(negative_inf);
        assert !Float.isNaN(positive_inf);
        assert !Float.isNaN(negative_inf);
        assert one_div_zero == positive_inf;
        assert log_zero == negative_inf;
            // Double check infinities.

        // See what they look like.
        System.out.printf("nan            0x%08x %f\n", Float.floatToRawIntBits(nan           ), nan           );
        System.out.printf("zero_div_zero  0x%08x %f\n", Float.floatToRawIntBits(zero_div_zero ), zero_div_zero );
        System.out.printf("sqrt_negative  0x%08x %f\n", Float.floatToRawIntBits(sqrt_negative ), sqrt_negative );
        System.out.printf("log_negative   0x%08x %f\n", Float.floatToRawIntBits(log_negative  ), log_negative  );
        System.out.printf("inf_minus_inf  0x%08x %f\n", Float.floatToRawIntBits(inf_minus_inf ), inf_minus_inf );
        System.out.printf("inf_times_zero 0x%08x %f\n", Float.floatToRawIntBits(inf_times_zero), inf_times_zero);
        System.out.printf("quiet_nan1     0x%08x %f\n", Float.floatToRawIntBits(quiet_nan1    ), quiet_nan1    );
        System.out.printf("quiet_nan2     0x%08x %f\n", Float.floatToRawIntBits(quiet_nan2    ), quiet_nan2    );
        System.out.printf("signaling_nan1 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan1), signaling_nan1);
        System.out.printf("signaling_nan2 0x%08x %f\n", Float.floatToRawIntBits(signaling_nan2), signaling_nan2);
        System.out.printf("nan_minus      0x%08x %f\n", Float.floatToRawIntBits(nan_minus     ), nan_minus     );
        System.out.printf("positive_inf   0x%08x %f\n", Float.floatToRawIntBits(positive_inf  ), positive_inf  );
        System.out.printf("negative_inf   0x%08x %f\n", Float.floatToRawIntBits(negative_inf  ), negative_inf  );
        System.out.printf("one_div_zero   0x%08x %f\n", Float.floatToRawIntBits(one_div_zero  ), one_div_zero  );
        System.out.printf("log_zero       0x%08x %f\n", Float.floatToRawIntBits(log_zero      ), log_zero      );

        // NaN comparisons always fail.
        // Therefore, all tests that we will do afterwards will be just isNaN.
        assert !(1.0f < nan);
        assert !(1.0f == nan);
        assert !(1.0f > nan);
        assert !(nan == nan);

        // NaN propagate through most operations.
        assert Float.isNaN(nan + 1.0f);
        assert Float.isNaN(1.0f + nan);
        assert Float.isNaN(nan + nan);
        assert Float.isNaN(nan / 1.0f);
        assert Float.isNaN(1.0f / nan);
        assert Float.isNaN((float)Math.sqrt((double)nan));
    }
}
Run Code Online (Sandbox Code Playgroud)

GitHub 上游.

运行:

javac Nan.java && java -ea Nan
Run Code Online (Sandbox Code Playgroud)

输出:

nan            0x7fc00000 NaN
zero_div_zero  0x7fc00000 NaN
sqrt_negative  0xffc00000 NaN
log_negative   0xffc00000 NaN
inf_minus_inf  0x7fc00000 NaN
inf_times_zero 0x7fc00000 NaN
quiet_nan1     0x7fc00001 NaN
quiet_nan2     0x7fc00002 NaN
signaling_nan1 0x7fa00001 NaN
signaling_nan2 0x7fa00002 NaN
nan_minus      0xffc00000 NaN
positive_inf   0x7f800000 Infinity
negative_inf   0xff800000 -Infinity
one_div_zero   0x7f800000 Infinity
log_zero       0xff800000 -Infinity
Run Code Online (Sandbox Code Playgroud)

所以从中我们学到了一些东西:

  • 没有任何合理结果的奇怪浮动操作给 NaN:

    • 0.0f / 0.0f
    • sqrt(-1.0f)
    • log(-1.0f)

    生成一个NaN.

    在 C 中,实际上可以请求在此类操作上引发信号以feenableexcept检测它们,但我认为它没有在 Java 中公开:为什么整数除以零 1/0 给出错误但浮点数为 1/0.0返回“Inf”?

  • 然而,在正负无穷大极限上的奇怪运算确实给出了 +- 无穷大而不是 NaN

    • 1.0f / 0.0f
    • log(0.0f)

    0.0 几乎属于这一类,但问题可能在于它可以达到正无穷大或负无穷大,因此它被保留为 NaN。

  • 如果 NaN 是浮点运算的输入,则输出也趋向于 NaN

  • NaN 0x7fc00000, 0x7fc00001,有几个可能的值0x7fc00002,尽管 x86_64 似乎只生成0x7fc00000.

  • NaN 和无穷大具有相似的二进制表示。

    让我们分解其中的一些:

    nan          = 0x7fc00000 = 0 11111111 10000000000000000000000
    positive_inf = 0x7f800000 = 0 11111111 00000000000000000000000
    negative_inf = 0xff800000 = 1 11111111 00000000000000000000000
                                | |        |
                                | |        mantissa
                                | exponent
                                |
                                sign
    
    Run Code Online (Sandbox Code Playgroud)

    由此我们确认 IEEE754 规定的内容:

    • NaN 和无穷大都有指数 == 255(所有的)
    • 无穷大的尾数 == 0。因此只有两个可能的无穷大:+ 和 -,由符号位区分
    • NaN 有尾数 != 0。因此有几种可能性,除了尾数 == 0 是无穷大
  • NaN 可以是正数或负数(最高位),尽管这对正常操作没有影响

在 Ubuntu 18.10 amd64、OpenJDK 1.8.0_191 中测试。


Mik*_*els 5

NaN意思是"不是数字".它是一个特殊的浮点值,表示操作的结果未定义或不能表示为实数.

有关此值的更多说明,请参见此处.


小智 5

NaN代表Not a Number.它用于表示数学上未定义的任何值.比如将0.0除以0.0.您可以在此处查看更多信息:https://web.archive.org/web/20120819091816/http : //www.concentric.net/~ttwang/tech/javafloat.htm

如果您需要更多帮助,请在此处发布您的计划