【问题标题】:Java DecimalFormat rounding issue ( consistency problem)Java DecimalFormat 舍入问题(一致性问题)
【发布时间】:2021-04-27 02:20:09
【问题描述】:

我在尝试将双精度数舍入到小数点后 2 位时看到一些奇怪的行为

下面是代码

        DecimalFormat df = new DecimalFormat();
        df.setMaximumFractionDigits(2);
        df.setRoundingMode(RoundingMode.HALF_EVEN);
        
        double f1 = 100.845;
                
        double f2 = 1440.845;
        
        System.out.println( df.format(f1));
        System.out.println( df.format(f2));

这个输出

100.84
1,440.85

我期望第一个值是 100.85。

当我进一步研究它时,我发现了以下内容

101.845 --> 100.84
102.845 --> 102.84
103.845 --> 103.84
.
.
255.845 --> 255.84
**256.845 --> 256.85**
257.845 --> 256.85
.
.

我认为这一定与精度有关,因为从 0.84 到 .85 的切换发生在 255(2^8 -1)左右。但是,我没有计算这个值(至少在这个示例代码中没有)。

谁能解释为什么会这样?

谢谢

【问题讨论】:

    标签: java decimalformat rounding-error


    【解决方案1】:

    这里的问题是由于这些双精度值都不完全等于 Java 代码中使用的十进制表示;它们是一个接近的浮点值。

    以下是打印它们的确切值的一种方法:

    System.out.println(new BigDecimal(100.845));
    System.out.println(new BigDecimal(1440.845));
    

    这个输出:

    100.844999999999998863131622783839702606201171875
    1440.845000000000027284841053187847137451171875
    

    100.8449... 向下舍入为100.84,因为它最接近100.841440.8450... 向上舍入到 100.85,因为它最接近 100.85

    在这两种情况下,半偶数逻辑都不适用,因为这两个数字都不是两个潜在舍入目标的中间值。

    相比之下,如果您使用可以准确表示这些值的数字格式(例如BigDecimal),您将看到预期的四舍五入:

    DecimalFormat df = new DecimalFormat();
    df.setMaximumFractionDigits(2);
    df.setRoundingMode(RoundingMode.HALF_EVEN);
    
    BigDecimal d1 = new BigDecimal("100.845");
    BigDecimal d2 = new BigDecimal("1440.845");
    
    System.out.println( df.format(d1));
    System.out.println( df.format(d2));
    

    输出:

    100.84
    1,440.84
    

    【讨论】:

      【解决方案2】:

      当使用HALF_EVEN 时,它会向“最近的邻居”四舍五入,除非两个邻居距离相等。如果它们是等距的,它会向左边的偶数邻居四舍五入......

      在您的情况下,100.845 最后一位数字 5 是等距的,因此它舍入到左侧最近的偶数邻居 4

      在这里,您使用的是double,在内存中,它的值可以稍微关闭。为确保您正在路由的数字不是等距的,请为您的 double 添加精度误差 + 1e-6

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-08-23
        • 1970-01-01
        • 1970-01-01
        • 2013-04-12
        • 2011-04-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多