BigDecimal能解决金融计算精度丢失,因其以“整数+小数位数”方式精确表示十进制数,避开float/double的二进制表示缺陷;构造推荐字符串入参,除法须指定scale与舍入模式,比较用compareTo()而非equals()。

BigDecimal 在金融计算中能解决精度丢失,核心在于它用“整数+小数位数”方式精确表示十进制数,避开二进制浮点数(如 double)固有的表示缺陷。
为什么 float/double 在金融场景必然出错
计算机底层用二进制存储浮点数,而很多十进制小数(如 0.1、0.01)无法被有限位二进制精确表示。例如:
- 0.1 + 0.2 != 0.3 —— double 计算结果是 0.30000000000000004
- 银行计息、分账、对账等场景要求“所见即所得”,误差哪怕 1 分钱也不允许
- IEEE 754 浮点规范设计目标是科学计算(容忍微小误差),不是会计核算
BigDecimal 是如何做到精确的
它不存“小数值”,而是存两个整数:unscaledValue(未缩放值)和 scale(小数位数)。例如:
- new BigDecimal("19.99") 内部实际存的是 unscaledValue = 1999,scale = 2
- 所有算术操作(add、subtract、multiply、divide)都在整数层面进行,再按 scale 调整结果
- 构造时推荐用 字符串入参(如 new BigDecimal("0.1")),避免 double 入参(new BigDecimal(0.1))已携带二进制误差
关键操作必须注意的细节
BigDecimal 的“精确”不等于“自动正确”,错误用法仍会导致偏差:
- 除法必须指定 scale 和舍入模式:divide() 不带参数会抛 ArithmeticException(如 1 ÷ 3 无限循环);应写成 a.divide(b, 2, RoundingMode.HALF_UP)
- 比较用 compareTo(),不用 equals():equals() 会比较 scale(new BigDecimal("1.0").equals(new BigDecimal("1.00")) → false),compareTo() 只比数值大小
- 避免隐式类型转换:不要混用 int/double 运算后再转 BigDecimal;全程保持 BigDecimal 类型链式计算
一个典型安全计算流程示例
比如计算 1000 元按年利率 3.85% 日计息(360 天)一天的利息:
- 本金:new BigDecimal("1000.00")
- 日利率:new BigDecimal("0.0385").divide(new BigDecimal("360"), 6, RoundingMode.HALF_UP)
- 利息 = 本金 × 日利率,再 setScale(2, RoundingMode.HALF_UP) 保留两位小数
- 全程无 double 参与,无字符串拼接,无默认舍入

















