简体   繁体   English

Java DecimalFormat 舍入问题(一致性问题)

[英]Java DecimalFormat rounding issue ( consistency problem)

I am seeing some strange behavior in trying to round doubles to 2 decimal places我在尝试将双精度数舍入到小数点后 2 位时看到一些奇怪的行为

Below is the code下面是代码

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

This outputs这输出

100.84
1,440.85

I was expecting 100.85 for the first value.我期望第一个值是 100.85。

As I was looking into it further, I found the following当我进一步研究它时,我发现了以下内容

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

I am thinking it must have something to do with the precision as the switch from.84 to.85 occurred around 255( 2^8 -1).我认为它必须与精度有关,因为从.84 到.85 的切换发生在 255(2^8 -1)左右。 But, I am not calculating this value( at least not in this sample code).但是,我没有计算这个值(至少在这个示例代码中没有)。

Can anyone shed some light on why this is happening?任何人都可以阐明为什么会这样吗?

Thank you谢谢

The issue here is due to the fact that neither of these double values are exactly equal to the decimal representation used in the Java code;这里的问题是由于这些双精度值都不完全等于 Java 代码中使用的十进制表示; they're instead a close floating point value.相反,它们是一个接近的浮点值。

The following is one way to print their exact values:以下是打印其确切值的一种方法:

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

This outputs:这输出:

100.844999999999998863131622783839702606201171875
1440.845000000000027284841053187847137451171875

100.8449... rounds down to 100.84 , since it's closest to 100.84 . 100.8449...向下舍入为100.84 ,因为它最接近100.84 1440.8450... rounds up to 100.85 , since it's closest to 100.85 . 1440.8450...四舍五入到100.85 ,因为它最接近100.85

In neither of these cases does the half-even logic apply, since neither number is exactly halfway between two potential rounding targets.在这两种情况下,半偶数逻辑都不适用,因为这两个数字都不是两个潜在舍入目标之间的中间值。

By contrast, if you use a number format that can exactly represent these values (such as BigDecimal ), you'll see the expected rounding:相比之下,如果您使用可以准确表示这些值的数字格式(例如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));

Output: Output:

100.84
1,440.84

When using HALF_EVEN , it rounds towards the "nearest neighbor" unless both neighbors are equidistant.使用HALF_EVEN时,它会向“最近的邻居”四舍五入,除非两个邻居是等距的。 If they are equidistant, it rounds towards the even neighbor to the left...如果它们是等距的,它会向左边的偶数邻居四舍五入......

In you case, 100.845 the last digit 5 is equidistant so it rounds to the nearest even neighbor to the left 4 .在您的情况下, 100.845最后一位数字5是等距的,因此它舍入到左侧最近的偶数邻居4

Here, you are using double which, in memory, can be sligtly off with the value.在这里,您使用的是double精度,在 memory 中,可以使用该值稍微关闭。 To make sure the numbers that you are rouding are not equidistand, add the precision error which is + 1e-6 for your double .为确保您正在路由的数字不是等距的,请为您的double添加精度误差,即+ 1e-6

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM