Java BigDecimal: 四舍五入至最接近的整数值

108

我需要以下结果

100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

.round() 还是 .setScale()? 我该如何选择?

7个回答

190

您可以使用 setScale() 将小数位数减少到零。假设 value 保存要舍入的值:

BigDecimal scaled = value.setScale(0, RoundingMode.HALF_UP);
System.out.println(value + " -> " + scaled);

使用round()函数需要指定要保留的小数位数,所以它比较麻烦。在你的例子中,这个数字是3,但并非对所有值都适用:

BigDecimal rounded = value.round(new MathContext(3, RoundingMode.HALF_UP));
System.out.println(value + " -> " + rounded);

(请注意,BigDecimal 对象是不可变的;setScaleround 方法都会返回一个新对象。)


1
它不起作用:100.12 : 100.12,100.44 : 100.44,100.50 : 100.5,100.75 : 100.75 - Boris Pavlović
3
不,设置位数会返回一个新的 BigDecimal,它与原来的不同。例如:BigDecimal bd1 = new BigDecimal(100.12); BigDecimal bd2 = bd1.setScale(0, RoundingMode.HALF_UP); System.out.println(bd1.equals(bd2)); 输出 false。 - Daniel Fath
6
@Daniel:我在我的回答中发布的代码片段中已经暗示了这一点。我现在已经明确表述了。 - Grodriguez
RoundingMode what is that? It's BigDecimal - trilogy
https://docs.oracle.com/javase/9/docs/api/java/math/BigDecimal.html#setScale-int-java.math.RoundingMode- - Grodriguez

16
如果我按照Grodriguez的回答走。
System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

这是输出结果

100.23 -> 100
100.77 -> 101

这还不是我想要的,所以我最终做了这个...

System.out.println("" + value);
value = value.setScale(0, BigDecimal.ROUND_HALF_UP);
value = value.setScale(2, BigDecimal.ROUND_HALF_UP);
System.out.println("" + value);

这就是我得到的结果

100.23 -> 100.00
100.77 -> 101.00

这暂时解决了我的问题.. : ) 谢谢大家。


9
我对“第一个结果‘不太是我想要的...’”这句话很好奇。如果你真的关心输出格式,你可以使用DecimalFormat(如new DecimalFormat("###.00"))来将BigDecimal转换为字符串。它会使得从@Grodriquez和你创建的两个值的结果都为“101.00”。 - joel.neely
4
你第二次进行四舍五入其实是不必要的,因为你已经知道自己有一个整数了,所以我会使用BigDecimal.ROUND_UNNECESSARY,这样更加清晰明了。 - kosmoplan

5

这里有一个非常复杂的解决方案,但它是可行的:

public static BigDecimal roundBigDecimal(final BigDecimal input){
    return input.round(
        new MathContext(
            input.toBigInteger().toString().length(),
            RoundingMode.HALF_UP
        )
    );
}

测试代码:

List<BigDecimal> bigDecimals =
    Arrays.asList(new BigDecimal("100.12"),
        new BigDecimal("100.44"),
        new BigDecimal("100.50"),
        new BigDecimal("100.75"));
for(final BigDecimal bd : bigDecimals){
    System.out.println(roundBigDecimal(bd).toPlainString());
}

输出:

100
100
101
101


不是为了支持这个解决方案或其他任何东西,但使用对数会使input.toBigInteger().toString().length()部分更加高效,例如round_up(log(input)) + (1 if input is a power of ten, else 0) - Addison
BigDecimal 看起来像是一堆热气腾腾的垃圾。 - MarkHu

3

0

我认为你不能在一个命令中这样四舍五入。尝试一下

    ArrayList<BigDecimal> list = new ArrayList<BigDecimal>();
    list.add(new BigDecimal("100.12"));
    list.add(new BigDecimal("100.44"));
    list.add(new BigDecimal("100.50"));
    list.add(new BigDecimal("100.75"));

    for (BigDecimal bd : list){
        System.out.println(bd+" -> "+bd.setScale(0,RoundingMode.HALF_UP).setScale(2));
    }

Output:
100.12 -> 100.00
100.44 -> 100.00
100.50 -> 101.00
100.75 -> 101.00

我测试了你提供的其他例子,它返回了期望的值,但我不能保证其正确性。


0
如果你对 .round().setScale() 都不太熟悉,那么你可以使用这段代码来实现任意精度的整数舍入(例如以10、25、50、100等为步长进行舍入)。
用法:
int distance = roundN(_distance, 5);

声明:

public static BigDecimal roundN(BigDecimal num, int precision){
    BigDecimal remainder = num.remainder(BigDecimal.valueOf(precision));
    System.out.println("remainder: " + remainder);

    if (remainder.compareTo(BigDecimal.valueOf((precision / 2))) < 0 ){
        System.out.println("round down");
        return num.subtract(remainder);
    } else {
        BigDecimal neg = remainder.negate().add(BigDecimal.valueOf(precision));
        System.out.println("round up");
        return num.add(neg);
    }
}

在需要的情况下,可以将尾随的.00添加到结果中。


-2

你想要什么

round(new MathContext(0));  // or perhaps another math context with rounding mode HALF_UP

3
这个操作没有任何效果。根据round函数的文档说明:“当精度设置为0时,不进行四舍五入。” - Grodriguez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接