BigDecimal能解决浮点数精度丢失问题,因其以BigInteger加标度方式精确表示十进制数,避开IEEE 754二进制存储缺陷;关键在于字符串构造、整数运算及显式舍入控制。

BigDecimal 能解决浮点数精度丢失问题,根本原因在于它不依赖二进制浮点表示,而是用整数加标度的方式精确建模十进制数。
底层用整数存储,避开二进制陷阱
float 和 double 按 IEEE 754 标准用二进制存储小数,而像 0.1、0.2 这类十进制小数在二进制中是无限循环小数,必须截断——误差从存入那一刻就已产生。BigDecimal 完全绕开这个路径:
- 内部由 BigInteger unscaledValue + int scale 构成,例如 "12.34" 存为整数 1234 和标度 2
- 所有运算(加减乘除)都转化为整数运算,整数计算天然无精度损失
- 小数点位置由 scale 控制,全程保持十进制语义,不涉及进制转换
构造方式决定精度起点是否干净
精度不丢失的前提是“输入不能带毒”。常见错误是用 double 初始化:
你是 TypeScript 项目架构专家,专注于脚手架搭建生产就绪的 Node.js 和前端应用。生成包含现代工具链(pnpm、Vite、Next.js)、类型
- ❌ new BigDecimal(0.1):0.1 已是 double 的近似值(实际是 0.10000000000000000555…),BigDecimal 只是把它“原样记下来”
- ✅ new BigDecimal("0.1"):字符串直接解析为精确的十进制整数+标度,零误差
- ✅ BigDecimal.valueOf(0.1):内部调用 Double.toString(),避免科学计数法,效果等同字符串构造
运算过程可控,不默认妥协
加减法自动对齐标度,结果精度可预期;乘除法则强制你明确精度和舍入规则,杜绝隐式截断:
立即学习“Java免费学习笔记(深入)”;
- add/subtract:结果标度取操作数中较大者,无需指定
- multiply:建议用
multiply(BigDecimal, MathContext)控制总位数 - divide:必须指定标度和舍入模式,如
a.divide(b, 2, RoundingMode.HALF_EVEN),否则可能抛异常
不是“修复”浮点数,而是彻底换赛道
BigDecimal 不是对 float/double 的补丁,它是另一套计算体系:用字符串输入、整数运算、显式舍入、不可变对象。只要源头用对(字符串或 valueOf)、中间不碰 double、运算时控好舍入,就能守住每一分精度。金融系统敢用它,靠的就是这种确定性,而不是概率性“大概准”。

















