当前位置:网站首页>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 14:48:00 【Hollis Chuang】
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.331.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.00Don'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.52.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 .
End
My new book 《 In depth understanding of Java The core technology 》 It's on the market , After listing, it has been ranked in Jingdong best seller list for several times , At present 6 In the discount , If you want to start, don't miss it ~ Long press the QR code to buy ~

Long press to scan code and enjoy 6 A discount
Previous recommendation
B The station was scolded on the hot search ..
There is Tao without skill , It can be done with skill ; No way with skill , Stop at surgery
Welcome to pay attention Java Road official account

Good article , I was watching ️
边栏推荐
- 【云原生】我怎么会和这个数据库杠上了?
- 92. (cesium chapter) cesium building layering
- (1)性能调优的标准和做好调优的正确姿势-有性能问题,上HeapDump性能社区!
- LVGL 8.2 Line
- How to match chords
- [C language] Pointer written test questions
- 炒股网上开户安全吗?会不会被骗。
- MySQL triggers
- First experience of ViewModel
- Why do domestic mobile phone users choose iPhone when changing a mobile phone?
猜你喜欢

Digi重启XBee-Pro S2C生产,有些差别需要注意
![LeetCode 1200 最小絕對差[排序] HERODING的LeetCode之路](/img/4a/6763e3fbdeaf9de673fbe8eaf96858.png)
LeetCode 1200 最小絕對差[排序] HERODING的LeetCode之路

LVGL 8.2 text shadow

Expose Ali's salary and position level

Kubernets Pod 存在 Finalizers 一直处于 Terminating 状态

Node mongodb installation

Why do domestic mobile phone users choose iPhone when changing a mobile phone?

Leetcode 61: rotating linked list

Digi XBee 3 RF: 4个协议,3种封装,10个大功能

Data center concept
随机推荐
Redis daily notes
C language book rental management system
Expose Ali's salary and position level
[information retrieval] experiment of classification and clustering
Leetcode T48: rotating images
Sqlserver functions, creation and use of stored procedures
92. (cesium chapter) cesium building layering
内存管理总结
The implementation of OSD on rk1126 platform supports color translucency and multi-channel support for Chinese
Real time data warehouse
Query optimizer for SQL optimization
Programmer turns direction
【C语言】指针笔试题
flink sql-client. SH tutorial
关于FPGA底层资源的细节问题
Data center concept
Wt588f02b-8s (c006_03) single chip voice IC scheme enables smart doorbell design to reduce cost and increase efficiency
A keepalived high availability accident made me learn it again
第十六章 字符串本地化和消息字典(二)
Opencv learning notes - linear filtering: box filtering, mean filtering, Gaussian filtering


