为什么 BigDecimal 不丢失精度?

在 Java 里做金额、税费、利息计算,几乎所有人都知道一条铁律:
禁止使用 float、double,必须用 BigDecimal。
因为 float/double 动不动就出现这种诡异结果:
System.out.println(0.1 + 0.2); // 输出:0.30000000000000004
而 BigDecimal 就能老老实实算出 0.3。
很多人只知道“要用 BigDecimal”,却不知道:它到底凭什么能保证不丢失精度?
今天从底层原理讲清楚,看完你就彻底通透。
一、先搞懂:float/double 为什么会丢精度?
计算机底层是二进制。
像 0.1 这种十进制小数,转换成二进制是一个无限循环小数:
0.1 → 二进制:0.00011 0011 0011 0011…(无限循环)
而 float、double 的存储空间是固定长度的:
- float:32 位;
- double:64 位。
无限循环的二进制,只能被截断存储。
一截断,就丢精度;一计算,误差就放大。
这就是为什么 0.1 + 0.2 ≠ 0.3。
不是计算错了,是存储方式天生不精确。
二、BigDecimal 为什么不丢精度?核心原理一句话
BigDecimal 不用二进制浮点存储,而是用“整数 + 标度”来模拟十进制小数。
它把一个小数拆成两部分存在内部:
- unscaled value:一个任意长度的大整数(BigInteger);
- scale:小数点向右移动几位(标度/指数)。
比如:
123.45 = 12345 × 10^-2
在 BigDecimal 内部就是:
- unscaled value = 12345;
- scale = 2。
再比如:
0.1 = 1 × 10^-1
- unscaled value = 1;
- scale = 1。
三、它为什么能精确?关键点有三个
1. 完全基于整数运算
BigDecimal 做加减乘除,本质上都是整数运算。
整数在二进制里可以精确表示,不会循环、不会截断。
只要内存够,整数可以无限大,不存在精度上限。
2. 严格模拟十进制,而非二进制浮点
double 是二进制小数,天生无法精确表示很多十进制小数。
BigDecimal 是十进制表示:
- 你写 0.1,它内部就是 1/10;
- 你写 0.25,它内部就是 25/100。
完全按照人类十进制数学规则计算,自然不会乱飘。
3. 标度(scale)可控,舍入策略明确
你可以精确控制:
- 保留几位小数;
- 超出部分如何舍入(四舍五入、向上取整、截断等)。
只要你不主动舍入,它就绝对不会偷偷丢精度。
四、一个例子看懂内部计算
以 0.1 + 0.2 为例:
-
0.1 → 1 × 10^-1 -
0.2 → 2 × 10^-1
相加:
(1 + 2) × 10^-1 = 3 × 10^-1 = 0.3
全程整数运算,完美精确。
换成 double:
- 0.1 是近似值;
- 0.2 也是近似值;
- 加完还是近似值。
结果自然错乱。
五、重要提醒:BigDecimal 不代表绝对安全
虽然 BigDecimal 本身精度可靠,但用法不对照样丢精度。
坑 1:用 double 构造 BigDecimal(经典错误)
// 错误! BigDecimal a = new BigDecimal(0.1);
0.1 传入时已经是不精确的 double,
BigDecimal 再精确也救不回来。
正确写法:
BigDecimal a = new BigDecimal("0.1");
坑 2:除法不指定舍入模式
BigDecimal.ONE.divide(new BigDecimal("3"));
无限小数会直接抛异常:ArithmeticException: Non-terminating decimal expansion
正确写法:
BigDecimal.ONE.divide(new BigDecimal("3"), 2, RoundingMode.HALF_UP);
六、总结
为什么 BigDecimal 不丢失精度?
- 放弃二进制浮点,改用十进制思想;
- 内部用大整数 + 标度表示小数;
- 所有运算都是精确整数运算;
- 舍入行为可控,不会偷偷截断。
以上关于为什么 BigDecimal 不丢失精度?的文章就介绍到这了,更多相关内容请搜索码云笔记以前的文章或继续浏览下面的相关文章,希望大家以后多多支持码云笔记。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 admin@mybj123.com 进行投诉反馈,一经查实,立即处理!
重要:如软件存在付费、会员、充值等,均属软件开发者或所属公司行为,与本站无关,网友需自行判断
码云笔记 » 为什么 BigDecimal 不丢失精度?
微信
支付宝