BigDecimal类

104 阅读2分钟

案例引入:试想一下,下面这段代码会输出什么?是0.1吗?还是其它答案?

        double d1 = 1.0;
        double d2 = 0.9;
        System.out.println(d1-d2);

当你去试一下的时候,你就会发现,不是等于0.1,而是等于0.0999999999998.这是为什么呢?

-->原因很简单,Double和Float类型的数在运算时很可能会丢失精度,从而造成运算的错误。

那面对这种情况我们该怎么办呢,我们该怎么实现高精度的浮点数运算呢?这个时候,BigDecimal类就发挥了它的作用。BigDecimal类就提供了高精度的浮点数的计算方法(加减乘除)。 下面我们就来看一下BigDecimal的这些运算方法吧

        BigDecimal b1 = new BigDecimal("1.0");//()内一定要使用字符串!!!
        BigDecimal b2 = new BigDecimal("0.9");
        //b1-b2
        BigDecimal r1 = b1.subtract(b2);
        System.out.println(r1);
        //b1+b2
        BigDecimal r2 = b1.add(b2);
        System.out.println(r2);
        //b1*b2
        BigDecimal r3 = b1.multiply(b2);
        System.out.println(r3);
        //b1/b2
        //除法:BigDecimal.divide(BigDecimal bd,int scal,RoundingMode mode)
        // --> scal:保留几位小数  mode:小数部分的取舍条件,一般为BigDecimal.ROUND_HALF_DOWN(四舍五入)
        BigDecimal r4 = b1.divide(b2,2,BigDecimal.ROUND_HALF_DOWN);
        System.out.println(r4);

特别注意:

  1. 需要精确的小数计算时再使用BigDecimal,BigDecimal的性能比double和float差,在处理庞大,复杂的运算时尤为明显。故一般精度的计算没必要使用BigDecimal。
  2. 尽量使用参数类型为String的构造函数。
    • 参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。
    • String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言, 通常建议优先使用String构造方法。
    • 当double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将double转换为String。要获取该结果,请使用static valueOf(double)方法。
  3. BigDecimal都是不可变的(immutable)的, 在进行每一次四则运算时,都会产生一个新的对象 ,所以在做加减乘除运算时要记得要保存操作后的值。