Java中float/double精度丢失是IEEE 754二进制表示固有局限,金融计算必须用BigDecimal(字符串构造、方法运算、compareTo比较、DECIMAL映射),整数单位换算(如元→分)更轻量可靠,科学计算等允许误差场景需用容差比较。

Java 中 float 和 double 无法避免精度丢失,因为这是 IEEE 754 二进制表示的固有局限——像 0.1、0.05 这类十进制小数在二进制中是无限循环小数,而浮点类型只能截断存储。关键不是“修复”它,而是根据业务需求选对处理方式。
金融/金额类计算必须用 BigDecimal
涉及钱、库存、税率等“1分都不能错”的场景,一律禁用 float/double:
- 构造时用字符串:
new BigDecimal("19.99"),绝不用new BigDecimal(19.99)(后者先失真再封装) - 所有运算调用方法:
.add()、.subtract()、.multiply()、.divide(scale, RoundingMode.HALF_UP) - 比较用
.compareTo(),不用==或.equals()(后者会比 scale) - 数据库字段对应
DECIMAL类型,JDBC 映射保持精度不降级
整数换算单位更轻量也更可靠
适合规则清晰、性能敏感的业务,比如电商价格、计费系统:
- 把“元”转为“分”,全程用
long或int计算:19.99 元 → 存 1999 - 加减乘除无精度损失;显示时再除以 100,并用
DecimalFormat或BigDecimal.divide()控制格式 - 注意除法仍需指定舍入,避免
1999 / 100得到 19(整数除)或 19.990000000000002(double 除)
必须用 double 时要接受近似本质
科学计算、图形渲染、传感器读数等允许误差的场景,重点在于“怎么用”,而非“怎么修”:
立即学习“Java免费学习笔记(深入)”;
- 判断相等改用容差比较:
Math.abs(a - b) ,别写 <code>a == b - 显示输出前格式化:
String.format("%.2f", d)或DecimalFormat,不依赖原始值的小数位 - 避免连续浮点运算后直接比较结果,尤其不要用于循环条件(如
for (double x = 0; x != 1; x += 0.1))
别让 long 不经意变成 float
看似安全的自动转换(如 float f = someLongValue;)可能静默丢精度:
- float 尾数仅 23 位,最多精确表示 ±16777216 的整数;超限后相邻可表示值出现间隔
- 订单 ID、时间戳毫秒等关键 long 值,禁止转 float;必须参与浮点运算时优先升为
double(可精确表示 ≤ 9×10¹⁵) - 若真要转,先校验:
(long)((float)original) == original,不成立就说明已失真


















