Java RoundingMode.HALF_EVEN是bug吗?

Liu*_*hua 4 java

当我用HALF_EVEN模式舍入一个双号时,我发现了一个问题,我不知道它是否是JDK的一个bug?请参阅以下代码:

public static void main(String[] args) {
    RoundingMode mode = RoundingMode.HALF_EVEN;
    for (int i = 10; i < 100; i++) {
        double d = i + 0.55;
        int scale = 1;
        process(d, scale++, mode);

        d = i + 0.555;
        process(d, scale++, mode);

        d = i + 0.5555;
        process(d, scale++, mode);

        d = i + 0.55555;
        process(d, scale++, mode);
        System.out.println("\n");
    }
}

private static void process(double d, int scale, RoundingMode roundingMode) {
    BigDecimal b = new BigDecimal(d).setScale(scale, roundingMode);
    System.out.println(d + " -> " + b);
}
Run Code Online (Sandbox Code Playgroud)

我希望输出:

10.55 -> 10.6
10.555 -> 10.56
10.5555 -> 10.556
10.55555 -> 10.5556


11.55 -> 11.6
11.555 -> 11.56
11.5555 -> 11.556
11.55555 -> 11.5556

.....
Run Code Online (Sandbox Code Playgroud)

但实际上,它输出的数据如下:

10.55 -> 10.6
10.555 -> 10.55
10.5555 -> 10.556
10.55555 -> 10.5556


11.55 -> 11.6
11.555 -> 11.55
11.5555 -> 11.556
11.55555 -> 11.5556
....

30.55 -> 30.6
30.555 -> 30.55
30.5555 -> 30.555
30.55555 -> 30.5556



31.55 -> 31.6
31.555 -> 31.55
31.5555 -> 31.555
31.55555 -> 31.5556



32.55 -> 32.5
32.555 -> 32.55
32.5555 -> 32.556
32.55555 -> 32.5555



33.55 -> 33.5
33.555 -> 33.55
33.5555 -> 33.556
33.55555 -> 33.5555

.........

62.55 -> 62.5
62.555 -> 62.55
62.5555 -> 62.556
62.55555 -> 62.5555



63.55 -> 63.5
63.555 -> 63.55
63.5555 -> 63.556
63.55555 -> 63.5555



64.55 -> 64.5
64.555 -> 64.56
64.5555 -> 64.555
64.55555 -> 64.5555



65.55 -> 65.5
65.555 -> 65.56
65.5555 -> 65.555
65.55555 -> 65.5555



66.55 -> 66.5
66.555 -> 66.56
66.5555 -> 66.555
66.55555 -> 66.5555
Run Code Online (Sandbox Code Playgroud)

JDK 1.7/1.8中有相同的结果

这是JDK的错误吗?

Bat*_*eba 5

遗憾的是,它是生活的一部分,并且由于double类型在内部以2的基数实现.对于科学编程,这是一个非常聪明的事情.但它确实意味着当你想要用10基数来查看或指定它们时,你看到的并不一定是你得到的.

例如,文字10.555实际上是一个略小于此的数字(10.5549999999999997157829056959599256515502929687...)因此,明显的德国舍入实际上将向下舍入这个数字.您的问题包含许多类似案例.

这不是一个错误,但是如果你需要精确的舍入,那么你应该使用一个能够以任意精度表示十进制数的类.

使用BigDecimal是一种选择,但你可怕地滥用它!.通过使用来自double(即new BigDecimal(d))不精确的地方性的构造函数d将仅仅复制到BigDecimal.所以你应该使用String相反或类似方法的构造函数.

最后,请查看http://www.exploringbinary.com/floating-point-converter.输入您的十进制数,并查看转换为浮点时它所采用的值.