解决double的精度问题-BigDecimal

BigDecimal的用法

这里写图片描述
不可变的,任意精度的,有符号十进制数。



BigDecimal valueOf(double val)

说明文档:

        public static BigDecimal valueOf(double val) {
        // Reminder: a zero double returns '0.0', so we cannot fastpath
        // to use the constant ZERO.  This might be important enough to
        // justify a factory approach, a cache, or a few private
        // constants, later.
        return new BigDecimal(Double.toString(val));
    }

所以,
BigDecimal b2 = new BigDecimal(Double.toString(2.283));
BigDecimal b3 = BigDecimal.valueOf(2.283);
两种double转BigDecimal的方法其实是等价的,而且第二更简洁,建议使用第二种。

这里写图片描述

关于类型转换:
BigDecimal类提供了诸如intValue(),floatValue(), doubleValue(), longValue()方法来将BigDecimal对象转换成对应的值。如果要使用构造器的话也建议使用String来初始化,因为使用其他类型的初始化的结果是不可预知的。比如BigDecimal(0.1)其实表示的值是和0.1很接近的一个浮点数,但是使用BigDecimal(“0.1”)就是真的0.1。



setScale函数

  • setScale(1)表示保留以为小数,默认用四舍五入方式
  • setScale(1,BigDecimal.ROUND_DOWN)直接删除多余的小数位,如2.35会变成2.3
  • setScale(1,BigDecimal.ROUND_UP)进位处理,2.35变成2.4
  • setScale(1,BigDecimal.ROUND_HALF_UP)四舍五入,2.35变成2.4
  • setScaler(1,BigDecimal.ROUND_HALF_DOWN)五舍六入,2.35变成2.3,2.36变成2.40;如果是5则向下舍。


加法

 public static double sum(double d1,double d2){ 
        BigDecimal bd1 = BigDecimal.valueOf(d1); 
        BigDecimal bd2 = BigDecimal.valueOf(d2);
        return bd1.add(bd2).doubleValue(); 
    } 


减法

 public double sub(double d1,double d2){ 
        BigDecimal bd1 = BigDecimal.valueOf(d1); 
        BigDecimal bd2 = BigDecimal.valueOf(d2);
        return bd1.subtract(bd2).doubleValue(); 
    } 


乘法

 public double mul(double d1,double d2){ 
        BigDecimal bd1 = BigDecimal.valueOf(d1); 
        BigDecimal bd2 = BigDecimal.valueOf(d2); 
        return bd1.multiply(bd2).doubleValue(); 
    } 


除法

除法要注意,因为BigDecimal 计算时由于除法运算,得到循环结果,造成异常!

BigDecimal total = new BigDecimal(200).setScale(3,BigDecimal.ROUND_HALF_UP);

表示这个total的初始值为200.000

BigDecimal total2 = new BigDecimal(10).setScale(3, BigDecimal.ROUND_HALF_UP);

表示这个total2的初始值为10.000

当这个2数相除的时候不能简单的用total.divide(total2); 如果这样会报错:

Non-terminating decimal expansion; no exact representable decimal result

正确的方法:

total.divide(total2,3,BigDecimal.ROUND_HALF_UP);

这样才不会报错,你必须为它指定保留小数位,所以除法的常用模式为:

/** 
     * double 除法 
     * @param d1 
     * @param d2 
     * @param scale 四舍五入 小数点位数 
     * @return 
     */ 
    public double div(double d1,double d2,int scale){ 
        //  当然在此之前,你要判断分母是否为0,   
        //  为0你可以根据实际需求做相应的处理 

        BigDecimal bd1 = BigDecimal.valueOf(d1); 
        BigDecimal bd2 = BigDecimal.valueOf(d2); 
        return bd1.divide 
               (bd2,scale,BigDecimal.ROUND_HALF_UP).doubleValue(); 
    } 


加减乘除运算后的标度问题

除了逻辑的准确结果外,每种算术运算都有一个表示结果的首选标度。下表列出了每个运算的首选标度。
运算 结果的首选标度

  • Add:max(addend.scale(), augend.scale())
  • Subtract:max(minuend.scale(), subtrahend.scale())
  • Multiply:multiplier.scale() + multiplicand.scale()
  • Divide:dividend.scale() - divisor.scale()

这里写图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值