用double类型的数构造BigDecimal的坑

项目场景:

最近,再做支付相关的东西,前端展示相关金额的商品,然后提交到后端。前端展示的商品价格只支持到角,所以只保留一位小数。前端用到的是controller+velocity模板,展示的金额,是在controller中用BigDecimal相关方法格式化的。例如

 Double aa = 1.2;
 BigDecimal bigDecimalOne = new BigDecimal(aa).setScale(1, BigDecimal.ROUND_DOWN);

执行结果输出为1.1;
用户在提交订单后,后台服务还要重新计算一下商品价格,例子如下

 Double aa = 1.2;
 BigDecimal bigDecimalTwo = new BigDecimal(aa + "").setScale(1, BigDecimal.ROUND_DOWN);

执行结果输出变为1.2;
前后两个结果不一致这是为什么呢

原因分析:

  1. 通过a + ‘’ 将 double 值隐式转换为字符串(如 “11.2”)BigDecimal 通过字符串构造时,会精确存储十进制值(11.2)
  2. 而通过double类型构造时,double 类型存储的 11.2 是二进制近似值,实际值为:11.199999999999999289457264239899814060211181640625,所以保留1位截断的时候为11.1
  3. 根本原因就是,二进制浮点数缺陷:double 无法精确表示十进制小数(如 11.2),实际存储的是近似值。

解决方案:

	处理浮点数时,永远避免直接使用 new BigDecimal(double)。优先选择:BigDecimal.valueOf(double)或者
new BigDecimal(String)。以保证精确的十进制表示。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值