gpt4 book ai didi

java - 仅 Java 8 的 NumberFormat 舍入问题

转载 作者:太空狗 更新时间:2023-10-29 22:53:00 25 4
gpt4 key购买 nike

谁能给我解释一下为什么会出现下面的代码:

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”作为输出。少即是多?

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

[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 的输出:

[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 行。

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

这显然是一个错误,而且是一个奇怪的错误,因为执行类似操作的代码(仅针对另一个方向)就在错误代码的正下方。

        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…)。所以在这种情况下它会四舍五入。

关于java - 仅 Java 8 的 NumberFormat 舍入问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24426438/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com