当前位置:网站首页>Is BigDecimal safe to calculate the amount? Look at these five pits~~
Is BigDecimal safe to calculate the amount? Look at these five pits~~
2022-07-04 17:33:00 【Young】
See an article because it is not used in the amount calculation BigDecimal
And the article that caused the failure , But unless in some very simple scenes , Settlement of remittance businesses will not be directly used BigDecimal
To calculate the amount , For two reasons :
BigDecimal
There are still many hidden pitsBigDecimal
The unit that did not provide the amount
1. BigDecimal
Five easy pits in
1.1 new BigDecimal()
still BigDecimal#valueOf()
?
First look at the following code
BigDecimal bd1 = new BigDecimal(0.01);
BigDecimal bd2 = BigDecimal.valueOf(0.01);
System.out.println("bd1 = " + bd1);
System.out.println("bd2 = " + bd2);
The output to the console is :
bd1 = 0.01000000000000000020816681711721685132943093776702880859375
bd2 = 0.01
The reason for this difference is 0.1 This digital computer cannot accurately express , Send BigDecimal
The accuracy has been lost by , and BigDecimal#valueOf
The implementation of is completely different
public static BigDecimal valueOf(double val) {
// Reminder: a zero double returns '0.0', so we cannot fastpath
// to use the constant ZERO. This might be important enough to
// justify a factory approach, a cache, or a few private
// constants, later.
return new BigDecimal(Double.toString(val));
}
It uses the corresponding string of floating-point numbers to construct BigDecimal
object , Therefore, the accuracy problem is avoided . So we should try to use strings instead of floating-point numbers to construct BigDecimal
object , If it doesn't work , Just use BigDecimal#valueOf()
Methods! .
1.2 Equivalence comparison
BigDecimal bd1 = new BigDecimal("1.0");
BigDecimal bd2 = new BigDecimal("1.00");
System.out.println(bd1.equals(bd2));
System.out.println(bd1.compareTo(bd2));
The output of the console will be :
false
0
The reason is ,BigDecimal
in equals
The implementation of the method will compare the accuracy of two numbers , and compareTo
Method will only compare the size of the value .
1.3 BigDecimal
Does not mean infinite accuracy
First look at this code
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b) // results in the following exception.
The result is an exception :
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
About this exception ,Oracle The official documents of have specific instructions
If the quotient has a nonterminating decimal expansion and the operation is specified to return an exact result, an ArithmeticException is thrown. Otherwise, the exact result of the division is returned, as done for other operations.
The main idea is , If the result of the quotient of division is an infinite decimal, but we expect to return the exact result , Then the program will throw an exception . Back to our example , We need to tell JVM
We don't need to return exact results
BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("3.0");
a.divide(b, 2, RoundingMode.HALF_UP)// 0.33
1.4 BigDecimal
Turn it back String
Be careful
BigDecimal d = BigDecimal.valueOf(12334535345456700.12345634534534578901);
String out = d.toString(); // Or perform any formatting that needs to be done
System.out.println(out); // 1.23345353454567E+16
It can be seen that the results have been converted into scientific counting , Maybe this is not the expected result BigDecimal
There are three methods that can be converted to the corresponding string type , Remember not to use the wrong :
String toString(); // Use scientific counting when necessary
String toPlainString(); // No scientific counting
String toEngineeringString(); // The method of recording numbers often used in engineering calculation , Similar to scientific counting , But ask for 10 The power of must be 3 Multiple
1.5 The execution sequence cannot be changed ( The commutative law of multiplication fails )
It is common sense that multiplication satisfies the commutative law , But in the world of computers , There will be situations that do not satisfy the commutative law of multiplication
BigDecimal a = BigDecimal.valueOf(1.0);
BigDecimal b = BigDecimal.valueOf(3.0);
BigDecimal c = BigDecimal.valueOf(3.0);
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP).multiply(c)); // 0.990
System.out.println(a.multiply(c).divide(b, 2, RoundingMode.HALF_UP)); // 1.00
Don't underestimate this 0.01 The difference between , In Huijin , There will be a very large amount difference .
2. Best practices
About the amount calculation , Many business teams will be based on BigDecimal
One more Money
class , In fact, we can directly use a semi official Money
class :JSR 354 , Although not in Java 9
To become Java
standard , It is likely to be integrated into subsequent Java
Become the official library in version .
2.1 maven
coordinate
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.1</version>
</dependency>
2.2 newly build Money
class
CurrencyUnit cny = Monetary.getCurrency("CNY");
Money money = Money.of(1.0, cny);
// perhaps Money money = Money.of(1.0, "CNY");
//System.out.println(money);
2.3 Amount calculation
CurrencyUnit cny = Monetary.getCurrency("CNY");
Money oneYuan = Money.of(1.0, cny);
Money threeYuan = oneYuan.add(Money.of(2.0, "CNY")); //CNY 3
Money tenYuan = oneYuan.multiply(10); // CNY 10
Money fiveFen = oneYuan.divide(2); //CNY 0.5
2.4 More equal
Money fiveFen = Money.of(0.5, "CNY"); //CNY 0.5
Money anotherFiveFen = Money.of(0.50, "CNY"); // CNY 0.50
System.out.println(fiveFen.equals(anotherFiveFen)); // true
You can see , This class abstracts the amount explicitly , Increase the unit of the amount , It also avoids direct use BigDecimal
Some pits .
边栏推荐
- R language plot visualization: plot visualization of multiple variable violin plot in R with plot
- 数学分析_笔记_第7章:多元函数的微分学
- PingCode 性能测试之负载测试实践
- La 18e Conférence internationale de l'IET sur le transport d'électricité en courant alternatif et en courant continu (acdc2022) s'est tenue avec succès en ligne.
- Face_recognition人脸识别之考勤统计
- Master the use of auto analyze in data warehouse
- 金额计算用 BigDecimal 就万无一失了?看看这五个坑吧~~
- 解决el-input输入框.number数字输入问题,去掉type=“number“后面箭头问题也可以用这种方法代替
- Interpretation of data security governance capability evaluation framework 2.0, the fourth batch of DSG evaluation collection
- VB cannot access database stocks
猜你喜欢
完美融入 Win11 风格,微软全新 OneDrive 客户端抢先看
解决el-input输入框.number数字输入问题,去掉type=“number“后面箭头问题也可以用这种方法代替
聊聊异步编程的 7 种实现方式
整理混乱的头文件,我用include what you use
解读数据安全治理能力评估框架2.0,第四批DSG评估征集中
kaili不能输入中文怎么办???
Hidden corners of coder Edition: five things that developers hate most
Solve the El input input box For number number input problem, this method can also be used to replace the problem of removing the arrow after type= "number"
被PMP考试“折磨”出来的考试心得,值得你一览
Wuzhicms code audit
随机推荐
To sort out messy header files, I use include what you use
What is low code development?
【华为HCIA持续更新】SDN与FVC
Solution of dealer collaboration system in building materials industry: empowering enterprises to build core competitiveness
Spark 中的 Rebalance 操作以及与Repartition操作的区别
Is it safe to open an account online
CANN算子:利用迭代器高效实现Tensor数据切割分块处理
shell脚本的替换功能实现
go-micro教程 — 第二章 go-micro v3 使用Gin、Etcd
Ks007 realizes personal blog system based on JSP
Implementation of super large-scale warehouse clusters in large commercial banks
解决el-input输入框.number数字输入问题,去掉type=“number“后面箭头问题也可以用这种方法代替
Hidden corners of coder Edition: five things that developers hate most
2022年国内云管平台厂商哪家好?为什么?
安信证券属于什么档次 开户安全吗
Congratulations to Mr. Zhang Pengfei, chief data scientist of artefact, for winning the campaign Asia tech MVP 2022
Rebalance operation in spark and its difference from repartition operation
Flask 轻量web框架
【Unity UGUI】ScrollRect 动态缩放格子大小,自动定位到中间的格子
【模板】【luogu P4630】Duathlon 铁人两项(圆方树)