Java除法精度丢失源于整数截断和double二进制表示缺陷;应避免整数除法、用BigDecimal精确计算(字符串构造+指定舍入)、数据库用DECIMAL+getBigDecimal、金额可转整数运算。

Java 除法精度丢失不是代码写错了,而是数据类型本身的限制导致的。核心问题有两个层面:一是整数除法直接截断小数;二是 double 类型用二进制表示十进制小数时天然不精确(比如 0.1 在二进制中是无限循环小数)。处理的关键不是“修”,而是“绕”——选对类型、控好源头、用对方法。
避免整数除法截断:至少一个操作数转浮点
当两个 int 或 long 相除,结果仍是整数,小数部分被直接丢弃:
-
错误写法:
int result = 10 / 3;→ 得到 3 -
正确做法:把其中一个转成 double,让运算升级为浮点运算
double result = 10.0 / 3;或double result = (double) 10 / 3;→ 得到约 3.3333333333333335
规避 double 二进制误差:用 BigDecimal 做真正精确计算
如果需要业务级准确(如金额、计费、计量),不能依赖 double 的近似值。必须从源头杜绝误差:
-
禁止:
new BigDecimal(0.1)—— 此时 0.1 已是 double 的近似值,误差已固化 -
推荐:
new BigDecimal("0.1")或BigDecimal.valueOf(0.1)(后者内部转字符串,更安全) - 除法必须指定标度和舍入模式:
a.divide(b, 2, RoundingMode.HALF_EVEN)(保留两位,银行家舍入)
不指定会抛ArithmeticException(如 1 ÷ 3 无法终止)
数据库与前后端对接:全程保持 BigDecimal 链路
精度丢失常发生在系统边界:
立即学习“Java免费学习笔记(深入)”;
- 数据库字段用 DECIMAL(18,2),不用 FLOAT/DOUBLE
- JDBC 读取时用
rs.getBigDecimal("price"),别用getDouble()再转 - 写入时用
ps.setBigDecimal(1, price) - JSON 序列化启用
WriteBigDecimalAsPlain,防止"1.00"变成1或科学计数法
简单场景可考虑整数替代法
对金额等固定小数位的业务,可统一换算为“分”或“厘”存为 long/int:
- 0.99 元 → 存 99 分(int)
- 所有加减乘除都在整数上进行,完全无精度问题
- 展示时再除以 100.0 并格式化:
String.format("%.2f", cents / 100.0)


















