# BigDecimal collection of Java scientific computing

## 1, The background of BigDecimal

First, let's look at the following code example:

```@Test
public void countDemo() {
logger.info("result:{}", 0.06 + 0.01);
logger.info("result:{}", 1.0 - 0.42);
logger.info("result:{}", 4.015 * 100);
logger.info("result:{}", 303.1 / 1000);
}
```

give the result as follows

```result:0.06999999999999999
result:0.5800000000000001
result:401.49999999999994
result:0.30310000000000004
```

What's the problem? The reason is that our computer is binary, floating-point numbers can not be accurately expressed in binary.

Java float can only be used for scientific computing or engineering computing. In most business computing, it is generally used java.math.BigDecimal Class to perform an exact calculation.

## 2, Using BigDecimal correctly

### 2.1 BigDecimal constant

BigDecimal defines several commonly used values, 0, 1, 10, which are static and can be directly referenced by class name, such as: BigDecimal.ZERO .

```/**
* The value 0, with a scale of 0.
*
* @since  1.5
*/
public static final BigDecimal ZERO =
zeroThroughTen[0];

/**
* The value 1, with a scale of 0.
*
* @since  1.5
*/
public static final BigDecimal ONE =
zeroThroughTen[1];

/**
* The value 10, with a scale of 0.
*
* @since  1.5
*/
public static final BigDecimal TEN =
zeroThroughTen[10];
```

### 2.2 construction method

BigDecimal has four common construction methods

1. new BigDecimal(int) creates an object with the integer value specified by the parameter;
2. new BigDecimal(double) creates an object with the double precision value specified by the parameter;
3. new BigDecimal(long) creates an object with a long integer value specified by the parameter;
4. new BigDecimal(String) creates an object with a string value specified by the parameter.

### 2.3 general steps of BigDecimal operation

When using the BigDecimal class for calculation, there are three main steps:

1. Use float or double variable to build BigDecimal object.
2. By calling the corresponding methods of BigDecimal, such as addition, subtraction, multiplication, division, etc., the arithmetic operation is carried out.
3. Convert BigDecimal object to float, double, int and other types.

## 3, Detailed explanation of common methods

In the general development process, the data stored in our database are of float and double types. I encapsulate a tool class, which provides add, subtract, multiply, divide, value up, value down and other operations.

### 3.1 ordinary addition, subtraction, multiplication and division

```/**
* Default division precision
*/
private static final int DEF_DIV_SCALE = 10;

/**
*
* @param v1 augend
* @param v2 Addend
* @return Sum of two parameters
*/
public static double add(Double v1, Double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
}

/**
* Accurate subtraction.
*
* @param v1 minuend
* @param v2 Subtraction
* @return Difference between two parameters
*/
public static double sub(Double v1, Double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.subtract(b2).doubleValue();
}

/**
* Precise multiplication.
*
* @param v1 Multiplier
* @param v2 multiplier
* @return Product of two parameters
*/
public static double mul(Double v1, Double v2) {
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.multiply(b2).doubleValue();
}

/**
* (Relative) accurate division operation. In case of inexhaustible division, the default precision is 10 digits after the decimal point, and the subsequent numbers are rounded.
*
* @param v1 Divisor
* @param v2 Divisor
* @return Quotient of two parameters
*/
public static double div(Double v1, Double v2) {
return div(v1, v2, DEF_DIV_SCALE, RoundingMode.HALF_UP);
}
```

### 3.2 rounding to accuracy or rounding up / down

```/**
* Round off the calculation results
*
* @param val
* @param scale accuracy
* @return For example, keep three decimal places: 0.646464 =] 0.646
*/
public static double roundHalfUp(double val, int scale) {
BigDecimal dec = BigDecimal.valueOf(val);
return dec.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}

/**
* Get the calculation result and round it up
*
* @param val   val
* @param scale accuracy
* @return For example, keep three decimal places: 0.646464 =] 0.647
*/
public static double roundUp(double val, int scale) {
BigDecimal dec = BigDecimal.valueOf(val);
return dec.setScale(scale, RoundingMode.UP).doubleValue();
}

/**
* Round down after getting the calculation results
*
* @param val   val
* @param scale accuracy
* @return For example, keep three decimal places: 0.646464 =] 0.646
*/
public static double roundDown(double val, int scale) {
BigDecimal dec = BigDecimal.valueOf(val);
return dec.setScale(scale, RoundingMode.DOWN).doubleValue();
}

/**
* Division plus rounding up.
*
* @param v1    Divisor
* @param v2    Divisor
* @param scale accuracy
* @return
*/
public static double divOfUp(Double v1, Double v2, int scale) {
return div(v1, v2, scale, RoundingMode.UP);
}

/**
* Division plus rounding down.
*
* @param v1    Divisor
* @param v2    Divisor
* @param scale accuracy
* @return
*/
public static double divOfDown(Double v1, Double v2, int scale) {
return div(v1, v2, scale, RoundingMode.DOWN);
}

/**
* Provides (relatively) accurate division operations. In case of inexhaustible division, the scale parameter specifies the precision and the roundingMode specifies the selection method.
*
* @param v1           Divisor
* @param v2           Divisor
* @param scale        Indicates that the representation needs to be accurate to several decimal places.
* @param roundingMode Specify the choice.
* @return Quotient of two parameters
*/
private static double div(double v1, double v2, int scale, RoundingMode roundingMode) {
//If the exact range is less than 0, an exception is thrown
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = BigDecimal.valueOf(v1);
BigDecimal b2 = BigDecimal.valueOf(v2);
return b1.divide(b2, scale, roundingMode).doubleValue();
}
```

### 3.3 if it happens to be divided by or multiplied by ten

Sometimes, for example, in the calculation of RMB cents / yuan / 10000, we just divide or multiply by 100 / 10000. In addition to addition and subtraction, BigDecimal provides a method to move the decimal point directly.

```/**
* Moves the decimal point to the right by a specified number of digits
*
* @param val   Multiplier
* @param index Move digits
* @return For example, move four decimal places to the right: 1000.01 =] 1000010.0
*/
public static double movePointRight(Double val, int index) {
BigDecimal value = BigDecimal.valueOf(val);
return value.movePointRight(index).doubleValue();
}

/**
* Moves the decimal point to the left by a specified number of digits
*
* @param val   Divisor
* @param index Move digits
* @return For example, move four decimal places to the left: 1000.01 = > 1.00001
*/
public static double movePointLeft(Double val, int index) {
BigDecimal value = BigDecimal.valueOf(val);
return value.movePointLeft(index).doubleValue();
}
```

### 3.4 BigDecimal size comparison

When comparing whether the values of two BigDecimal are equal, compareTo() method must be used to compare. It returns - 1, 1 and 0 respectively according to the size of the two values, representing less than, greater than and equal to.

```@Test
public void compareDecimal() {
BigDecimal v1 = BigDecimal.valueOf(1.21);
BigDecimal v2 = BigDecimal.valueOf(1.22);
BigDecimal v3 = BigDecimal.valueOf(1.22);
// -1: Less than, 1: greater than, 0: equal to
logger.info("result:{}", v1.compareTo(v2));
logger.info("result:{}", v2.compareTo(v1));
logger.info("result:{}", v2.compareTo(v3));
}
```

### 3.5BigDecimal accuracy is also lost

Carefully, you must have found that in the tool class, using BigDecimal's valueOf() to create objects, and the internal implementation of valueOf() is

```public static BigDecimal valueOf(double val) {
return new BigDecimal(Double.toString(val));
}
```

And the constructor uses new BigDecimal(String), because other problems, such as new BigDecimal(int)/new BigDecimal(long)/new BigDecimal(double), will still result in the loss of precision.

• Example
```@Test
public void precisionLose() {
BigDecimal v1 = new BigDecimal(1.01);
BigDecimal v2 = new BigDecimal(1.02);
BigDecimal v3 = new BigDecimal("1.01");
BigDecimal v4 = new BigDecimal("1.02");
// 2.0300000000000000266453525910037569701671600341796875
// 2.03
}
```

## 4, Summary

1. BigDecimal is used to express precise decimal, which is often used in financial calculation;

2. To compare whether the values of BigDecimal are equal, compareTo() must be used instead of equals().

#### [Github sample code]

More Java notes, see [Java knowledge notebook] , welcome to provide ideas and suggestions.

### Daily praise

1. Ancestral script Spring Boot sunflower classic Welcome to Tucao, and make complaints about open source.
2. nine men's power [Java knowledge notebook] Welcome to Tucao, and make complaints about open source.

The latest article, welcome to the public: the official account - the dust blog; the exchange of views, welcome to add: personal WeChat.

Posted on Wed, 17 Jun 2020 03:21:46 -0400 by pixy