BigDecimal

在日常开发中我们经常会碰到小数计算,而小数直接计算的话会出现一些小小的错误,如下

System.out.println(1.01 + 2.02);  
复制代码

你说能输出什么?3.03?实际上输出的是3.0300000000000002。这是因为不论是float 还是double都是浮点数,而计算机是二进制的,浮点数会失去一定的精确度。有没有不失精度的办法呢?这里就要用到BigDecimal了。

java.math.BigDecimal
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

创建BigDecimal对象主要有两种。

BigDecimal b1 = new BigDecimal("1.34");//1.34  
BigDecimal b2 = BigDecimal.valueOf(1.34);//1.34  
复制代码

其中b1也可以写成new BigDecimal(Double.toString(1.34)),可以直接new BigDecimal(1.34)吗,也是可以的,只是会出现上述的精度问题。

BigDecimal one1 = new BigDecimal(1.34);//1.3400000000000000799360577730112709105014801025390625  
BigDecimal two1 = new BigDecimal("1.34");//1.34  
复制代码

除了这两种外,特殊的像0、1、10可以这样写。

BigDecimal zero = BigDecimal.ZERO;  
BigDecimal one = BigDecimal.ONE;  
BigDecimal ten = BigDecimal.TEN;  
复制代码

比较一下BigDecimal.ZERO、new BigDecimal("0")、BigDecimal.valueOf(0)这三者,equals都是true,==的话new BigDecimal("0")就不用看了都new了,而BigDecimal.ZERO == BigDecimal.ZERO为true。查看一下源代码可得。

public static BigDecimal valueOf(long val) {  
        if (val >= 0 && val < zeroThroughTen.length)  
            return zeroThroughTen[(int)val];  
        else if (val != INFLATED)  
            return new BigDecimal(null, val, 0, 0);  
        return new BigDecimal(INFLATED_BIGINT, val, 0, 0);  
    }  
// Cache of common small BigDecimal values.  
    private static final BigDecimal zeroThroughTen[] = {  
        new BigDecimal(BigInteger.ZERO,       0,  0, 1),  
        new BigDecimal(BigInteger.ONE,        1,  0, 1),  
        new BigDecimal(BigInteger.valueOf(2), 2,  0, 1),  
        new BigDecimal(BigInteger.valueOf(3), 3,  0, 1),  
        new BigDecimal(BigInteger.valueOf(4), 4,  0, 1),  
        new BigDecimal(BigInteger.valueOf(5), 5,  0, 1),  
        new BigDecimal(BigInteger.valueOf(6), 6,  0, 1),  
        new BigDecimal(BigInteger.valueOf(7), 7,  0, 1),  
        new BigDecimal(BigInteger.valueOf(8), 8,  0, 1),  
        new BigDecimal(BigInteger.valueOf(9), 9,  0, 1),  
        new BigDecimal(BigInteger.TEN,        10, 0, 2),  
    };  
复制代码

发现10以内的对象都是同一个,所以为true。

BigDecimal的加减乘除运算。

public BigDecimal add(BigDecimal value);//加法  
public BigDecimal subtract(BigDecimal value);//减法   
public BigDecimal multiply(BigDecimal value);//乘法  
public BigDecimal divide(BigDecimal value);//除法  
复制代码

也可以照下面加法例子写成一个util,另外三个都差不多就不展开了。

public static double add(double value1,double value2){  
    BigDecimal b1 = new BigDecimal(Double.toString(value1));  
    BigDecimal b2 = new BigDecimal(Double.toString(value2));  
    return b1.add(b2).doubleValue();  
}  
复制代码

BigDecimal的运算都没有对原值进行操作,而是返回一个新的BigDecimal对象,这点可能有些小伙伴会搞错要注意一下。

BigDecimal b1 =new BigDecimal("1.34");  
System.out.println("b1: " + b1);  
BigDecimal b2 =new BigDecimal("2.34");  
b1.add(b2);  
System.out.println("b1: " + b1);//b1并没有变  
复制代码

BigDecimal的比较用的是BigDecimal的compareTo方法,将此 BigDecimal 与指定的 BigDecimal 比较。 根据此方法,值相等但具有不同标度的两个BigDecimal对象(如,2.0 和 2.00)被认为是相等的。

当此 BigDecimal 在数字上小于、等于或大于被比较对象时,返回 -1、0 或 1。

BigDecimal one = BigDecimal.valueOf(1);  
BigDecimal two = BigDecimal.valueOf(2);  
BigDecimal three = one.add(two);  
int i1 = one.compareTo(two);//-1  
int i2 = two.compareTo(two);//0  
int i3 = three.compareTo(two);//1  
复制代码

其他补充:

  • divide的参数
java.math.BigDecimal
public BigDecimal divide(@NotNull BigDecimal divisor,//除数
                         int scale,//小数点后保留几位
                         int roundingMode
                         //舍入方式
                        CEILING   
                                  向正无限大方向舍入的舍入模式。 
                        DOWN   
                                  向零方向舍入的舍入模式。 
                        FLOOR   
                                  向负无限大方向舍入的舍入模式。 
                        HALF_DOWN   
                                  向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向下舍入。 
                        HALF_EVEN   
                                  向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。 
                        HALF_UP   
                                  向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。 
                        UNNECESSARY   
                                  用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。 
                        UP   
                                  远离零方向舍入的舍入模式。 )
复制代码
  • BigDecimal.setScale
setScale(int, int) 
setScale(int, RoundingMode)
注:第二个参数等价对应
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值