bigdecimal.valueof(double)能将0.1转为精确的“0.1”,因它先调用double.tostring()获取最短十进制字符串再构造;而new bigdecimal(double)直接继承double的二进制近似值(如0.10000000000000000555…),导致精度失真。

用 BigDecimal.valueOf(double) 替代 new BigDecimal(double),能避开 double 二进制表示固有的精度缺陷,让 0.1 真正变成 “0.1”,而不是一长串近似值。
为什么 new BigDecimal(double) 会出错
double 类型本身无法精确存储大多数十进制小数。比如 0.1 在内存中实际是:
0.1000000000000000055511151231257827021181583404541015625
new BigDecimal(0.1) 会原样把这个近似值转成 BigDecimal,结果自然失真。
valueOf 是怎么做到“看起来准确”的
它不直接读 double 的二进制位,而是先调用 Double.toString(0.1),这个方法返回的是对人类最友好的、能唯一反推该 double 值的最短十进制字符串——也就是 "0.1",再用这个字符串构造 BigDecimal。
所以:BigDecimal.valueOf(0.1) ≡ new BigDecimal("0.1")
但 valueOf 并非万能,这些情况仍要小心
- 如果传入的 double 本身已是多次浮点计算的结果(如
0.1 + 0.2得到0.30000000000000004),valueOf 会如实转成"0.30000000000000004",误差照旧 - 超大数值(如超过 16 位有效数字)时,double 已经丢失原始精度,valueOf 无法还原
- 业务要求严格控制小数位数(如货币必须两位),valueOf 不自动设 scale,后续运算或比较前得手动
setScale(2, RoundingMode.HALF_UP)
更稳妥的源头写法
优先级从高到低:
- 原始就是字符串:直接
new BigDecimal("19.99") - 原始是整数单位(如分):用
BigDecimal.valueOf(1999).divide(BigDecimal.valueOf(100))或new BigDecimal(1999).movePointLeft(2) - 不得不从 double 来:只用于简单常量(如 0.1、0.01),且确认该 double 未被污染;否则加一层
setScale(...)显式截断










