# Interviewer: Will BigDecimal not lose accuracy?

Posted Jun 16, 20205 min read

Everyone knows that Double will lose precision, will BigDecimal not? Hope you will use it correctly!

Author:HikariCP

We have basically formed common sense that BigDecimal should be used wherever we need money, and we all know that floating-point variables will lose accuracy when they are calculated.

So, did you know that BigDecimal also loses precision? Is there anything worth exploring behind using BigDecimal? Today, I tell you, know what it is and why it is.

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);``````

Output:
0.060000000000000005
0.5800000000000001
401.49999999999994
1.2329999999999999

It can be seen that when performing floating-point arithmetic in Java, there will be a problem of loss of precision. Then if we are calculating commodity prices, there will be problems.

It is very likely that we have 0.06 yuan in our hands, but we cannot buy a product of 0.05 yuan and 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 concurrency of e-commerce websites goes up, the problem will be huge. It may result in the inability to place orders or problems with reconciliation. So we can use the BigDecimal class in Java to solve this kind of problem.

Popularize:

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

### API

Constructor:

``````Constructor Description
BigDecimal(int) creates an object with the integer value specified by the parameter.
BigDecimal(double) creates an object with the double value specified by the parameter.
BigDecimal(long) creates an object with the long integer value specified by the parameter.
BigDecimal(String) creates an object with a numeric value specified by a parameter as a string.``````

function:

``````Method Description
add(BigDecimal) The values   in the BigDecimal object are added, and then this object is returned.
subtract(BigDecimal) The value in the BigDecimal object is subtracted, and then this object is returned.
multiply(BigDecimal) Multiply the values   in the BigDecimal object, and then return this object.
divide(BigDecimal) Divides the value in the BigDecimal object, and then returns this object.
toString() Converts the value of the BigDecimal object to a string.
doubleValue() returns the value in the BigDecimal object as a double precision number.
floatValue() returns the value in the BigDecimal object as a single precision number.
longValue() returns the value in the BigDecimal object as a long integer.
intValue() returns the value in the BigDecimal object as an integer.``````

Due to general numeric types, for example double cannot accurately represent numbers above 16 digits.

### BigDecimal accuracy is also lost

When we use BigDecimal, it only makes sense to use its BigDecimal(String) constructor to create objects. Others, such as BigDecimal b = new BigDecimal(1), still have the problem of loss of precision. 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");

Output:
2.0300000000000000266453525910037569701671600341796875
2.03

It can be seen that the loss accuracy of BigDecimal is even more excessive. However, the variables that use BigDecimal's BigDecimal(String) constructor do not have this problem when performing operations.

The reason is that there are principles of computer composition, and their coding determines such a result.

Long can accurately store 19 digits, while double can only be prepared to store 16 digits.

Since double has exp bits, it can store more than 16 digits, but at the cost of inaccuracy of the lower bits. If you need more than 19 digits of accurate storage, you must use BigInteger to save, of course, some performance will be sacrificed.

So we generally use BigDecimal to solve the problem of loss of precision in business operations. When declaring BigDecimal objects, we must use its constructor with a parameter of type String.

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

And we have also given instructions from the comments of the source code. The following is a part of the comments on the constructor of the double type parameter of the BigDecimal class:

``````* The results of this constructor can be somewhat unpredictable.
One*mightassume that writing {@codenew BigDecimal(0.1)}in
Java*creates {@code BigDecimal} which is exactly equal to
0.1*(an unscaled value of 1, 1, with a scale of 1), but it is
**Actually equal to
* 0.1000000000000000055511151231257827021181583404541015625.
* This This is because 0.1 Cannot Be Represented exactly As As
{@Codedouble}(or, for that matter, as a binary, fraction, offraction ofof)``````

(*Anyfinite length).Thus, the value is that being passed
in to the constructor is not exactly equal to 0.1,
*Appearances notwithstanding.

``````* When When {@codedouble} must be used sourced for source
*{@Code BigDecimal}, note that that constructor provides anan
*Exact*conversion;it does not give the same result asas
*Converting {@codedouble} {@code\String} using the the
*{@Link Double#toString(double)} method and the using using the
*{@Link#BigDecimal(String)} constructor. To get that result,
**</ol>
public BigDecimal(double)val{{
This(val,MathContext.UNLIMITED);
}``````

The first paragraph also made 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 double type parameters to String type. And use the BigDecimal(String) construction method for construction. To get results.

### Proper use of BigDecimal

In addition, what BigDecimal creates is an object. We can't use traditional +, -, *,/and other arithmetic operators to directly perform mathematical operations on its objects, 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 are of type float and double. In the process of carrying out calculations, continuous conversion is required, which is very inconvenient. Here I wrote a tool class:

``````/**
*@Author:JiYongGuang.
*@Date:19:50 2017/12/14.
*//
publicclass 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));
}

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 == Two digits after the decimal point are kept ROUND_HALF_UP= Rounded off
Return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP); //respond to inexhaustible situations
}
}``````

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