当前位置:网站首页>BigDecimal使用不当,造成P0事故!
BigDecimal使用不当,造成P0事故!
2022-06-09 10:11:00 【程序猿DD_】
文章来源:https://c1n.cn/MSqAy
背景
我们在使用金额计算或者展示金额的时候经常会使用 BigDecimal,也是涉及金额时非常推荐的一个类型。
BigDecimal 自身也提供了很多构造器方法,这些构造器方法使用不当可能会造成不必要的麻烦甚至是金额损失,从而引起事故资损。
事故
接下来我们看下收银台出的一起事故。
问题描述
收银台计算商品金额报错,导致订单无法支付。
事故级别
P0
事故过程
如下:
13:44,接到报警,订单支付失败,支付可用率降至 60%
13:50,迅速回滚上线代码,恢复正常
14:20,review 代码,预发布验证发现问题点
14:58,修改问题代码上线,线上恢复
故障原因
BigDecimal 在金额计算中丢失精度。
原因分析
首先我们先用一段代码复现问题根源,如下所示:
public static void main(String[] args) {
BigDecimal bigDecimal=new BigDecimal(88);
System.out.println(bigDecimal);
bigDecimal=new BigDecimal("8.8");
System.out.println(bigDecimal);
bigDecimal=new BigDecimal(8.8);
System.out.println(bigDecimal);
}执行结果如下:

通过测试发现,当使用 double 或者 float 这些浮点数据类型时,会丢失精度,String、int 则不会,这是为什么呢?
我们点开构造器方法看下源码:
public static long doubleToLongBits(double value) {
long result = doubleToRawLongBits(value);
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
DoubleConsts.EXP_BIT_MASK) &&
(result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
result = 0x7ff8000000000000L;
return result;
}问题就处在 doubleToRawLongBits 这个方法上,在 jdk 中 double 类(float 与 int 对应)中提供了 double 与 long 转换,doubleToRawLongBits 就是将 double 转换为 long,这个方法是原始方法(底层不是 java 实现,是 c++ 实现的)。
double 之所以会出问题,是因为小数点转二进制丢失精度。

BigDecimal 在处理的时候把十进制小数扩大 N 倍让它在整数上进行计算,并保留相应的精度信息。
① float 和 double 类型,主要是为了科学计算和工程计算而设计的,之所以执行二进制浮点运算,是为了在广泛的数值范围上提供较为精确的快速近和计算。
② 并没有提供完全精确的结果,所以不应该被用于精确的结果的场合。
③ 当浮点数达到一定大的数,就会自动使用科学计数法,这样的表示只是近似真实数而不等于真实数。
④ 当十进制小数位转换二进制的时候也会出现无限循环或者超过浮点数尾数的长度。
总结
所以,在涉及到精度计算的过程中,我们尽量使用 String 类型来进行转换。
我们创建了一个高质量的技术交流群,与优秀的人在一起,自己也会优秀起来,赶紧点击加群,享受一起成长的快乐。另外,如果你最近想跳槽的话,年前我花了2周时间收集了一波大厂面经,节后准备跳槽的可以点击这里领取!
推荐阅读
··································
你好,我是程序猿DD,10年开发老司机、阿里云MVP、腾讯云TVP、出过书创过业、国企4年互联网6年。从普通开发到架构师、再到合伙人。一路过来,给我最深的感受就是一定要不断学习并关注前沿。只要你能坚持下来,多思考、少抱怨、勤动手,就很容易实现弯道超车!所以,不要问我现在干什么是否来得及。如果你看好一个事情,一定是坚持了才能看到希望,而不是看到希望才去坚持。相信我,只要坚持下来,你一定比现在更好!如果你还没什么方向,可以先关注我,这里会经常分享一些前沿资讯,帮你积累弯道超车的资本。
边栏推荐
- Authentication successful processor
- 叁拾肆- sklearn 根据样本对文本情绪进行分类
- 肆拾贰- JS 告诉你,到底你是贫穷还是富贵
- Application of ebpf in cloud native environment
- Forty four - wechat applet canvas unlocking and spring physical effect animation
- Go zero micro Service Practice Series (II. Service splitting)
- [genius_platform software platform development] lesson 101st: summary of errors encountered in compiling Windows environment vs2017 for DZ products of power projects
- 1019. the next larger node in the linked list
- [model deployment and business implementation] model transformation of AI framework deployment scheme
- 多线程系列之基本概念
猜你喜欢

You need to think about the following questions about the online help center

Web SSH client shwifty

安防监控视频EasyCVR视频调阅界面增加单个视频的关闭按钮

【光学】 基于matlab模拟光的双缝干涉附GUI

1340. jumping game v-dynamic planning plus DFS

77.5% of the world's websites are using PHP, the "best language in the world"!

Unemployment wave? Yuancosmos opens up new employment opportunities

时间复杂度和空间复杂度

How many points can you get if the programmer's college entrance examination paper is exposed?

【模型部署与业务落地】AI 框架部署方案之模型转换
随机推荐
多线程中thread::join()和thread::detach()的区别
1340. jumping game v-dynamic planning plus DFS
Web版SSH客戶端Sshwifty
华泰证券安全吗?我要开户
叁拾贰- NodeJS简单代理池(有完没完?) 之 SuperAgent 使用代理不是 Timeout 的 Timeout
数学公式显示
CTF WEB WP杂谈
“当你不再是程序员,很多事会脱离掌控”—— 对话全球最大独立开源公司SUSE CTO...
Blazor University (27) routing - detect navigation events
31. next spread
Micronet: image recognition with very low flop
Thirty eight JS tried fractal graphics on canvas (II) tried mountain building, painted mountains and the basis of angular geometry
TensorFlow新文档发布:新增CLP、DTensor...最先进的模型已就绪!
C语言与Lua的交互(实践二)
flutter 生成海报
[genius_platform software platform development] lecture 37: network card hybrid mode and raw socket
Interview question 01.06 String compression
Forty four - wechat applet canvas unlocking and spring physical effect animation
16. sum of the nearest three numbers - quick sort plus double pointer method
塔米狗知识|2022年新的国有产权非公开协议转让新规解读来了!