作者:幻好 来源: 恒生LIGHT云社区
概述
近日,“拼多多砍价, 砍价永远差一刀 ”登上了热搜,而这个功能在我们周围的亲朋好友中都有过亲身体验。
本次事件具体就去年3月,上海律师刘宇航当时参加了拼多多的“砍价免费拿”活动,领取了一张“超级免单卡”,但邀请多人砍价后,始终差“0.9%”。刘宇航以拼多多在提供网络服务时涉嫌违背诚实信用原则,使用虚假数据隐瞒规则已构成欺诈为由,向法院递交了起诉材料。在案件审理中,针对刘宇航的起诉以及由此引发的质疑,拼多多表示,因页面显示百分比位数有限,所以他们把一个至少小数点后有6位数以上的百分比,省略显示为0.9%,砍价页面显示的0.9%不是0.9%,而是0.9996427%。
本文主要通过这一现实场景,来思考其背后相关的技术实现——Java中精确小数计算。
BigDecimal
应用背景
在Java中 JDK 中提供的 float 和 double 的数据类型,其主要设计目标是为了科学计算和工程计算,由于其执行的二进制浮点运算,在某些场景下并不能提供精确的结果。比如:
System.out.println(0.1 + 0.2);
// 输出
0. 30000000000000004
一个简单的加法运算,在输出的结果上并不能保证结果的准确性。其主要原因是在CPU中,表示的浮点数由两个部分组成:指数和尾数,这样一般都会导致失去一定的精确度,有些浮点数运算也会产生一定的误差,浮点数的值实际上是由一个特定的数学公式计算得到的。如:2.4的二进制表示并非就是精确的1.5。反而最为接近的二进制表示是 1.59999999999999。
所以在许多需要精确小数计算的商业场景(如支付,商城等),通常需要采用 java.math.BigDecimal
类来进行精确计算。
操作使用
创建 BigDecimal
对象
BigDecimal bigDecimal = new BigDecimal("2022.01054");
通常建议使用
String
类型的构造方法,创建BigDecimal
对象,虽然也可以使用Double
类型的构造方法,但是前面就说过,浮点数本来就不准确,因此转换的BigDecimal
对象也会不精确。
格式化小数
// 向零方向舍入
System.out.println(bigDecimal.setScale(3, BigDecimal.ROUND_DOWN));
// 输出
2022.010
// 向远离0的方向舍入,进位处理
new BigDecimal(4.32579).setScale(4, BigDecimal.ROUND_UP);
// 输出
2022.011
// 向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入: >=5
new BigDecimal(4.32575).setScale(4, BigDecimal.ROUND_HALF_UP);
// 输出
2022.011
// 向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入: >5
new BigDecimal(4.32575).setScale(4, BigDecimal.ROUND_HALF_DOWN);
// 输出
2022.010
加减乘除运算
// 推荐用字符串的形式初始化
BigDecimal numFri = new BigDecimal("0.0888");
BigDecimal numSec = new BigDecimal("0.2222");
// 加法
BigDecimal resultByAdd = numFri.add(numSec);
// 减法
BigDecimal resultBySub = numFri.subtract(numSec);
// 乘法
BigDecimal resultByMul = numFri.multiply(numSec);
// 除法
BigDecimal resultBydiv = numFri.divide(numSec,20,BigDecimal.ROUND_HALF_UP);
// 绝对值
BigDecimal resultByAbs = numFri.abs();
BigDecimal
对象在减乘除时,最终都返回的是一个新的BigDecimal
对象,因为BigInteger
与BigDecimal
都是不可变的(immutable)的
,在进行每一步运算时,都会产生一个新的对象
总结
在需要精确计算的重要场景,使用 BigDecimal
,同时推荐使用 String 类型的构造函数创建 BigDecimal
对象。
想向技术大佬们多多取经?开发中遇到的问题何处探讨?如何获取金融科技海量资源?
恒生LIGHT云社区,由恒生电子搭建的金融科技专业社区平台,分享实用技术干货、资源数据、金融科技行业趋势,拥抱所有金融开发者。
扫描下方小程序二维码,加入我们!