文章目录
前几天在进行计算操作的时候发生了精度丢失的问题,就查了一下防止精度丢失的办法:BigDecimal;了解之后感觉BigDecimal还是很有意思的,就总结一下:
1、创建一个BigDecimal对象
1.1、常用构造函数
构造器:
构造方法 | 描述 |
---|---|
BigDecimal(int) | 创建一个具有参数所指定整数值的对象。 |
BigDecimal(double) | 创建一个具有参数所指定双精度值的对象。 |
BigDecimal(long) | 创建一个具有参数所指定长整数值的对象 |
BigDecimal(String) | 创建一个具有参数所指定以字符串表示的数值的对象。 |
// int
BigDecimal bigDecimal1 = new BigDecimal(1);
// double
BigDecimal bigDecimal2 = new BigDecimal(0.1);
// long
BigDecimal bigDecimal3 = new BigDecimal(100L);
// String
BigDecimal bigDecimal4= new BigDecimal("0.1");
System.out.println(bigDecimal1);
System.out.println(bigDecimal2);
System.out.println(bigDecimal3);
System.out.println(bigDecimal4);
输出结果:
这里可以看到用double类型的数据去创建BigDecimal 的结果不一样:
其实这也就是我们使用double来进行计算的时候会出现精度丢失的原因,十进制转二进制的时候有些十进制数是无法使用一个有限的二进制数来表达的,换言之就是转换的时候出现了精度的丢失问题,所以说BigDecimal(double)这个构造的结果是不可预知的;
与BigDecimal(double)相比,BigDecimal(String)就是完全符合我们预期的,所以通常都推荐用BigDecimal(String);
1.1、常用计算方法
方法 | 描述 |
---|---|
add(BigDecimal) | BigDecimal对象中的值相加,然后返回这个对象。 |
subtract(BigDecimal) | BigDecimal对象中的值相减,然后返回这个对象。 |
multiply(BigDecimal) | BigDecimal对象中的值相乘,然后返回这个对象。 |
divide(BigDecimal) | BigDecimal对象中的值相除,然后返回这个对象。 |
toString() | 将BigDecimal对象的数值转换成字符串。 |
doubleValue() | 将BigDecimal对象中的值以双精度数返回。 |
floatValue() | 将BigDecimal对象中的值以单精度数返回 |
BigDecimal zero1 = new BigDecimal("1.5");
BigDecimal zero2 = new BigDecimal("0.5");
BigDecimal zero3 = new BigDecimal("5");
// 加
System.out.println(zero1.add(zero2));
// 减
System.out.println(zero1.subtract(zero2));
// 乘
System.out.println(zero1.multiply(zero2));
// 除
System.out.println(zero1.divide(zero2));
System.out.println(zero3.toString());
System.out.println(zero3.doubleValue());
System.out.println(zero3.floatValue());
结果:
2、BigDecimal很方便的几个用法
2.1、用BigDecimal去除小数点后多余的0:stripTrailingZeros()
用BigDecimal计算会生成多余的0,比如下面:
System.out.println(new BigDecimal("2.0").multiply(new BigDecimal("1.0")));
结果:
// 去除多余的0
System.out.println(new BigDecimal("2.0").multiply(new BigDecimal("1.0")).stripTrailingZeros());
结果:
2.2、BigDecimal的原值和科学计数值
当我们使用上面的stripTrailingZeros()时,有时候会出现一些问题。比如我有一个数值是10.0000000000000,我用stripTrailingZeros()想去除多余的0:
System.out.println( new BigDecimal("10.0000000000000").stripTrailingZeros());
结果:
或者在进行一些运算的时候,比如0/0.5,0除以任何数都应该是0:
System.out.println(new BigDecimal("0").divide(new BigDecimal("0.05")));
这其实并不是出了问题,而是科学计数值;如果我们不行输出科学计数值,可以用toPlainString()输出原值:;
System.out.println("科学计数值:" + new BigDecimal("0").divide(new BigDecimal("0.05")));
System.out.println("原值:" + new BigDecimal("0").divide(new BigDecimal("0.05")).toPlainString());
System.out.println("科学计数值:" + new BigDecimal("10.000000000000").stripTrailingZeros());
System.out.println("原值:" +new BigDecimal("10.000000000000").stripTrailingZeros().toPlainString());
结果:
2.3、用BigDecimal比较大小:compareTo()
即左边比右边数大,返回1,相等返回0,比右边小返回-1。
BigDecimal a = new BigDecimal("1.5");
BigDecimal b = new BigDecimal("0.5");
BigDecimal c = new BigDecimal("2.5");
BigDecimal d = new BigDecimal("1.5");
// 比较大小
System.out.println(a.compareTo(b));
System.out.println(a.compareTo(c));
System.out.println(a.compareTo(d));
结果:
2.4、BigDecimal格式化
BigDecimal对象可以作为NumberFormat类的format()方法的参数,可以对超出16位有效数字的货币值,百分值,以及一般数值进行格式化控制。
// 货币格式
System.out.println("货币:" + NumberFormat.getCurrencyInstance().format(new BigDecimal("123.56")));
// 百分比格式
NumberFormat percent = NumberFormat.getPercentInstance();
// 百分比小数点最多3位
percent.setMaximumFractionDigits(3);
System.out.println("百分比:" + percent.format(new BigDecimal("0.036")));
结果:
3、BigDecimal使用须知
- BigDecimal的性能比double和float差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用BigDecimal,在需要精确的小数计算时再使用BigDecimal;
- 尽量使用参数类型为String的构造函数。 BigDecimal都是不可变的(immutable)的,在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。