作者:幻好
来源:恒生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
// 向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入: >=5new BigDecimal(4.32575).setScale(4, BigDecimal.ROUND_HALF_UP);
// 输出2022.011
// 向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入: >5new 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 云社区,由恒生电子搭建的金融科技专业社区平台,分享实用技术干货、资源数据、金融科技行业趋势,拥抱所有金融开发者。
扫描下方小程序二维码,加入我们!
评论