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

什么是 NaN 在Java中是什么意思?

有帮助吗?

解决方案

此页摘自:

  

“南”代表“非数字”。 “南”   产生,如果一个浮点   操作具有一些输入参数   使所述操作以产生   一些不确定的结果。例如,   0.0通过0.0除以算术未定义。服用的平方根   负数也是未定义的。

其他提示

NaN 方法 “不是一个数字” 基本上是特殊浮点值的表示 IEE 754 浮点 标准。 通常意味着该值无法用有效的浮点数表示。

当要转换的值是其他值时(例如转换不代表数字的字符串时),转换将产生此值。

NaN装置“不是数”和是未定义的操作对浮点数像例如零被零除的结果。 (注意的是,虽然将一个非零数通过零也通常在数学未定义,它不会导致的NaN但在正或负无穷大)。

NaN装置 “而不是数字。”它是该装置的操作的结果没有定义或不是表示为一个实数特殊浮点值。

请参阅 rel="noreferrer">此值的更多的解释。

的NaN =不是数字。

平均值不是数字。 这是在许多编程语言不可能数值的通用表示。

不是Java的家伙,但在JS和其他语言我用它的“非数”,意思是某些操作导致它变得不是有效的数字。

有字面意思是“不是数字。”我怀疑事情是不对您的转换过程。

检查出在此参考

不是一个有效的浮点值(例如被零除的结果)

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

最小可运行示例

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

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

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

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

现在进行一些 Java 操作。大多数不在核心语言中的感兴趣的功能都位于内部 java.lang.Float.

南.java

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));
    }
}

GitHub 上游.

运行:

javac Nan.java && java -ea Nan

输出:

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

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

  • 没有任何合理结果的奇怪浮点运算给出 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
    

    由此我们确认 IEEE754 的规定:

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top