Java BigDecimal类用法详解

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,例a的intCompact值为122
  long ys = augend.intCompact;//同上
  BigInteger fst = (this.intCompact !=INFLATED) ?null :this.intVal;//初始化BigInteger的值,intVal为BigDecimal的一个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对象,因为BigInteger与BigDecimal都是不可变的(immutable)的,在进行每一步运算时,都会产生一个新的对象,所以a.add(b);虽然做了加法操作,但是a并没有保存加操作后的值,正确的用法应该是a=a.add(b);

5.总结

  (1)商业计算使用BigDecimal。

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

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

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

参考:类 BigDecimal

(0)

相关推荐

  • Java中使用BigDecimal进行精确运算

    首先我们先来看如下代码示例: public class Test_1 { public static void main(String[] args) { System.out.println(0.06+0.01); System.out.println(1.0-0.42); System.out.println(4.015*100); System.out.println(303.1/1000); } } 运行结果如下. 0.06999999999999999 0.58000000000000

  • Java BigDecimal类的使用和注意事项

    BigDecimal简介 JDK文档(中文)中的解释如下: 不可变的.任意精度的有符号十进制数.BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成.如果为零或正数,则标度是小数点后的位数.如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂.因此,BigDecimal 表示的数值是 (unscaledValue × 10-scale). 具体解释 1."BigDecimal 对象的值是不可变的".这点在BigDecimal 对象的运

  • Java BigDecimal详解_动力节点Java学院整理

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,例如银行存款数额,这时候BigDecimal就派上大用场啦. 2.BigDecimal简介 BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组

  • Java中BigDecimal类的简单用法

    本文实例讲述了Java中BigDecimal类的简单用法,是Java程序设计中非常实用的技巧,分享给大家供大家参考.具体用法分析如下: 一般来说,一提到Java里面的商业计算,我们都知道不能用float和double,因为他们无法进行精确计算.但是Java的设计者给编程人员提供了一个很有用的类BigDecimal,他可以完善float和double类无法进行精确计算的缺憾.BigDecimal类位于java.maths类包下.首先我们来看下如何构造一个BigDecimal对象.它的构造函数很多,

  • java中BigDecimal的操作方法

    本文实例讲述了java中BigDecimal的操作方法.分享给大家供大家参考.具体分析如下: 由于double,float的精度不够,因此在进行商业计算的时候要使用的BigDecimal.BigDecimal对象创建如下: 复制代码 代码如下: BigDecimal b = new BigDecimal("12.000001"); System.out.println(b); 输出结果为:12.000001: BigDecimal在创建的时候可以传入String和double,但是最好

  • Java使用BigDecimal进行高精度计算的示例代码

    首先看如下代码示例: System.out.println(0.05 + 0.01); System.out.println(0.05 - 0.03); System.out.println(1.025 * 100); System.out.println(305.1 / 1000); 输出结果为: 0.060000000000000005 0.020000000000000004 102.49999999999999 0.30510000000000004 Java语言支持两种基本的浮点类型:

  • Java BigDecimal类用法详解

    一.简介 Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更小的数进行运算和处理.float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal.BigDecimal所创建的是对象,我们不能使用传统的+.-.*./等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法.方法中的参数也必须是BigDe

  • Java BigDecimal类用法详解

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确的快速近似计算而精心设计的.然而,它们没有提供完全精确的结果,所以不应该被用于要求精确结果的场合.但是,商业计算往往要求结果精确,这时候BigDecimal就派上大用场啦. 2.BigDecimal简介 BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成.如果为零或正数

  • Java BigDecimal基础用法详解

    目录 一.BigDecimal概述 二.BigDecimal常用构造函数 2.1.常用构造函数 2.2.使用问题分析 三.BigDecimal常用方法详解 3.1.常用方法 3.2.BigDecimal大小比较 四.BigDecimal格式化 五.BigDecimal常见异常 5.1.除法的时候出现异常 六.BigDecimal总结 6.1.总结 6.2.工具类推荐 一.BigDecimal概述 一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Do

  • Java BigDecimal正确用法详解

    目录 一.背景 二.事故案例 1.问题 2.问题复现 3.源码分析 4.原因分析 三.总结 四.工具类 一.背景 BigDecimal 平时主要用于计算金钱时,其自身提供了很多的构造方法,但是这些构造方法使用不当会造成精度丢失,从而引起事故. 二.事故案例 1.问题 收银台计算商品价格报错,导致订单无法支付 2.问题复现 public static void main(String[] args) { BigDecimal bigDecimal=new BigDecimal(88); Syste

  • Java String类用法详解

    一.简介 零碎知识点 extends Object implements serializable,Comparable< String >,charSequence String类表示字符串,所有字符串文字都是此类的对象 字符串是不变的,值在创建后无法更改 对象一旦声明则不可改变,改变的只是地址,原来的字符串还是存在的,并且产生垃圾 任何一个""都为字符串对象,无赋值则为匿名对象 用"+"拼接字符串尽量避免,一般用append+toString Str

  • java BigDecimal类案例详解

    目录 前言 一.介绍 二.知识点介绍 三.知识点详解 1.概述 2.BigDecimal构造方法 3.源码的描述 4.BigDecimal加减乘除运算 5.总结 6.精炼练习 6.1  题目 6.2 实验步骤 结语 前言 只要认真计划一件事,并且一边坚持一边调整,往往会完成得十分出色.懈怠的情绪谁都会有,不要担心自己比别人走得慢,也不要因暂时的挫折心灰意冷,只要不断调整心态,不停下脚步,最终能抵达终点. 一.介绍 float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制

  • Java基础类库之StringBuffer类用法详解

    StringBuffer类 String类是在所有开发项目开发之中一定会使用的一个功能类,并且这个类拥有如下功能 每个字符串的常量都属于一个String类匿名对象,并且不能修改: String类有两个常量池:静态常量池.运行常量池: String类对象实例化建议直接使用赋值的形式完成,这样可以直接将对象保存在对象池中方便下次重用: 虽然String类很好用,但是我们发现它也有弊端,就是内容不允许频繁修改,所以为了解决问题,我们提供了StringBuffer类 StringBuffer 并不像St

  • java Beanutils.copyProperties( )用法详解

    这是一篇开发自辩甩锅稿~~~~ 昨天测试小姐姐将我的一个bug单重开了,emmmm....内心OS:就调整下对象某个属性类型这么简单的操作,我怎么可能会出错呢,一定不是我的锅!!but再怎么抗拒,bug还是要改的,毕竟晚上就要发版本了~~ 老老实实将我前天改的部分跟了一遍,恩,完美,没有任何的缺失~~but本应success的测试数据,接口返还的结果确实是false来着,那还是老老实实debug吧. 一步步跟下来,恩,多么顺畅,就说一定不是我的锅~~诶?不对不对,这里的ID值,为啥是null?传

  • Java RandomAccessFile的用法详解

    RandomAccessFile RandomAccessFile是用来访问那些保存数据记录的文件的,你就可以用seek( )方法来访问记录,并进行读写了.这些记录的大小不必相同:但是其大小和位置必须是可知的.但是该类仅限于操作文件. RandomAccessFile不属于InputStream和OutputStream类系的.实际上,除了实现DataInput和 DataOutput接口之外(DataInputStream和DataOutputStream也实现了这两个接口),它和这两个类系毫

  • Java File类的详解及简单实例

    Java File类的详解及简单实例 1. File():构造函数,一般是依据文件所在的指定位置来创建文件对象.  CanWrite():返回文件是否可写. CanRead():返回文件是否可读. CompareTo(File pathname):检查指定文件路径间的顺序. Delet():从文件系统内删除该文件. DeleteOnExit():程序顺利结束时从系统中删除文件. Equals(Object obj):检查特定对象的路径名是否相等. Exists():判断文件夹是否存在. GetA

随机推荐