Java浮点数精度问题源于IEEE 754二进制表示本质,须用BigDecimal字符串构造、数据库定点类型、边界直传及显式标度控制来保障精度。

Java 基本数据类型本身无法确保数据精度——这不是操作问题,而是设计本质。float 和 double 按 IEEE 754 标准用二进制存储十进制小数,像 0.1、0.3 这类数在二进制中是无限循环小数,必须截断,误差从赋值那一刻就已固化。所以,“用对基本类型”不能提升精度;真正能保障精度的,是绕开它们。
用 BigDecimal 替代浮点计算,但初始化必须正确
BigDecimal 不是“修复” double,而是换了一套十进制建模系统:内部用整数 + 标度(scale)表示数值,所有运算都在十进制逻辑下进行。
关键不在“用了”,而在“怎么用”:
- ✅ 推荐:
new BigDecimal("19.99")—— 字符串直入,无转换污染 - ✅ 安全:
BigDecimal.valueOf(19.99)—— 底层调用Double.toString(),规避了double的二进制误差 - ❌ 禁止:
new BigDecimal(19.99)—— 此时19.99已是double近似值,错误被直接固化
用户输入、配置文件、前端传参等原始来源,应尽量保持字符串形态,不经过 double 中转,直通 BigDecimal 构造。
数据库与传输环节严格隔离 double
精度污染常发生在系统边界:
- 数据库字段必须定义为
DECIMAL(18,2)或类似定点类型,禁用FLOAT/DOUBLE - JDBC 查询时用
resultSet.getBigDecimal("amount"),绝不调用getDouble()再转 - 写入时用
preparedStatement.setBigDecimal(1, amount),跳过double中间层 - JSON 序列化(如 FastJSON、Jackson)需启用
WriteBigDecimalAsPlain或全局配置,避免1.00被序列化成"1",影响前端展示或校验
运算过程显式控制标度和舍入
加减法自动对齐标度,天然保精度;乘除法则必须人工指定:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 乘法:
a.multiply(b).setScale(2, RoundingMode.HALF_UP) - 除法:
a.divide(b, 2, RoundingMode.HALF_UP)—— 必须提供标度和舍入模式,否则可能抛ArithmeticException - 比较用
compareTo(),不用equals()(后者会比较标度,new BigDecimal("1.0").equals(new BigDecimal("1.00"))返回false)
整数类型虽无小数误差,但要防溢出
long 最大值约 9.2×10¹⁸,超限即翻转且不报错。若涉及大数累加、ID 运算(如雪花 ID),后端返回给前端时应转为字符串,避免 JS 端因 Number.MAX_SAFE_INTEGER(2^53−1)限制导致末位变 0。
不复杂但容易忽略

















