BigDecimal类
在Java算术运算过程中,是否会遇到浮点数计算出现结果错误的情况,在遇到这种情况是否感到困惑和无助?本文带你解决此类问题。
先看遇到的问题:
//浮点数计算遇到的问题
public class Main{
public static void main(String[] args){
double a = 1.0;
double b = 0.9;
double c=(1.4-0.5)/0.9;
System.out.println(a-b);
System.out.println(c);
}
}
结果:
为什么会出现上面的情况呢?
简单点说就是,计算机在存储浮点数字时以二进制方法存储,在进行转化为二进制时存储的小数部分出现部分数据丢失,而成为近似值,从而导致在计算时出现错误。
详细可参考:Java中浮点数运算不准确的原因
为解决此类问题而引入BigDecimal类
BigDecimal
不可变的、任意精度的有符号十进制数。BigDecimal
由任意精度的整数非标度值(unscaledValue) 和 32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂。因此,BigDecimal
表示的数值是
u
n
s
c
a
l
e
d
V
a
l
u
e
×
1
0
−
s
c
a
l
e
\ unscaledValue × 10^{-scale}
unscaledValue×10−scale。
常用方法
构造方法
BigDecimal类的构造方法挺多的,但这里只介绍一种public BigDecimal(String val)
,将字符串表示形式转换为BigDecimal。注意这里一定是字符串String
,如果在参数为小数时,使用double类型时,会出现一定的问题(注意看实例)。
普通方法
BigDecimal创建的是对象,所以在运算的时候不能再使用+-*/
等算术运算符进行直接运算,而是使用相应的方法。
方法 | 描述 |
---|---|
public BigDecimal add(BigDecimal augend) | 加法 |
public BigDecimal subtract(BigDecimal subtrahend) | 减法 |
public BigDecimal multiply(BigDecimal multiplicand) | 乘法 |
public BigDecimal divide(BigDecimal divisor,int scale, int roundingMode) | 除法。divisor - 此 BigDecimal 要除以的值。scale - 要返回的 BigDecimal 商的标度。roundingMode - 要应用的舍入模式。 |
这里需要注意的是,在进行除法运算时,如果结果为除不尽的数,未标明保留几位小数(或使用舍入的方式),会抛出的异常:
ArithmeticException - 如果 divisor 为零,则roundingMode==ROUND_UNNECESSARY 和指定的标度不足以准确地表示相除的结果。
IllegalArgumentException - 如果 roundingMode 不表示一个有效的舍入模式。
常用的舍入方法:
常量 | 描述 |
---|---|
ROUND_HALF_UP | 四舍五入 |
ROUND_UP | 直接进位 |
ROUND_DOWN | 直接舍弃 |
ROUND_HALF_DOWN | 舍弃部分>0.5进位,否则舍弃 |
实例
import java.math.BigDecimal;
import static java.math.BigDecimal.ROUND_HALF_UP;
public class Main2 {
public static void main(String[] args) {
BigDecimal a=new BigDecimal("1.0");
BigDecimal b=new BigDecimal("0.9");
System.out.println("加法:"+a.add(b));
System.out.println("减法:"+a.subtract(b));
System.out.println("乘法:"+a.multiply(b));
System.out.println("除法:"+a.divide(b,4,ROUND_HALF_UP));
System.out.println("使用double");
double a1=1.0;
double b1=0.9;
BigDecimal c=new BigDecimal(a1);
BigDecimal d = new BigDecimal(b1);
System.out.println("加法:"+c.add(d));
System.out.println("减法:"+c.subtract(d));
System.out.println("乘法:"+c.multiply(d));
System.out.println("除法:"+c.divide(d,4,ROUND_HALF_UP));
}
}
结果
注意看结果,出现这种情况的原因:
参数类型为double的构造方法的结果有一定的不可预知性。你可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
总结
对于不需要任何准确计算精度的数字可以直接使用float或double,但是如果需要精确计算结果,则必须使用BigDecimal类,而且使用BigDecimal类也可进行大数的操作。
如有错误,欢迎指正!!!
参考内容:BigDecimal-百度百科