如何截断双倍到N位小数?

时间:2015-08-01 14:28:13

标签: java rounding bigdecimal

我想将我的double值舍入到N个小数位(比如说一个),实际上只是忽略了后面的所有数字:

0.123 #=> 0.1
0.19  #=> 0.1
0.2   #=> 0.2

此问题已多次出现,例如herehere。建议的方法是使用BigDecimal然后对其进行缩放,特别是为了避免昂贵的转换为字符串和返回。我需要的舍入模式显然是RoundingMode.DOWN

所以方法是这样的:

static double truncate(double value, int places) {
    return new BigDecimal(value)
        .setScale(places, RoundingMode.DOWN)
        .doubleValue();
}

但是,由于精度的降低,它会返回一些意想不到的结果:

truncate(0.2, 1) #=> 0.2
truncate(0.3, 1) #=> 0.2
truncate(0.4, 1) #=> 0.4

truncate(0.2, 3) #=> 0.2
truncate(0.3, 3) #=> 0.299
truncate(0.4, 3) #=> 0.4

这引出了两个问题:

  1. 它应该如何适用于0.3?为什么在这种情况下会失去精确度?它没有打败BigDecimal的全部目的吗?

  2. 如何正确截断我的值?

  3. 感谢。

3 个答案:

答案 0 :(得分:4)

“特别要避免昂贵的转换为String并返回” - 这正是避免精度损失的原因。你不能免费获得任意精度。

如果您需要任意精确度,则不应使用double,而应使用:

static String truncate(String value, int places) {
return new BigDecimal(value)
    .setScale(places, RoundingMode.DOWN)
    .stripTrailingZeros()
    .toString()
}

答案 1 :(得分:2)

将数字乘以pow(10,n)并将其存储为整数类型&然后再将其除以pow(10,n)

答案 2 :(得分:1)

截断double到N位小数并不是一个有意义的问题,因为简单的十进制数(例如0.3)不能表示为double s。

如果您想了解double 0.3的真实价值

System.out.println(new BigDecimal(0.3));

你会发现它真的是

0.299999999999999988897769753748434595763683319091796875

所以0.299是正确答案。

此问题仅在使用BigDecimal并将答案设为BigDecimalString而非double时才有意义。 @ user1886323的答案显示了如何做到这一点。