BigDecimal与float互相转换时无法保留舍入后的值如何解决?
问题本质说明
你观察到的多余数位不是BigDecimal额外追加的,问题根源在float类型的特性:float是二进制浮点类型,无法精确表示绝大多数十进制小数。你将舍入完成的BigDecimal转回float的那一刻,精度就已经丢失了,后续用BigDecimal.valueOf读取float值时,拿到的就是float底层实际存储的不精确近似值,才会出现多余的小数位。
可行解决方案
方案1:全程使用BigDecimal传递数值(最推荐,适合价格类精确计算场景)
直接修改舍入方法的返回值类型为BigDecimal,全程不转float,从根源避免二进制浮点的精度损失:
private BigDecimal roundPrice(float price, int numDigits) { BigDecimal bd = BigDecimal.valueOf(price); return bd.setScale(numDigits, RoundingMode.HALF_UP); }
修改后后续无论是计算还是打印,拿到的都是精确的舍入结果,不会出现多余数位。
方案2:必须保留float返回值时,输出时做格式化处理
如果不能修改方法返回类型,可以在输出环节通过字符串格式化自动过滤无意义的多余数位,不需要提前获取舍入时的小数位数:
// 示例:最多保留9位小数,自动删除末尾无意义的0 System.out.println(new DecimalFormat("#.#########").format(bd));
也可以用字符串替换的方式处理:
String output = String.format("%.9f", bd).replaceAll("0*$", "").replaceAll("\\.$", ""); System.out.println(output);
方案3:需要得到无多余数位的BigDecimal对象
如果后续逻辑需要使用BigDecimal对象,可以调用stripTrailingZeros()方法自动去除末尾的无效数位,不需要提前知道舍入位数:
bd = bd.stripTrailingZeros(); // 如果需要避免输出科学计数法,调用toPlainString() System.out.println(bd.toPlainString());
内容的提问来源于stack exchange,提问作者jeninja
相关产品推荐
相关产品推荐

