我想将我的double值舍入到N个小数位(比如说一个),实际上只是忽略了后面的所有数字:
0.123 #=> 0.1
0.19 #=> 0.1
0.2 #=> 0.2
此问题已多次出现,例如here和here。建议的方法是使用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
这引出了两个问题:
它应该如何适用于0.3
?为什么在这种情况下会失去精确度?它没有打败BigDecimal
的全部目的吗?
如何正确截断我的值?
感谢。
答案 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
并将答案设为BigDecimal
或String
而非double
时才有意义。 @ user1886323的答案显示了如何做到这一点。