Overview of BigDecimal
Java provides an API class, BigDecimal, in the java.math package to perform precise operations on numbers that are more than 16 significant bits. The double-precision floating-point variable double can handle 16-bit significant numbers, but in practice you may need to operate on larger or smaller numbers. In general, we can use Float and Double directly for numbers that do not require exact calculation accuracy, but double-.valueof (String) and float.valueof (String) lose precision. So in development, if we need exact computed results, we must use BigDecimal classes to do so.
BigDecimal creates objects, so we cannot use the traditional +, -, *, / arithmetic operators directly to perform mathematical operations on their objects, but must call their corresponding methods. The parameters in the method must also be objects of BigDecimal. Constructors are special methods of classes that are used to create objects, especially objects with parameters.
Common constructors for BigDecimal
2.1. Common constructors
- BigDecimal(int)
Creates an object with the integer value specified by the argument
- BigDecimal(double)
Creates an object with the double value specified by the argument
- BigDecimal(long)
Creates an object with the long integer value specified by the argument
- BigDecimal(String)
Creates an object with a string representation of the value specified by the argument
2.2 Analysis of usage problems
Example:
BigDecimal a = new BigDecimal (0.1); System.out.println("a values is:"+a); System.out.println("====================="); BigDecimal b = new BigDecimal (" 0.1 "); System.out.println("b values is:"+b);Copy the code
Example result:
A values is: 0.1000000000000000055511151231257827021181583404541015625 = = = = = = = = = = = = = = = = = = = = = b values is: 0.1Copy the code
Cause analysis:
1) The result of a constructor with type double is somewhat unpredictable. One might think that writing newBigDecimal(0.1) to Java creates BigDecimal exactly equal to 0.1 (the scale-off value of 1 is 1), But in fact it is equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, in this case, as any finite length binary decimal). Thus, the value passed into the constructor will not be exactly equal to 0.1 (although ostensibly equal to that value).
2) The String constructor is completely predictable: writing newBigDecimal(” 0.1 “) creates a BigDecimal, which is exactly equal to the expected 0.1. Therefore, it is generally recommended to use the String constructor in preference.
3) When double must be used as a source for BigDecimal, note that this constructor provides an exact conversion; It does not provide the same result as converting a Double to a String using the double-.tostring (Double) method and then the BigDecimal(String) constructor. To get the result, use the static valueOf(double) method.
Common methods for BigDecimal
3.1. Common methods
- add(BigDecimal)
Add the values in a BigDecimal object, returning a BigDecimal object
- subtract(BigDecimal)
Returns a BigDecimal object by subtracting the values in the BigDecimal object
- multiply(BigDecimal)
Returns a BigDecimal object by multiplying the values in it
- divide(BigDecimal)
A BigDecimal object is returned by dividing the values in it
- toString()
Converts the value in a BigDecimal object to a string
- doubleValue()
Converts the value in a BigDecimal object to a double
- floatValue()
Converts a value in a BigDecimal object to a single-precision number
- longValue()
Converts a value in a BigDecimal object to a long integer
- intValue()
Converts values in a BigDecimal object to integers
3.2 BigDecimal size comparison
In Java, bigdemical compareTo methods are commonly used to compare sizes for BigDecimal
int a = bigdemical.compareTo(bigdemical2)
Copy the code
Return result analysis:
A = -1, indicating that bigdemical is less than Bigdemical2; A = 0, bigdemical equals Bigdemical2; A = 1, indicating that bigdemical is greater than Bigdemical2;Copy the code
For example, A is greater than or equal to B
new bigdemica(a).compareTo(new bigdemical(b)) >= 0
Copy the code
BigDecimal formatting
Because the Format () method of the NumberFormat class can take a BigDecimal object as its argument, BigDecimal can be used to format and control monetary, hundredth, and general values beyond the 16-digit significant number.
Take the example of currency and percentage formatting using BigDecimal. First, you create BigDecimal objects, perform BigDecimal arithmetic operations, establish references to currency and percentage formatting, respectively, and finally print their formatted currency values and percentages using BigDecimal objects as arguments to the format() method.
NumberFormat currency = NumberFormat.getCurrencyInstance(); / / set up currency formatting references NumberFormat percent = NumberFormat. GetPercentInstance (); / / set up percentage format reference percent. SetMaximumFractionDigits (3); // Percentage up to 3 decimal places BigDecimal loanAmount = new BigDecimal("15000.48"); // Sum of money BigDecimal interestRate = new BigDecimal("0.008"); // decimal = loanAmount. Multiply (interestRate); Println (" loanAmount :\t" + currency. Format (loanAmount)); System.out. Println (" rate :\t" + rate. System.out.println(" interest :\t" + currency. Format (interest));Copy the code
Results:
Loan Amount: ¥15,000.48 Interest rate: 0.8% Interest rate: ¥120.00Copy the code
BigDecimal formats to retain 2 as a decimal or fill in 0 if not:
public class NumberFormat { public static void main(String[] s){ System.out.println(formatToNumber(new BigDecimal (" 3.435 "))); System.out.println(formatToNumber(new BigDecimal(0))); System. The out. Println (formatToNumber (new BigDecimal (" 0.00 "))); System. The out. Println (formatToNumber (new BigDecimal (" 0.001 "))); System. The out. Println (formatToNumber (new BigDecimal (" 0.006 "))); System. The out. Println (formatToNumber (new BigDecimal (" 0.206 "))); } /** * @desc A BigDecimal number between 1.0 and 1, which is preceded by 0 if it loses the preceding 0 after formatting. * 2. If the argument passed is 0, the string "0.00" * 3 is returned. The decimal number greater than 1, Direct formatting returns String * @param obj Passed decimal * @return */ public static String formatToNumber(BigDecimal obj) {DecimalFormat df = new DecimalFormat("#.00"); If (obj.com pareTo (BigDecimal. ZERO) = = 0) {return "0.00". }else if(obj.compareTo(BigDecimal.ZERO)>0&&obj.compareTo(new BigDecimal(1))<0){ return "0"+df.format(obj).toString(); }else { return df.format(obj).toString(); }}}Copy the code
The result is:
0.00 0.00 0.00 0.01 0.21Copy the code
Common exceptions for BigDecimal
5.1. Exceptions occur during division
java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result
Copy the code
Cause analysis:
Through BigDecimal divide method to divide when not divisible, infinite decimals, would throw exceptions: Java. Lang. ArithmeticException: Non – terminating a decimal expansion; no exact representable decimal result.
Solutions:
The divide method sets the exact decimal point, as in divide(XXXXX,2).
Summary of BigDecimal
6.1,
Use BigDecimal only when precise decimal calculations are required; BigDecimal performance is worse than double and float, especially for large, complex operations. There is no need to use BigDecimal for general-precision calculations. Use a String constructor whenever possible. BigDecimal is immutable, creating a new object for each of its four operations, so remember to store the value of the operation when adding, subtracting, multiplying and dividing.
6.2 Recommended Tool classes
package com.vivo.ars.util;
import java.math.BigDecimal;
/**
* 用于高精确处理常用的数学运算
*/
public class ArithmeticUtils {
//默认除法运算精度
private static final int DEF_DIV_SCALE = 10;
/**
* 提供精确的加法运算
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static double add(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.add(b2).doubleValue();
}
/**
* 提供精确的加法运算
*
* @param v1 被加数
* @param v2 加数
* @return 两个参数的和
*/
public static BigDecimal add(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2);
}
/**
* 提供精确的加法运算
*
* @param v1 被加数
* @param v2 加数
* @param scale 保留scale 位小数
* @return 两个参数的和
*/
public static String add(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供精确的减法运算
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static double sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
/**
* 提供精确的减法运算。
*
* @param v1 被减数
* @param v2 减数
* @return 两个参数的差
*/
public static BigDecimal sub(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.subtract(b2);
}
/**
* 提供精确的减法运算
*
* @param v1 被减数
* @param v2 减数
* @param scale 保留scale 位小数
* @return 两个参数的差
*/
public static String sub(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static double mul(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.multiply(b2).doubleValue();
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @return 两个参数的积
*/
public static BigDecimal mul(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.multiply(b2);
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @param scale 保留scale 位小数
* @return 两个参数的积
*/
public static double mul(double v1, double v2, int scale) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return round(b1.multiply(b2).doubleValue(), scale);
}
/**
* 提供精确的乘法运算
*
* @param v1 被乘数
* @param v2 乘数
* @param scale 保留scale 位小数
* @return 两个参数的积
*/
public static String mul(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
* 小数点以后10位,以后的数字四舍五入
*
* @param v1 被除数
* @param v2 除数
* @return 两个参数的商
*/
public static double div(double v1, double v2) {
return div(v1, v2, DEF_DIV_SCALE);
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示表示需要精确到小数点以后几位。
* @return 两个参数的商
*/
public static double div(double v1, double v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
* 定精度,以后的数字四舍五入
*
* @param v1 被除数
* @param v2 除数
* @param scale 表示需要精确到小数点以后几位
* @return 两个参数的商
*/
public static String div(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v1);
return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 提供精确的小数位四舍五入处理
*
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static double round(double v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException("The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(Double.toString(v));
return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
}
/**
* 提供精确的小数位四舍五入处理
*
* @param v 需要四舍五入的数字
* @param scale 小数点后保留几位
* @return 四舍五入后的结果
*/
public static String round(String v, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b = new BigDecimal(v);
return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 取余数
*
* @param v1 被除数
* @param v2 除数
* @param scale 小数点后保留几位
* @return 余数
*/
public static String remainder(String v1, String v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
}
/**
* 取余数 BigDecimal
*
* @param v1 被除数
* @param v2 除数
* @param scale 小数点后保留几位
* @return 余数
*/
public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {
if (scale < 0) {
throw new IllegalArgumentException(
"The scale must be a positive integer or zero");
}
return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);
}
/**
* 比较大小
*
* @param v1 被比较数
* @param v2 比较数
* @return 如果v1 大于v2 则 返回true 否则false
*/
public static boolean compare(String v1, String v2) {
BigDecimal b1 = new BigDecimal(v1);
BigDecimal b2 = new BigDecimal(v2);
int bj = b1.compareTo(b2);
boolean res;
if (bj > 0)
res = true;
else
res = false;
return res;
}
}
Copy the code
Write here, all finished reading point a “like” plus a concern is not too much bar everyone see officer gentlemen!
Previous hot articles:
- Summary of Java basic knowledge
- Performance Tuning Series topics (JVM, MySQL, Nginx, and Tomcat)
- From being kicked out to 5 offers of 30K+, I have come a long way
- 100 Java project parsing, with source code and learning documentation!