当前位置:网站首页>Step on the pit. The BigDecimal was improperly used, resulting in P0 accident!
Step on the pit. The BigDecimal was improperly used, resulting in P0 accident!
2022-06-10 18:11:00 【hello-java-maker】
Recommended today
Reduce try-catch , This is grace !
An addictive new generation of development artifacts , Say goodbye to Controller、Service、Dao Other methods
SpringBoot Realize face recognition function
believe me , Use Stream Can really make the code more elegant !
The most detailed thread pool in the whole network ThreadPoolExecutor Reading !
Batch splitting with multithreading List Import database , Efficiency bars !background
When we use the amount to calculate or display the amount, we often use BigDecimal, It is also a very recommended type when it comes to the amount .
BigDecimal It also provides many constructor methods , Improper use of these constructor methods may cause unnecessary trouble or even loss of money , Thus causing accident asset loss .
accident
Next, let's look at an accident at the cashier .
Problem description
The cashier reported an error in calculating the amount of goods , The order cannot be paid .
Accident level
P0
Accident process
as follows :
13:44, Get the alarm , Order payment failed , Payment availability reduced to 60%
13:50, Quickly roll back online code , Back to normal
14:20,review Code , Problems found in pre release verification
14:58, Modify the problem code to go online , Online recovery
The cause of the problem
BigDecimal Lost precision in amount calculation .
Cause analysis
First, let's use a piece of code to reproduce the root cause of the problem , As shown below :
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);
}The results are as follows :

Found by test , When using double perhaps float These floating-point data types , Will lose precision ,String、int Will not be , Why is that ?
Let's open the constructor method to see the source code :
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;
} The problem is doubleToRawLongBits In this way , stay jdk in double class (float And int Corresponding ) Provided in double And long transformation ,doubleToRawLongBits Will be double Convert to long, This method is the original method ( The bottom is not java Realization , yes c++ Realized ).
double The reason why something goes wrong , It's because the decimal point to binary lost precision .

BigDecimal Expand decimal number in processing N Times make it count on integers , And keep the corresponding precision information .
①float and double type , It is mainly designed for scientific calculation and engineering calculation , The reason for performing binary floating-point operations , It is designed to provide accurate and fast approximate sum calculation over a wide range of numerical values .
② It doesn't provide completely accurate results , So it should not be used for precise results .
③ When the floating-point number reaches a certain large number , Will automatically use scientific counting , Such a representation is only approximate to the real number but not equal to the real number .
④ When decimals are converted to binary, there will be infinite cycles or the length of the floating-point mantissa will be exceeded .
summary
therefore , In the process of precision calculation , We try to use String Type to convert .
The correct usage is as follows :
BigDecimal bigDecimal2=new BigDecimal("8.8");
BigDecimal bigDecimal3=new BigDecimal("8.812");
System.out.println( bigDecimal2.compareTo(bigDecimal3));
System.out.println( bigDecimal2.add(bigDecimal3));BigDecimal What is created is an object , We can't use the traditional addition, subtraction, multiplication and division to calculate it , Must use his method , In our database store , If we use double perhaps float type , It needs to be calculated after round-trip conversion , Very inconvenient .
Tool sharing
So here we put together a util Class for everyone .
import java.math.BigDecimal;
/**
* @Author shuaige
* @Date 2022/4/17
* @Version 1.0
**/
public class BigDecimalUtils {
public static BigDecimal doubleAdd(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2);
}
public static BigDecimal floatAdd(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.add(b2);
}
public static BigDecimal doubleSub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2);
}
public static BigDecimal floatSub(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.subtract(b2);
}
public static BigDecimal doubleMul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2);
}
public static BigDecimal floatMul(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.multiply(b2);
}
public static BigDecimal doubleDiv(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
// Keep two decimal places ROUND_HALF_UP = rounding
return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
}
public static BigDecimal floatDiv(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
// Keep two decimal places ROUND_HALF_UP = rounding
return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);
}
/**
* Compare v1 v2 size
* @param v1
* @param v2
* @return v1>v2 return 1 v1=v2 return 0 v1<v2 return -1
*/
public static int doubleCompareTo(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.compareTo(b2);
}
public static int floatCompareTo(float v1, float v2) {
BigDecimal b1 = new BigDecimal(Float.toString(v1));
BigDecimal b2 = new BigDecimal(Float.toString(v2));
return b1.compareTo(b2);
}
}source :juejin.cn/post/7087404273503305736
Last , Recommend a planet of my knowledge , Join now , front 100 name , It only needs 25 element that will do , Very favorable .
边栏推荐
- 【AXI】解读AXI协议双向握手机制的原理
- Vim常用命令总结
- YML file configuration parameter definition dictionary and list
- IIS installation and deployment web site
- Canvas fire burning H5 animation JS special effects
- MMdetection之build_optimizer模块解读
- 聊聊远程办公那些事儿,参与征文领稿费拿大奖!
- Abbexa 无细胞 DNA 试剂盒说明书
- 软考不通过能不能补考?解答来了
- Unity stepping on the pit record: if you inherit monobehavior, the constructor of the class may be called multiple times by unity. Do not initialize the constructor
猜你喜欢

改变世界的开发者丨玩转“俄罗斯方块”的瑶光少年

mmdetection之dataloader构建

mmcv之Config类介绍

The development of flutter in digital life and the landing practice of Tianyi cloud disk

用脚本添加URP的RendererData

Noise line h5js effect realized by canvas

How will you integrate into the $20trillion "project economy" in five years

如何定位游戏发热问题

最新好文 | 基于因果推断的可解释对抗防御

MYSQL开窗函数详解
随机推荐
QTableWidget / QTableView实用技巧
IP总结(TCP/IP卷1和卷2)
Numpy - record
2022 version of idea graphical interface GUI garbled code solution super detailed simple version
LeetCode 321. 拼接最大数***
一文带你了解J.U.C的FutureTask、Fork/Join框架和BlockingQueue
[FAQ] summary of common problems and solutions during the use of rest API interface of sports health service
Memory pool principle I (based on the whole block)
Abbexa低样本量鸡溶菌酶 C (LYZ) ELISA 试剂盒
AI 加持实时互动|ZegoAvatar 面部表情随动技术解析
LeetCode 255. Verifying preorder traversal sequence binary search tree*
Play with pytoch's function class
苹果期待的「无密码时代」,真能实现吗?
国货彩妆,败走618
pands pd. Detailed parsing of dataframe() function
电商行业转账返款方案分析
LeetCode 321. 拼接最大數***
玩轉Pytorch的Function類
搭建在线帮助中心,轻松帮助客户解决问题
小程序积分商城如何实现营销目的