Java 11中BigDecimal转double计算丢失精度问题求助
问题描述
使用Java 11与IntelliJ IDEA开发,从外部系统获取字符串格式的价格数据,当前通过以下代码提取售价:
BigDecimal sellingPrice = BigDecimal.valueOf(Double.parseDouble(somesalesprice));
调试显示sellingPrice的值为"4.350000000",但执行以下代码转换时:
long roundedSellingPrice = (long) (sellingPrice.doubleValue() * 100);
结果为"434",莫名丢失1分。在500+条数据中约有40条出现该问题,且均为少1分,无法找到这些数据的共性,求问题原因。
问题原因与解决方案
核心原因:浮点数精度丢失
- Double类型的固有缺陷:
Double.parseDouble(somesalesprice)会把字符串转成double类型,但double是二进制浮点数,无法精确表示所有十进制小数(比如4.35)。实际存储的是一个接近4.35但略小于它的值(比如4.3499999999999996)。 - BigDecimal.valueOf(double)的局限性:你用
BigDecimal.valueOf(double)把这个不精确的double转成BigDecimal,虽然调试显示为"4.350000000",但这只是BigDecimal的格式化显示,底层实际存储的还是那个略小的近似值。 - 强制类型转换的截断:当调用
sellingPrice.doubleValue()时,又回到了那个略小于4.35的double值,乘以100后得到的是434.99999999999994,强制转成long时会直接截断小数部分,得到434。
正确解决方案
直接用BigDecimal的字符串构造方法,跳过double转换的步骤,从根源避免精度问题:
// 直接用字符串构造BigDecimal,保留精确的十进制值 BigDecimal sellingPrice = new BigDecimal(somesalesprice); // 使用BigDecimal的精确运算来转成分 long roundedSellingPrice = sellingPrice.multiply(new BigDecimal("100")).longValue();
或者结合缩放规则做更严谨的处理:
long roundedSellingPrice = sellingPrice.setScale(2, RoundingMode.HALF_UP) .multiply(new BigDecimal(100)) .longValue();
内容的提问来源于stack exchange,提问作者JustLudo
相关产品推荐
相关产品推荐

