当前位置:网站首页>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 :
BigDecimalThere are still many hidden pitsBigDecimalThe 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 .
边栏推荐
- What are cache penetration, cache breakdown, and cache avalanche
- 金额计算用 BigDecimal 就万无一失了?看看这五个坑吧~~
- [Acwing] 58周赛 4490. 染色
- 中信证券网上开户安全吗 开户收费吗
- New technology releases a small program UNIPRO to meet customers' mobile office scenarios
- Electronic pet dog - what is the internal structure?
- 【Go ~ 0到1 】 第六天 文件的读写与创建
- Is it safe for CITIC Securities to open an account online? Is the account opening fee charged
- Offline and open source version of notation -- comprehensive evaluation of note taking software anytype
- Master the use of auto analyze in data warehouse
猜你喜欢

VSCode修改缩进不成功,一保存就缩进四个空格

【Go ~ 0到1 】 第六天 文件的读写与创建

Master the use of auto analyze in data warehouse

Zhijieyun - meta universe comprehensive solution service provider

数学分析_笔记_第7章:多元函数的微分学

Ble HCI flow control mechanism

【Unity UGUI】ScrollRect 动态缩放格子大小,自动定位到中间的格子

What is low code development?

kaili不能输入中文怎么办???

第十八届IET交直流輸電國際會議(ACDC2022)於線上成功舉辦
随机推荐
整理混乱的头文件,我用include what you use
中银证券网上开户安全吗?
就在今天丨汇丰4位专家齐聚,共讨银行核心系统改造、迁移、重构难题
leetcode刷题目录总结
第十八届IET交直流输电国际会议(ACDC2022)于线上成功举办
The 18th IET AC / DC transmission International Conference (acdc2022) was successfully held online
斑马识别成狗,AI犯错的原因被斯坦福找到了丨开源
PingCode 性能测试之负载测试实践
智捷云——元宇宙综合解决方案服务商
R language plot visualization: plot visualization of multiple variable violin plot in R with plot
DataKit——真正的统一可观测性 Agent
Ks007 realizes personal blog system based on JSP
关于nacos启动时防火墙开启8848的坑
Solution of dealer collaboration system in building materials industry: empowering enterprises to build core competitiveness
The Ministry of human resources and Social Security announced the new construction occupation
整理混乱的头文件,我用include what you use
How to choose one plus 10 pro and iPhone 13?
Rainfall warning broadcast automatic data platform bwii broadcast warning monitor
太方便了,钉钉上就可完成代码发布审批啦!
金额计算用 BigDecimal 就万无一失了?看看这五个坑吧~~