java BigDecimal介绍

来源:互联网 发布:淘宝店铺怎么加入天猫 编辑:程序博客网 时间:2024/05/18 03:36

1.引言

        借用《Effactive Java》这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算。他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的。然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合。但是,商业计算往往要求结果精确,这时候BigDecimal就派上大用场啦。

 

2.BigDecimal简介

        BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成。如果为零或正数,则标度是小数点后的位数。如果为负数,则将该数的非标度值乘以 10 的负scale 次幂。因此,BigDecimal表示的数值是(unscaledValue × 10-scale)

 

3.测试代码

3.1构造函数(主要测试参数类型为double和String的两个常用构造函数)

       BigDecimal aDouble =new BigDecimal(1.22);

        System.out.println("construct with a double value: " + aDouble);

        BigDecimal aString = new BigDecimal("1.22");

         System.out.println("construct with a String value: " + aString);

        你认为输出结果会是什么呢?如果你没有认为第一个会输出1.22,那么恭喜你答对了,输出结果如下:

         construct with a doublevalue:1.2199999999999999733546474089962430298328399658203125

         construct with a String value: 1.22

        JDK的描述:1、参数类型为double的构造方法的结果有一定的不可预知性。有人可能认为在Java中写入newBigDecimal(0.1)所创建的BigDecimal正好等于 0.1(非标度值 1,其标度为 1),但是它实际上等于0.1000000000000000055511151231257827021181583404541015625。这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1(虽然表面上等于该值)。

        2、另一方面,String 构造方法是完全可预知的:写入 newBigDecimal("0.1") 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言,通常建议优先使用String构造方法

        3、double必须用作BigDecimal的源时,请注意,此构造方法提供了一个准确转换;它不提供与以下操作相同的结果:先使用Double.toString(double)方法,然后使用BigDecimal(String)构造方法,将double转换为String。要获取该结果,请使用static valueOf(double)方法。

3.2 加法操作

        BigDecimal a =new BigDecimal("1.22");

        System.out.println("construct with a String value: " + a);

        BigDecimal b =new BigDecimal("2.22");

        a.add(b);

        System.out.println("aplus b is : " + a);

        我们很容易会认为会输出:

        construct with a Stringvalue: 1.22

        a plus b is :3.44

        但实际上a plus b is : 1.22

4.源码分析

4.1 valueOf(doubleval)方法

    public   static BigDecimal valueOf(double val) {

       // Reminder: a zero double returns '0.0', so we cannotfastpath

       // to use the constant ZERO. This might be important enough to

       // justify a factory approach, a cache, or a few private

       // constants, later.

       returnnew BigDecimal(Double.toString(val));//3.1关于JDK描述的第三点

    }

4.2 add(BigDecimal augend)方法

      public BigDecimal   add(BigDecimal augend) {

          long xs =this.intCompact; //整型数字表示的BigDecimal,aintCompact值为122

          long ys = augend.intCompact;//同上

          BigInteger fst = (this.intCompact !=INFLATED) ?null :this.intVal;//初始化BigInteger的值,intValBigDecimal的一个BigInteger类型的属性

          BigInteger snd =(augend.intCompact !=INFLATED) ?null : augend.intVal;

          int rscale =this.scale;//小数位数

 

          long sdiff = (long)rscale - augend.scale;//小数位数之差

          if (sdiff != 0) {//取小数位数多的为结果的小数位数

              if (sdiff < 0) {

                 int raise =checkScale(-sdiff);

                 rscale =augend.scale;

                 if (xs ==INFLATED ||

                     (xs = longMultiplyPowerTen(xs,raise)) ==INFLATED)

                     fst =bigMultiplyPowerTen(raise);

                }else {

                   int raise =augend.checkScale(sdiff);

                   if (ys ==INFLATED ||(ys =longMultiplyPowerTen(ys,raise)) ==INFLATED)

                       snd = augend.bigMultiplyPowerTen(raise);

               }

          }

          if (xs !=INFLATED && ys !=INFLATED) {

              long sum = xs + ys;

              if ( (((sum ^ xs) &(sum ^ ys))) >= 0L)//判断有无溢出

                 return BigDecimal.valueOf(sum,rscale);//返回使用BigDecimal的静态工厂方法得到的BigDecimal实例

           }

           if (fst ==null)

               fst =BigInteger.valueOf(xs);//BigInteger的静态工厂方法

           if (snd ==null)

               snd =BigInteger.valueOf(ys);

           BigInteger sum =fst.add(snd);

           return (fst.signum == snd.signum) ?new BigDecimal(sum,INFLATED, rscale, 0) :

              new BigDecimal(sum,compactValFor(sum),rscale, 0);//返回通过其他构造方法得到的BigDecimal对象

       }

 

        以上只是对加法源码的分析,减乘除其实最终都返回的是一个新的BigDecimal对象,因为BigIntegerBigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以a.add(b);虽然做了加法操作,但是a并没有保存加操作后的值,正确的用法应该是a=a.add(b);

 

5.总结

        (1)商业计算使用BigDecimal。

        (2)尽量使用参数类型为String的构造函数。

        (3) BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以在做加减乘除运算时千万要保存操作后的值。

        (4)我们往往容易忽略JDK底层的一些实现细节,导致出现错误,需要多加注意。

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 网线被车挂断了怎么办 挂了光纤跑了怎么办 cf天赋点多了怎么办 cf天赋点点错了怎么办 警用记录仪丢了怎么办 被伪基站覆盖了怎么办 加热包的水喝了怎么办 剩米饭放硬了怎么办 肉罐头拉环断了怎么办 5大战区拥兵自重怎么办 买的期房停工了怎么办 怀孕后长了副乳怎么办 耳朵冻的红肿了怎么办 吃螃蟹吃柿子了怎么办 吃了螃蟹和柿子怎么办 螃蟹与柿子同吃怎么办 手被鞭炮炸伤了怎么办 索尼l36h变砖了怎么办 oppor9s手机忘记解锁图案怎么办 索尼z5刷死机了怎么办 魅蓝note3被锁定怎么办 oppo图案锁忘了怎么办 手机图案锁忘w怎么办输 手机图案解锁密码忘了怎么办 忘记htc手机锁屏怎么办 我手机密码忘了怎么办 小米5x忘记密码怎么办 oppo忘记手机解锁图案怎么办 手机解锁图案忘了怎么办 苹果id给锁了怎么办 苹果手机忘了ld怎么办 4s忘记开机密码怎么办 取卵22个肚子胀怎么办 夜神模拟器很卡怎么办 夜神模拟器卡顿怎么办 入职体检有痔疮怎么办 泰迪鼻子干怎么办恢复 泰迪幼犬鼻子干怎么办 狗狗呕吐没精神怎么办 狗狗鼻子干拉稀怎么办 狗狗鼻子干呕吐怎么办