ITPub博客

首页 > 应用开发 > IT综合 > BigDecimal 被拼多多的"砍一刀"应用到了极致

BigDecimal 被拼多多的"砍一刀"应用到了极致

原创 IT综合 作者:恒生LIGHT云社区 时间:2022-01-20 13:35:43 0 删除 编辑

作者:幻好 来源: 恒生LIGHT云社区

概述

近日,“拼多多砍价, 砍价永远差一刀”登上了热搜,而这个功能在我们周围的亲朋好友中都有过亲身体验。

本次事件具体就去年3月,上海律师刘宇航当时参加了拼多多的“砍价免费拿”活动,领取了一张“超级免单卡”,但邀请多人砍价后,始终差“0.9%”。刘宇航以拼多多在提供网络服务时涉嫌违背诚实信用原则,使用虚假数据隐瞒规则已构成欺诈为由,向法院递交了起诉材料。在案件审理中,针对刘宇航的起诉以及由此引发的质疑,拼多多表示,因页面显示百分比位数有限,所以他们把一个至少小数点后有6位数以上的百分比,省略显示为0.9%,砍价页面显示的0.9%不是0.9%,而是0.9996427%。

image-20220119084743848.png

本文主要通过这一现实场景,来思考其背后相关的技术实现——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云社区,由恒生电子搭建的金融科技专业社区平台,分享实用技术干货、资源数据、金融科技行业趋势,拥抱所有金融开发者。

扫描下方小程序二维码,加入我们!


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70001864/viewspace-2853193/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2021-06-09

  • 博文量
    135
  • 访问量
    93940