Java BigDecimal详解

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

大家好,又见面了,我是你们的朋友全栈君。

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底层的一些实现细节,导致出现错误,需要多加注意。

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/134227.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Dreamweaver CC2020软件安装包+安装教程

    Dreamweaver CC2020软件安装包+安装教程Dreamweaver介绍Dreamweaver使用所见即所得的接口,亦有HTML编辑的功能,借助经过简化的智能编码引擎,轻松地创建、编码和管理动态网站。访问代码提示,即可快速了解HTML、CSS和其他Web标准。使用视觉辅助功能减少错误并提高网站开发速度。Dreamweaver常用版本我们常用的版本有:DW2020、DW2019、DW2018、DW2017、DW2015、DW2014、DWCS6和DWCS5;常用的版本就是这些了,作为一个经常写代码的人,这个软件是..

    2022年7月14日
    45
  • Portraiture磨皮滤镜的使用,变美就这么简单

    Portraiture磨皮滤镜的使用,变美就这么简单欢迎关注公众号“游戏内圈”,免费更多领取资料:1、下载并解压安装包压缩包,然后将文件夹复制到PS安装的Plug-ins目录下。2、打开PS,进入主界面选择滤镜—永乐汉化—人像磨皮即可打开插件。3

    2022年7月4日
    32
  • 初识.Net审计

    初识.Net审计前言对.net认知比较少,学习一下.net的一些简单审计。遇到.net源码能简单审审。基础概念文件类型ASPX.cs是页面后的代码,aspx负责显示,服务器端的动作就是在as

    2021年12月13日
    44
  • 建立本地数据库「建议收藏」

    建立本地数据库「建议收藏」首先下载安装MySQL,参考:http://www.runoob.com/mysql/mysql-install.html,安装完成后直接打开(安装过程中要求设置用户名和密码,此时输入的密码要记住,后面要使用)然后下载NavicatforMySQL,本人觉得这个比较简单,很适合初学者,安装完成之后点击File(文件)–新建文件,连接名可不填,主机名:localhost,用户名是安装MySQL…

    2022年6月1日
    31
  • 淘宝,天猫,京东,苏宁抢购茅台、手机等脚本(适合兼职,亲测可用)「建议收藏」

    淘宝,天猫,京东,苏宁抢购茅台、手机等脚本(适合兼职,亲测可用)「建议收藏」由来:最近用钱比较多,缺钱,自己也是除了一份死工资就没有别的收入了,而且每个月的工资发了就立马还给了马爸爸,所以一直在想是不是工作之余搞点什么兼职做做,但是一直也是找不到什么门路。碰巧看到uc给我推了一个文章(其实一直有推只是之前没有想法每注意),说天猫,京东,苏宁这些网购平台的茅台90%都是买来卖的,一瓶利润能有一千块。我顿时有了想法,就想着能不能搞个脚本啥的去抢抢,总比自己手动来得好,然后就上网去找脚本,修修补补改改,基于别人的基础上搞了个脚本(目前只有安卓版,后续可能会出苹果的)。然后坚持了几天,

    2022年5月16日
    104
  • intellij idea安装教程_intellij idea2021安装教程

    intellij idea安装教程_intellij idea2021安装教程下载第一步:打开官网:http://www.jetbrains.com/idea/,点击页面中的“DOWNLOAD”第二步:根据自己的需要选择下载的IntelliJIDEA版本。Communit

    2022年8月4日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号