目录
1、为什么要用
BigDecimal
?
工作中我们通过
浮点
数进行运算时,好像时不时的会出现一些小误差。例如:
public class Text04 {
public static void main(String[] args) {
System.out.println(1.9 - 1.2);
System.out.println(1.9 - 1.5);
System.out.println(100 - 99.8);
}
}
计算结果:
0.7
0.3999999999999999
0.20000000000000284
网上说我们的计算机是二进制的,而浮点数是没有办法通过二进制精准的表示出来。也就导致在运算的时候,float类型和double类型很容易丢失精度。
所以在开发中,如果我们需要精确计算的结果,可以使用java.math包中提供的BigDecimal类来进行操作。
2、BigDecimal初始化赋值
方法 | 类型 | 描述 |
public BigDecimal(int val) | 构造函数 | int类型的值生成BigDecimal对象 |
public BigDecimal(long val) | 构造函数 | long类型的值生成BigDecimal对象 |
public BigDecimal(String val) | 静态方法 | String类型的值转换为BigDecimal类型 |
public static BigDecimal valueOf(double val) | 静态方法 | double类型的值转换为BigDecimal类型 |
public static BigDecimal valueOf(long val) | 静态方法 | long类型(包含int类型)的值转换为BigDecimal类型 |
- 代码示例:
BigDecimal b = new BigDecimal("33");
BigDecimal c = BigDecimal.valueOf(4.7);
3.
BigDecimal
的加减乘除绝对值
运算法则 | 对应方法 |
---|---|
加法 | public BigDecimal add(BigDecimal value) |
减法 | public BigDecimal subtract(BigDecimal value) |
乘法 | public BigDecimal multiply(BigDecimal value) |
除法 | public BigDecimal divide(BigDecimal value) |
- 代码示例:
import java.math.BigDecimal;
/**
* 2022年6月1日 wyd
*/
public class Text01 {
public static void main(String[] args) {
BigDecimal num1 = new BigDecimal (9);
BigDecimal num2 = new BigDecimal (11);
//加法
BigDecimal result1 = num1.add(num2);
System.out.println(result1);
//减法
BigDecimal result2 = num1.subtract(num2);
System.out.println(result2);
//乘法
BigDecimal result3 = num1.multiply(num2);
System.out.println(result3);
//绝对值
BigDecimal result4 = num2.abs();
System.out.println(result4);
//BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
//除法 (BigDecimal divisor 除数, int scale 精确小数位, int roundingMode 舍入模式)
BigDecimal result5 = num2.divide(num1,10,BigDecimal.ROUND_HALF_UP);
System.out.println(result5);
}
}
- 输出结果:
加:20
减:-2
乘:99
绝:11
除:1.2222222222
- 注意1:BigDecimal的运算结果都是返回了一个新的BigDecimal对象,并不是在原有的对象上进行操作。
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(5);
System.out.println("a的地址:" + System.identityHashCode(a));
a = a.add(BigDecimal.valueOf(3));
System.out.println("计算后a的地址:" + System.identityHashCode(a));
}
a的地址:356573597
计算后a的地址:1735600054
- 注意2:使用divide除法函数除不尽,出现无线循环小数的时候,就需要使用另外精确的小数位数以及舍入模式,不然会出现报错。例如:
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(10), b = BigDecimal.valueOf(3);
System.out.println(a.divide(b));
}
// 该程序运行会出现以下错误
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1690)
at Text04.main(Text04.java:20)
解决方法如下(此处舍入模式使用四舍五入的方式,其他模式在该文章后面有讲解):
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(10), b = BigDecimal.valueOf(3);
System.out.println(a.divide(b, 3, BigDecimal.ROUND_HALF_UP));
}
// 该程序运行后输出:
3.33
4.
BigDecimal
比较大小
首先得先理解
compareTo :
BigDecimal类提供的比较值的方法,
注意比较的两个值均不能为空
。
a.compareTo(b)得到结果 1, 0, -1。
比较结果 | 描述 |
---|---|
1 | a 大于b |
0 | a 等于b |
-1 | a 小于b |
因此得到结论:
如果第一个参数与第二个参数相等返回0。
如果第一个参数小于第二个参数返回 -1。
如果第一个参数大于第二个参数返回 1。
- 代码示例:
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(1);
BigDecimal b = BigDecimal.valueOf(2);
BigDecimal c = BigDecimal.valueOf(1);
BigDecimal d = BigDecimal.ZERO;
System.out.println("1和2比较结果:" + a.compareTo(b));
System.out.println("1和1比较结果:" + a.compareTo(c));
System.out.println("1和0比较判断:" + (a.compareTo(d) > 0) );
}
- 输出结果:
1和2比较结果:-1
1和1比较结果:0
1和0比较判断:true
5、
BigDecimal
与零比较大小
- 代码示例
import java.math.BigDecimal;
/**
* 2022年6月1日 wyd
*
* 如果第一个参数与第二个参数相等返回0。
*
* 如果第一个参数小于第二个参数返回 -1。
*
* 如果第一个参数大于第二个参数返回 1。
*/
public class Text03 {
public static void main(String[] args) {
BigDecimal bigDecimal = new BigDecimal("100");
if(bigDecimal.compareTo(BigDecimal.ZERO)==-1){
//bigDecimal小于0
System.out.println("bigDecimal小于0");
}
if(bigDecimal.compareTo(BigDecimal.ZERO)==0){
//bigDecimal等于0
System.out.println("bigDecimal等于0");
}
if(bigDecimal.compareTo(BigDecimal.ZERO) == 1){
//bigDecimal大于0
System.out.println("bigDecimal大于0");
}
}
}
- 输出结果:
bigDecimal大于0
6、BigDecimal其他方法及常量
代码 | 类型 | 描述 |
---|---|---|
BigDecimal.ZERO | 常量 | 初始化一个为0的BigDecimal对象 |
BigDecimal.ONE | 常量 | 初始化一个为1的BigDecimal对象 |
BigDecimal.TEN | 常量 | 初始化一个为10的BigDecimal对象 |
public BigDecimal abs() | 方法 | 求绝对值,不管正数还是负数,都得到正数 |
public BigDecimal negate() | 方法 | 求相反数,正变负,负变正 |
public BigDecimal pow(int n) | 方法 | 求乘方,如BigDecimal.valueOf(2).pow(3)的值为8 |
public BigDecimal max(BigDecimal val) | 方法 | 两值比较,返回最大值 |
public BigDecimal min(BigDecimal val) | 方法 | 两值比较,返回最小值 |
7、BigDecimal保留两位小数及舍入模式
用于格式化小数的方法,第一个值表示保留几位小数,第二个值表示格式化的类型。
格式化类型 | 描述 |
---|---|
ROUND_DOWN | 舍弃多余位数,如1.55会格式化为1.5,-1.55会格式化为-1.5 |
ROUND_UP | 进位处理,如1.52会格式化为1.6,-1.52会格式化为-1.6 |
ROUND_HALF_UP |
四舍五入,如果舍弃部分 >= .5 ,则进位 |
ROUND_HALF_DOWN |
五舍六入,如果舍弃部分 > .5 ,则进位 |
ROUND_CEILING | 正无穷大方向舍入模式。如果值为正数,则与ROUND_UP模式相同;如果值为负数,则与ROUND_DOWN模式相同 |
ROUND_FLOOR | 负无穷大方向舍入模式。如果值为正数,则与ROUND_DOWN模式相同;如果值为负数,则与ROUND_UP模式相同 |
ROUND_UNNECESSARY | 确认值的小数位数是否与传入第一个参数(保留小数的位数)相等,如果符合则返回值,如果不符抛出异常 |
ROUND_HALF_EVEN | 如果舍弃部门左边的数字为奇数,则与ROUND_HALF_UP模式相同,如果为偶数则与ROUND_HALF_DOWN模式相同 |
- 代码示例:
public static void main(String[] args) {
BigDecimal a = BigDecimal.valueOf(5.445);
System.out.println("5.445舍弃多余位数:" + a.setScale(2, BigDecimal.ROUND_DOWN));
System.out.println("5.445进位处理:" + a.setScale(2, BigDecimal.ROUND_UP));
System.out.println("5.445四舍五入(舍弃部分>= .5,进位):" + a.setScale(2, BigDecimal.ROUND_HALF_UP));
System.out.println("5.445四舍五入(舍弃部分未> .5,舍弃):" + a.setScale(2, BigDecimal.ROUND_HALF_DOWN));
System.out.println("5.446四舍五入(舍弃部分> .5,进位):" + BigDecimal.valueOf(5.446).setScale(2, BigDecimal.ROUND_HALF_DOWN));
}
- 输出结果:
5.445舍弃多余位数:5.44
5.445进位处理:5.45
5.445四舍五入(舍弃部分>= .5,进位):5.45
5.445四舍五入(舍弃部分未> .5,舍弃):5.44
5.446四舍五入(舍弃部分> .5,进位):5.45