java中的BigDecimal使用
Posted CUIYD_1989
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java中的BigDecimal使用相关的知识,希望对你有一定的参考价值。
文章目录
1、什么是BigDecimal?
BigDecimal属于java.math
包,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。
float和double只能用来做科学计算或者是工程计算,在商业计算中(如金融行业)要用java.math.BigDecimal。
BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算
,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
2、为什么使用BigDecimal?
我们看如下代码:
public static void main(String[] args) throws Exception
System.out.println(0.2 + 0.1);
System.out.println(0.3 - 0.1);
System.out.println(0.2 * 0.1);
System.out.println(0.3 / 0.1);
打印结果:
为何会这样?
原因:不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。
根本原因:十进制值通常没有完全相同的二进制表示形式;十进制数的二进制表示形式可能不精确。只能无限接近于那个值。
但是,在项目中,我们不可能让这种情况出现,特别是金融项目,因为涉及金额的计算都必须十分精确,否则,如果你的微信账户余额显示193.99999999999998,那是一种怎么样的体验?
3、如何使用BigDecimal?
(1)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("25");
BigDecimal c = new BigDecimal(12);
System.out.println(b);
System.out.println(c);
打印结果:
注意:不建议使用public BigDecimal(double val)方式初始化值
如下代码:
BigDecimal c = new BigDecimal(12.3);
System.out.println(c);
打印结果:
如图,也会出现计算的错误。
通常建议优先使用String构造方法。当double必须用作BigDecimal的源时,请使用Double.toString(double)转成String,然后使用String构造方法,或使用BigDecimal的静态方法valueOf:
BigDecimal b = new BigDecimal("12.3");
BigDecimal c = BigDecimal.valueOf(7.34325);
BigDecimal d = new BigDecimal(Double.toString(7.34325));
System.out.println(b);
System.out.println(c);
System.out.println(d);
打印结果:
(2)加减乘除运算
运算法则 | 对应方法 | |
---|---|---|
加法 | public BigDecimal add(BigDecimal value) | |
减法 | public BigDecimal subtract(BigDecimal value) | |
乘法 | public BigDecimal multiply(BigDecimal value) | |
除法 | public BigDecimal divide(BigDecimal value) |
代码示例:
public static void main(String[] args) throws Exception
System.out.println("计算加法: " + BigDecimal.valueOf(1.9).add(BigDecimal.valueOf(0.2)));
System.out.println("计算减法: " + BigDecimal.valueOf(1.9).subtract(BigDecimal.valueOf(1.5)));
System.out.println("计算乘法: " + BigDecimal.valueOf(1.9).multiply(BigDecimal.valueOf(0.2)));
System.out.println("计算除法: " + BigDecimal.valueOf(1.9).divide(BigDecimal.valueOf(0.2)));
打印结果:
注意点:
- BigDecimal的运算结果都是返回了一个新的BigDecimal对象,并不是在原有的对象上进行操作。
代码示例:
public static void main(String[] args)
BigDecimal bigDecimal = new BigDecimal("2");
System.out.println("bigDecimal计算前的地址是:"+System.identityHashCode(bigDecimal));
bigDecimal = bigDecimal.add(BigDecimal.valueOf(3));
System.out.println("bigDecimal计算后的地址是:"+System.identityHashCode(bigDecimal));
打印结果:
- 使用divide除法函数除不尽,出现无线循环小数的时候,就需要使用另外精确的小数位数以及舍入模式,不然会出现报错。
代码示例:
public static void main(String[] args)
BigDecimal a = BigDecimal.valueOf(10), b = BigDecimal.valueOf(3);
System.out.println(a.divide(b));
报错如下:
解决方法可以采用四舍五入的方式,详情见下文!
(3)BigDecimal保留两位小数及舍入模式
public BigDecimal setScale(int newScale, int roundingMode)
用于格式化小数的方法,第一个值表示保留几位小数,第二个值表示格式化的类型。
8种类型如下:
格式化类型 | 描述 | |
---|---|---|
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));
打印结果:
(4)BigDecimal比较大小
public int compareTo(BigDecimal val)
BigDecimal类提供的比较值的方法,注意比较的两个值均不能为空。
a.compareTo(b)得到结果 1, 0, -1。
比较结果 | 描述 | |
---|---|---|
1 | a 大于b | |
0 | a 等于b | |
-1 | a 小于b |
代码示例:
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) );
打印结果:
注意:实际业务中,不会单纯的比较谁打谁小,而是类似于第三条去判断一个布尔值。
(5)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) | 方法 | 两值比较,返回最小值 |
货币金额-Java中的BigDecimal
对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算的结果,则必须使用BigDecimal类,而且使用BigDecimal类也可以进行大数的操作。
float和double只能用来做科学计算或者是工程计算,在商业计算中金额我们要用 java.math.BigDecimal。
表11-15 BigDecimal类的常用方法
序号 |
方 法 |
类型 |
描 述 |
1 |
public BigDecimal(double val) |
构造 |
将double表示形式转换 为BigDecimal |
2 |
public BigDecimal(int val) |
构造 |
将int表示形式转换为 BigDecimal |
3 |
public BigDecimal(String val) |
构造 |
将字符串表示 形式转换为BigDecimal |
4 |
public BigDecimal add(BigDecimal augend) |
普通 |
加法 |
5 |
public BigDecimal subtract(BigDecimal |
普通 |
减法 |
6 |
public BigDecimal multiply(BigDecimal |
普通 |
乘法 |
7 |
public BigDecimal divide(BigDecimal |
普通 |
除法 |
BigDecimal的计算
金额的计算BigDecimal类 double d = 9.84; double d2 = 1.22; //注意需要使用BigDecimal(String val)构造方法 BigDecimal bigDecimal = new BigDecimal(Double.toString(d)); BigDecimal bigDecimal2 = new BigDecimal(Double.toString(d2)); //加法 BigDecimal bigDecimalAdd = bigDecimal.add(bigDecimal2); double add = bigDecimalAdd.doubleValue(); //减法 BigDecimal bigDecimalSubtract = bigDecimal.subtract(bigDecimal2); double subtract = bigDecimalSubtract.doubleValue(); //乘法 BigDecimal bigDecimalMultiply = bigDecimal.multiply(bigDecimal2); double multiply = bigDecimalMultiply.doubleValue(); //除法 int scale = 2;//保留2位小数 BigDecimal bigDecimalDivide = bigDecimal.divide(bigDecimal2, scale, BigDecimal.ROUND_HALF_UP); double divide = bigDecimalDivide.doubleValue(); //格式化 double format = 12343171.6; //获取常规数值格式 NumberFormat number = NumberFormat.getNumberInstance(); String str = number.format(format);//12,343,171.6 //获取整数数值格式 NumberFormat integer = NumberFormat.getIntegerInstance(); str = integer.format(format);//如果带小数会四舍五入到整数12,343,172 //获取货币数值格式 NumberFormat currency = NumberFormat.getCurrencyInstance(); currency.setMinimumFractionDigits(2);//设置数的小数部分所允许的最小位数(如果不足后面补0) currency.setMaximumFractionDigits(4);//设置数的小数部分所允许的最大位数(如果超过会四舍五入) str = currency.format(format);//¥12,343,171.60 //获取显示百分比的格式 NumberFormat percent = NumberFormat.getPercentInstance(); percent.setMinimumFractionDigits(2);//设置数的小数部分所允许的最小位数(如果不足后面补0) percent.setMaximumFractionDigits(3);//设置数的小数部分所允许的最大位数(如果超过会四舍五入) str = percent.format(format);//1,234,317,160.00%
System.out.println(new BigDecimal(0.1).toString()); // 0.1000000000000000055511151231257827021181583404541015625
System.out.println(new BigDecimal("0.1").toString()); // 0.1
System.out.println(new BigDecimal(
Double.toString(0.1000000000000000055511151231257827021181583404541015625)).toString());// 0.1
System.out.println(new BigDecimal(Double.toString(0.1)).toString()); // 0.1
分析一下上面代码的问题(注释的内容表示此语句的输出)
int x=(int)1023.99999999999999; // x=1024为什么?
原因还是在于二进制无法精确地表示某些十进制小数,因此1023.99999999999999在编译之后的double值变成了1024。
double d = 1023.99999999999999;
int x = (int) d;
System.out.println(new BigDecimal(d).toString()); // 1024
System.out.println(Long.toHexString(Double.doubleToRawLongBits(d))); // 4090000000000000
System.out.println(x); // 1024
前面提过BigDecimal可以精确地把double表示出来还记得吧。
以上是关于java中的BigDecimal使用的主要内容,如果未能解决你的问题,请参考以下文章