仅使用Java 8进行NumberFormat舍入问题 [英] NumberFormat rounding issue with Java 8 only

查看:74
本文介绍了仅使用Java 8进行NumberFormat舍入问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释为什么以下代码:

Can somebody explain to me why the following code:

public class Test {
    public static void main(String... args) {
        round(6.2088, 3);
        round(6.2089, 3);
    }

    private static void round(Double num, int numDecimal) {
        System.out.println("BigDecimal: " + new BigDecimal(num).toString());

        // Use Locale.ENGLISH for '.' as decimal separator
        NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
        nf.setGroupingUsed(false);
        nf.setMaximumFractionDigits(numDecimal);
        nf.setRoundingMode(RoundingMode.HALF_UP);

        if(Math.abs(num) - Math.abs(num.intValue()) != 0){
            nf.setMinimumFractionDigits(numDecimal);
        }

        System.out.println("Formatted: " + nf.format(num));
    }
}

给出以下输出?

[me@localhost trunk]$ java Test
BigDecimal: 6.208800000000000096633812063373625278472900390625
Formatted: 6.209
BigDecimal: 6.208899999999999863575794734060764312744140625
Formatted: 6.208

如果您没有看到它:6.2089四舍五入为3位数给出输出6.208而6.2088给出6.209作为输出。少即是多了?

In case you don't see it: "6.2089" rounded to 3 digits gives the output "6.208" while "6.2088" gives "6.209" as output. Less is more?

使用Java 5,6或7时结果很好但是这个Java 8给了我这个奇怪的输出。
Java版本:

The results were good when using Java 5, 6 or 7 but this Java 8 gives me this strange output. Java version:

[me@localhost trunk]$ java -version
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) Server VM (build 25.5-b02, mixed mode)

编辑:这是Java 7的输出:

this is Java 7's output:

[me@localhost trunk]$ java Test
BigDecimal: 6.208800000000000096633812063373625278472900390625
Formatted: 6.209
BigDecimal: 6.208899999999999863575794734060764312744140625
Formatted: 6.209

Java 7版本:

[me@localhost trunk]$ java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) Server VM (build 24.51-b03, mixed mode)


推荐答案

我可以追踪这个问题类 java.text.DigitList 第522行。

I could track down this issue to class java.text.DigitList line 522.

情况是它认为d ecimal数字 6.0289 已经四舍五入(与同等的 BigDecimal 表示相比,这是正确的6.208899 ... )并决定不再向上舍入。问题是这个决定只有在四舍五入产生的数字是 5 的情况下才有意义,而不是当它大于 5 。请注意 HALF_DOWN 的代码如何正确区分 digit =='5'数字> ;'5' case。

The situation is that it thinks the decimal digits 6.0289 are already rounded (which is correct when comparing to the equivalent BigDecimal representation 6.208899…) and decides to not round up again. The problem is that this decision makes sense only in the case that the digit resulting from rounding up is 5, not when it is bigger than 5. Note how the code for HALF_DOWN correctly differentiates between the digit=='5' and digit>'5' case.

这是一个错误,显然是一个奇怪的错误,因为代码做了类似的权利(只是为了另一个方向)正好在破碎的方向之下。

This is a bug, obviously, and a strange one given the fact that the code for doing similar right (just for the other direction) is right below the broken one.

        case HALF_UP:
            if (digits[maximumDigits] >= '5') {
                // We should not round up if the rounding digits position is
                // exactly the last index and if digits were already rounded.
                if ((maximumDigits == (count - 1)) &&
                    (alreadyRounded))
                    return false;

                // Value was exactly at or was above tie. We must round up.
                return true;
            }
            break;
        case HALF_DOWN:
            if (digits[maximumDigits] > '5') {
                return true;
            } else if (digits[maximumDigits] == '5' ) {
                if (maximumDigits == (count - 1)) {
                    // The rounding position is exactly the last index.
                    if (allDecimalDigits || alreadyRounded)
                        /* FloatingDecimal rounded up (value was below tie),
                         * or provided the exact list of digits (value was
                         * an exact tie). We should not round up, following
                         * the HALF_DOWN rounding rule.
                         */
                        return false;
                    else
                        // Value was above the tie, we must round up.
                        return true;
                }

                // We must round up if it gives a non null digit after '5'.
                for (int i=maximumDigits+1; i<count; ++i) {
                    if (digits[i] != '0') {
                        return true;
                    }
                }
            }
            break;

其他数字不会发生这种情况的原因是 6.2088 不是四舍五入的结果(再次,与 BigDecimal 输出相比 6.208800 ... )。所以在这种情况下,它会向上舍入。

The reason why this doesn’t happen to the other number is that 6.2088 is not the result of rounding up (again, compare to the BigDecimal output 6.208800…). So in this case it will round up.

这篇关于仅使用Java 8进行NumberFormat舍入问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆