如何理解Java中double这种奇怪的行为?

zho*_*udu 0 java floating-point double

我试图更深入地理解浮点数。我知道二进制(以 2 为基数)浮点数无法准确表示某些十进制数。但我对 Java 中 double 的这种奇怪行为感到困惑(在 Java 中,double 是一种二进制浮点数数据类型)。

我写了这段Java代码:

public void myTestMethod() {
    double num;
    double factor;
    double compared;
    double result1;
    double result2;
    String output;

    num = 0.3;
    factor = 10;
    compared = 3;

    //num * 10
    result1 = num * factor;

    //add 10 num, which is mathematically equal to num * 10
    result2 = num + num + num + num + num + num + num + num + num + num;

    output = "num: " + num + "\n";
    output = output + "result1: " + result1 + "\n";
    output = output + "result2: " + result2 + "\n";

    if (result1 == compared) {
        output = output + "result1 == compared\n";
    } else {
        output = output + "result1 != compared\n";
    }

    if (result2 == compared) {
        output = output + "result2 == compared\n";
    } else {
        output = output + "result2 != compared\n";
    }

    System.out.print(output);
}
Run Code Online (Sandbox Code Playgroud)

运行此方法会产生以下输出:

num: 0.3
result1: 3.0
result2: 2.9999999999999996
result1 == compared
result2 != compared
Run Code Online (Sandbox Code Playgroud)

据我所知,“factor”的值正好是10,“compared”的值正好是3,因为这些整数可以用double精确表示。但也许“num”的值与 0.3 有点不同。

现在我想知道:

  1. “num”的值是 0.3(正好)吗?

  2. 如果“num”的值为0.3,那么,为什么“result2 == Comparison”为假?

  3. 如果“num”的值不是0.3,那么,为什么它的String输出是“0.3”?据我所知,二进制浮点数总是可以精确地用十进制数表示。因此,如果“num”的值不是 0.3,则其字符串输出不应为“0.3”,而应类似于“0.300000000001”。

  4. 如果“num”的值不是0.3,那么为什么“result1 == Comparison”为真?

  5. 如果“num”的值不是0.3,那么它是什么呢?

Eri*_*hil 8

\n
    \n
  1. “num”的值是 0.3(正好)吗?
  2. \n
\n
\n

不,它是 0.299999999999999988897769753748434595763683319091796875。

\n
\n
    \n
  1. 如果“num”的值为0.3,那么,为什么“result2 == Comparison”为假?
  2. \n
\n
\n

前提是假的;的值num不是0.3。此外,result2使用九次加法计算。在每次加法中,都有一个舍入步骤。这些四舍五入相加的结果是 2.999999999999999555910790149937383830547332763671875。

\n
\n
    \n
  1. 如果“num”的值不是0.3,那么,为什么它的String输出是“0.3”?据我所知,二进制浮点数总是可以精确地用十进制数表示。因此,如果“num”的值不是 0.3,则其字符串输出不应为“0.3”,而应类似于“0.300000000001”。
  2. \n
\n
\n

Java 规范规定 a 的默认格式double是打印足够的十进制数字来唯一区分该数字。double具体来说,它转换为具有最少位数的十进制数字,具有将十进制数字转换回类型会产生原始值的属性。

\n

将 0.3 转换为double最接近的可表示值 0.299999999999999988897769753748434595763683319091796875,因此,在打印 0.299999999999999988897769753748434595763683319 时091796875。使用默认格式,Java 生成 \xe2\x80\x9c0.3\xe2\x80\x9d。

\n
\n
    \n
  1. 如果“num”的值不是0.3,那么为什么“result1 == Comparison”为真?
  2. \n
\n
\n

num是 0.299999999999999988897769753748434595763683319091796875。使用实数算术将其乘以 10 将产生 2.99999999999999988897769753748434595763683319091796875,但该数字无法在double. 浮点乘法运算产生可表示的最接近的值double,即 3。

\n
\n
    \n
  1. 如果“num”的值不是0.3,那么它是什么呢?
  2. \n
\n
\n

它是0.299999999999999988897769753748434595763683319091796875。

\n