仅使用Java 8进行NumberFormat舍入问题 [英] NumberFormat rounding issue with Java 8 only
问题描述
有人可以向我解释为什么以下代码:
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屋!