当前位置:网站首页>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 .
边栏推荐
- CDGA|工业企业进行数据治理的六个关键点
- 高数_第6章无穷级数__绝对收敛_条件收敛
- How will you integrate into the $20trillion "project economy" in five years
- js模糊阴影跟随动画js特效插件
- 2022版IDEA图形界面GUI乱码解决方法超详细简单版
- 电商行业转账返款方案分析
- XML&Xpath解析
- Numpy - record
- 用脚本添加URP的RendererData
- One of the Taobao short video pit avoidance Guide Series -- thoroughly understand Taobao short video
猜你喜欢
随机推荐
解决 vs2022在调试程序时缓慢加载一堆符号的问题
Canvas大火燃烧h5动画js特效
淘宝短视频避坑指南系列之一--彻底了解淘宝短视频
CDGA|工业企业进行数据治理的六个关键点
Abbexa 8-OHdG CLIA 试剂盒解决方案
ZigBee模块无线传输星形拓扑组网结构简介
Numpy np set_ Usage of printoptions () -- control output mode
我在做一件很酷的事情
LeetCode 255. Verifying preorder traversal sequence binary search tree*
Abbexa AML1 DNA 结合 ELISA 试剂盒说明书
Classic topics of leetcode tree (I)
AI 加持实时互动|ZegoAvatar 面部表情随动技术解析
protoc-gen-go-grpc‘不是内部或外部命令,也不是可运行的程序 或批处理文件
LeetCode 255. 验证前序遍历序列二叉搜索树*
美学心得(第二百三十七集) 罗国正
CUDA realizes efficient search - failed audit?
Draw confusion matrix
Red vertical left side menu navigation code
AOE网关键路径
Container containing the most water









