当前位置:网站首页>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-03 11:55:00 【Java confidant_】
I saw an article last week because it was 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 .
recommend
Technical involution group , Learn together !!

PS: Because the official account platform changed the push rules. , If you don't want to miss the content , Remember to click after reading “ Looking at ”, Add one “ Star standard ”, In this way, each new article push will appear in your subscription list for the first time . spot “ Looking at ” Support us !
边栏推荐
- Understand go language context in one article
- R language uses grid of gridextra package The array function combines multiple visual images of the ggplot2 package horizontally, and the ncol parameter defines the number of columns of the combined g
- previous permutation lintcode51
- (database authorization - redis) summary of unauthorized access vulnerabilities in redis
- The world's most popular font editor FontCreator tool
- Excel表格转到Word中,表格不超边缘纸张范围
- typeScript
- rxjs Observable filter Operator 的实现原理介绍
- Uniapp implementation Click to load more
- Excel quick cross table copy and paste
猜你喜欢

量化计算调研

【学习笔记】dp 状态与转移

Groovy test class and JUnit test

Solution to the second weekly test of ACM intensive training of Hunan Institute of technology in 2022

外插散点数据

STL tutorial 10 container commonalities and usage scenarios

The world's most popular font editor FontCreator tool

Excel quick cross table copy and paste

Modular programming of single chip microcomputer

"Jianzhi offer 04" two-dimensional array search
随机推荐
P3250 [hnoi2016] Network + [necpc2022] f.tree path tree section + segment tree maintenance heap
Yintai department store ignites the city's "night economy"
R language uses data The table package performs data aggregation statistics, calculates window statistics, calculates the median of sliding groups, and merges the generated statistical data into the o
优化接口性能
Mmc5603nj geomagnetic sensor (Compass example)
Unity3D学习笔记5——创建子Mesh
mysql使用update联表更新的方法
ArcGIS应用(二十一)Arcmap删除图层指定要素的方法
C language utf8toutf16 (UTF-8 characters are converted to hexadecimal encoding)
Excel quick cross table copy and paste
AI模型看看视频,就学会了玩《我的世界》:砍树、造箱子、制作石镐样样不差...
牛牛的组队竞赛
Master and backup role election strategy in kept
libvirt 中体验容器
"Jianzhi offer 04" two-dimensional array search
Unity3d learning notes 5 - create sub mesh
Wrong arrangement (lottery, email)
R语言使用原生包(基础导入包、graphics)中的hist函数可视化直方图(histogram plot)
R语言使用gridExtra包的grid.arrange函数将ggplot2包的多个可视化图像横向组合起来,ncol参数自定义组合图列数、nrow参数自定义组合图行数
Groovy test class and JUnit test