Java常用类之BigDecimal类(浮点数精确计算)

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×10scale

常用方法

构造方法

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-百度百科

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值