[Transfer] How much do you know about the BigDecimal class in Java?

foreword

We all know that floating-point variables will lose precision when performing calculations. The following piece of code:

System.out.println(0.05 + 0.01); System.out.println(1.0 - 0.42); System.out.println(4.015 * 100); System.out.println(123.3 / 100); 输出: 0.060000000000000005 0.5800000000000001 401.49999999999994 1.2329999999999999 

It can be seen that when floating-point operations are performed in Java, there will be a problem of loss of precision. Then if we calculate the commodity price, there will be problems. It is very likely that we have 0.06 yuan in our hands, but we cannot buy a commodity of 0.05 yuan and a commodity of 0.01 yuan. Because as shown above, the sum of the two of them is 0.060000000000000005. This is undoubtedly a very serious problem, especially when the concurrent volume of e-commerce websites increases, the problems that will arise will be huge. It may result in the inability to place an order, or problems with reconciliation. So then we can use the BigDecimal class in Java to solve this kind of problem.

Popularize it:

The precision of float in Java is 6-7 significant figures. double has a precision of 15-16 digits.

API

Constructor:

构造器                   描述BigDecimal(int)       创建一个具有参数所指定整数值的对象。      
  BigDecimal(double) 创建一个具有参数所指定双精度值的对象。 BigDecimal(long) 创建一个具有参数所指定长整数值的对象。 BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。 

function:

方法                    描述add(BigDecimal)       BigDecimal对象中的值相加,然后返回这个对象。
  subtract(BigDecimal) BigDecimal对象中的值相减,然后返回这个对象。 multiply(BigDecimal) BigDecimal对象中的值相乘,然后返回这个对象。 divide(BigDecimal) BigDecimal对象中的值相除,然后返回这个对象。 toString() 将BigDecimal对象的数值转换成字符串。 doubleValue() 将BigDecimal对象中的值以双精度数返回。 floatValue() 将BigDecimal对象中的值以单精度数返回。 longValue() 将BigDecimal对象中的值以长整数返回。 intValue() 将BigDecimal对象中的值以整数返回。 

Due to the general numerical type, such as double, it cannot accurately represent numbers with more than 16 bits.

BigDecimal precision is also lost

When we use BigDecimal, it only makes sense to use its BigDecimal(String) constructor to create objects. For others such as BigDecimal b = new BigDecimal(1), the problem of loss of precision will still occur. The following code:

BigDecimal a = new BigDecimal(1.01); BigDecimal b = new BigDecimal(1.02); BigDecimal c = new BigDecimal("1.01"); BigDecimal d = new BigDecimal("1.02"); System.out.println(a.add(b)); System.out.println(c.add(d)); 输出: 2.0300000000000000266453525910037569701671600341796875 2.03 

It can be seen that the loss of precision BigDecimal is even more excessive. However, this problem does not occur when variables using Bigdecimal's BigDecimal(String) constructor perform operations. The reason is contained in the composition principles of computers, and their encoding determines such a result. long can store exactly 19 digits, while double is only prepared to store 16 digits. Due to the exp bit, double can store numbers with more than 16 bits, but at the cost of low-bit inaccuracy. If you need accurate storage of numbers higher than 19, you must use BigInteger to save, of course, some performance will be sacrificed. Therefore, when we generally use BigDecimal to solve the problem of loss of precision in business operations, when declaring a BigDecimal object, we must use its constructor whose parameter is String.

At the same time, this principle is also mentioned in Effective Java and MySQL. float and double can only be used for scientific and engineering calculations. We use BigDecimal in business operations.

Moreover, we have also given an official explanation from the source code comments. The following is a part of the comment explanation on the constructor of the double type parameter of the BigDecimal class:

* The results of this constructor can be somewhat unpredictable.
     * One might assume that writing { 
            

The first paragraph also makes it clear that it can only calculate infinitely close to this number, but it cannot be accurate to this number. The second paragraph says that if you want to calculate this value accurately, you need to convert the parameter of type double to type String. And use the BigDecimal(String) construction method to construct. to get the result.

Correct use of BigDecimal

In addition, what BigDecimal creates is an object, we cannot use traditional arithmetic operators such as +, -, *, / to directly perform mathematical operations on its object, but must call its corresponding method. The parameters in the method must also be BigDecimal objects, as can be seen from the API we just listed.

In the general development process, the data stored in our database is of type float and double. It is very inconvenient to continue to convert when performing calculations. Here I wrote a utility class:

/**
 * @author: Ji YongGuang.
 * @date: 19:50 2017/12/14.
 */
public class BigDecimalUtil { private BigDecimalUtil() { } public static BigDecimal add(double v1, double v2) { 
                            // v1 + v2 BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2); } public static BigDecimal sub(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 mul(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 div(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); // 2 = 保留小数点后两位 ROUND_HALF_UP = 四舍五入 return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);// 应对除不尽的情况 } } 

This tool class provides basic addition, subtraction, multiplication and division operations of the double type. Just call it directly.


Author: HikariCP
Link: https://www.jianshu.com/p/c81edc59546c
Source: Jianshu
The copyright belongs to the author. For commercial reprint, please contact the author for authorization, for non-commercial reprint, please indicate the source.

Guess you like

Origin blog.csdn.net/m0_53121042/article/details/114847142