Java中Double类型相除取整数部分异常原因及最优解法
误差产生的原因
这个问题本质是浮点数精度丢失导致的:
- Java中
double类型基于IEEE 754二进制浮点数标准实现,绝大多数十进制小数都无法被精确存储为二进制浮点数,你代码里的18.2和2.6转成Double对象时本身就带有微小的精度误差 - 两个本身有误差的浮点数做除法后误差会进一步累积,最终计算结果不是精确的
7.0,而是接近7的6.99999...这类值,调用intValue()时会直接截断小数部分,所以得到6而非预期的7。
现有DecimalFormat方案的说明
你目前用的DecimalFormat方案能得到正确结果,但算不上最优方案,存在几个明显问题:
- 性能开销过大:
DecimalFormat是重量级格式化类,实例化和格式化操作都有额外开销,单纯为了取整使用属于大材小用 - 规则隐式不透明:不显式指定舍入模式的话,会用默认的
RoundingMode.HALF_EVEN,后续需求调整舍入规则时容易出隐藏问题 - 输出结果为字符串类型,如果后续还要对结果做数值运算,需要额外做类型转换,非常不方便。
更合适的实现方式
根据不同的使用场景,推荐两种更优的方案:
场景1:精度要求不高,追求代码极简
直接用Math.round()对运算结果做四舍五入后取整即可,代码比DecimalFormat轻量很多,输出直接是数值类型:
Double price = new Double("18.2"); Double qte = new Double("2.6"); double res = price / qte; // 输出7,结果为long类型 System.out.println(Math.round(res));
场景2:精度要求极高(比如涉及金额、计量类计算)
完全避免用double/float做数值运算,统一用BigDecimal处理,从根源杜绝精度丢失,还可以显式指定舍入规则,可控性最高:
import java.math.BigDecimal; import java.math.RoundingMode; // 直接用字符串构造BigDecimal,避免中间转double的精度损失 BigDecimal price = new BigDecimal("18.2"); BigDecimal qte = new BigDecimal("2.6"); // 除法时指定保留0位小数,舍入模式用四舍五入(可根据需求更换其他舍入模式) BigDecimal res = price.divide(qte, 0, RoundingMode.HALF_UP); // 输出7,结果为整数类型 System.out.println(res.intValue());
内容的提问来源于stack exchange,提问作者user2178964
相关产品推荐
相关产品推荐

