为什么这个DecimalFormat
没有按预期使用RoundingMode.HALF_UP
进行舍入,以及应该采取什么措施来获得预期的输出?是否可以使用DecimalFormat
完成?
DecimalFormat df = new DecimalFormat("0.0");
df.setRoundingMode(RoundingMode.HALF_UP);
df.format(0.05); // expecting 0.1, getting 0.1
df.format(0.15); // expecting 0.2, getting 0.1 << unexpected
df.format(0.06); // expecting 0.1, getting 0.0 << unexpected
我已经看到了来自this question的答案,特别是this answer,但它似乎只有在舍入到整数时才有效。
我的JDK是8.0.110而我的JRE是8.0.730.2
答案 0 :(得分:4)
(以下使用Java 8回答。)
您看到的问题来自于指定&#34; 0.15&#34;或&#34; 0.05&#34;在代码中,当表示为double时,略小于0.15。看看这个
DecimalFormat df = new DecimalFormat("#.#");
df.setRoundingMode(RoundingMode.HALF_UP);
BigDecimal bd = new BigDecimal(0.15);
System.out.println("bd=" + bd);
System.out.println(df.format(0.15)); // expecting 0.1, getting 0.1
bd = new BigDecimal(0.05);
System.out.println("bd=" + bd);
System.out.println(df.format(0.05));
bd = new BigDecimal(0.06);
System.out.println("bd=" + bd);
System.out.println(df.format(0.06));
此代码的输出是
bd=0.1499999999999999944488848768742172978818416595458984375
0.1
bd=0.05000000000000000277555756156289135105907917022705078125
0.1
bd=0.059999999999999997779553950749686919152736663818359375
0.1
一个可能的解决方案(如果你绝对需要它以正确的方式进行舍入)是使用BigDecimal.valueOf来创建值。例如
BigDecimal bd = BigDecimal.valueOf(0.15);
System.out.println("bd=" + bd);
System.out.println(df.format(bd)); // expecting 0.1, getting 0.1
bd = BigDecimal.valueOf(0.05);
System.out.println("bd=" + bd);
System.out.println(df.format(bd));
bd = BigDecimal.valueOf(0.06);
System.out.println("bd=" + bd);
System.out.println(df.format(bd));
现在会产生
bd=0.15
0.2
bd=0.05
0.1
bd=0.06
0.1
顺便说一下,正如Scary Wombat指出的那样,掩码设置为0.0而不是#。#将使0.6为0.但我认为这是后来的编辑,然后我开始查看它。使用#。#。
答案 1 :(得分:4)
当你这样做时
df.format(0.15);
实际上有两个舍入操作。显而易见的是df.format
所要求的那个,但是在编译时会发生更早的那个。
十进制值0.15不能表示为double。双打只能表示分母为2的幂的有理数,就像十进制表示法只能代表其分母为10的幂的有理数。当你编写0.15
时,编译器会将其舍入到可以表示为double的最接近的值,并且该值恰好是
0.1499999999999999944488848768742172978818416595458984375
df.format
正确向下舍入。它不完全在0.1和0.2之间,所以HALF_UP
舍入模式并不重要。
至于
df.format(0.06); // expecting 0.1, getting 0.0 << unexpected
如果您正在查看 ,那就是一个错误。看起来它匹配one linked by ScaryWombat,据报道固定在8u40和8u45。使用8u51的Ideone测试显示正确的行为。更新Java应该可以解决问题。
答案 2 :(得分:0)
我认为答案是IEEE Standard for Floating-Point Arithmetic (IEEE 754). Wiki文章在Rounding rules部分有一个很好的例子。您还可以阅读更多关于浮点的9.1 of Introduction to Java部分。 BigDecimal通过将未调用的值存储在BigInteger中来解决大部分这些短缺,精度和比例在整数字段中分开。